Skip to content

Commit

Permalink
code: improve error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
noomorph committed May 22, 2020
1 parent bb636e3 commit 05936f5
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 35 deletions.
8 changes: 7 additions & 1 deletion detox/local-cli/__snapshots__/build.test.js.snap
@@ -1,3 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`build fails with an error if a build script has not been found 1`] = `"Could not find build script for \\"testConfig\\" in Detox config at: /etc/detox/config"`;
exports[`build fails with an error if a build script has not been found 1`] = `
"Could not find a build script inside \\"testConfig\\" configuration.
HINT: Check contents of your Detox config at: /etc/detox/config
{}"
`;
7 changes: 6 additions & 1 deletion detox/local-cli/build.js
Expand Up @@ -2,6 +2,7 @@ const _ = require('lodash');
const cp = require('child_process');
const log = require('../src/utils/logger').child({ __filename });
const {composeDetoxConfig} = require('../src/configuration');
const DetoxConfigError = require('../src/errors/DetoxConfigError');

module.exports.command = 'build';
module.exports.desc = "Convenience method. Run the command defined in 'build' property of the specified configuration.";
Expand All @@ -28,6 +29,10 @@ module.exports.handler = async function build(argv) {
log.info(buildScript);
cp.execSync(buildScript, { stdio: 'inherit' });
} else {
throw new Error(`Could not find build script for "${meta.configuration}" in Detox config at: ${meta.location}`);
throw new DetoxConfigError({
message: `Could not find a build script inside "${meta.configuration}" configuration.`,
hint: meta.location && `Check contents of your Detox config at: ${meta.location}`,
debugInfo: deviceConfig,
});
}
};
19 changes: 5 additions & 14 deletions detox/src/configuration/composeDeviceConfig.js
@@ -1,23 +1,22 @@
const _ = require('lodash');
const util = require('util');
const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
const DetoxConfigError = require('../errors/DetoxConfigError');

function composeDeviceConfig({ configurationName, rawDeviceConfig, cliConfig }) {
if (!rawDeviceConfig.type) {
throw new DetoxRuntimeError({
throw new DetoxConfigError({
message: `Missing "type" inside detox.configurations["${configurationName}"]`,
hint: `Usually, 'type' property should hold the device type to test on (e.g. "ios.simulator" or "android.emulator").\nCheck again:`,
debugInfo: inspectObj(rawDeviceConfig),
debugInfo: rawDeviceConfig,
});
}

const device = cliConfig.deviceName || rawDeviceConfig.device || rawDeviceConfig.name;

if (_.isEmpty(device)) {
throw new DetoxRuntimeError({
throw new DetoxConfigError({
message: `'device' property is empty in detox.configurations["${configurationName}"]`,
hint: `It should hold the device query to run on (e.g. { "type": "iPhone 11 Pro" }, { "avdName": "Nexus_5X_API_29" }).\nCheck again:`,
debugInfo: inspectObj(rawDeviceConfig),
debugInfo: rawDeviceConfig,
});
}

Expand All @@ -27,13 +26,5 @@ function composeDeviceConfig({ configurationName, rawDeviceConfig, cliConfig })
return rawDeviceConfig;
}

function inspectObj(obj) {
return util.inspect(obj, {
colors: false,
compact: false,
depth: 0,
showHidden: false,
});
}

module.exports = composeDeviceConfig;
7 changes: 4 additions & 3 deletions detox/src/configuration/index.js
@@ -1,6 +1,5 @@
const _ = require('lodash');
const DetoxConfigError = require('../errors/DetoxConfigError');
const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
const collectCliConfig = require('./collectCliConfig');
const loadExternalConfig = require('./loadExternalConfig');
const composeArtifactsConfig = require('./composeArtifactsConfig');
Expand All @@ -26,7 +25,7 @@ async function composeDetoxConfig({
const detoxConfig = _.merge({}, externalConfig, override);

if (_.isEmpty(detoxConfig)) {
throw new DetoxRuntimeError({
throw new DetoxConfigError({
message: 'Cannot start Detox without a configuration',
hint: 'Make sure your package.json has "detox" section, or there\'s .detoxrc file in the working directory',
});
Expand Down Expand Up @@ -85,6 +84,8 @@ module.exports = {
composeDetoxConfig,

throwOnEmptyBinaryPath() {
throw new DetoxConfigError(`'binaryPath' property is missing, should hold the app binary path`);
throw new DetoxConfigError({
message: `'binaryPath' property is missing, should hold the app binary path`,
});
},
};
19 changes: 7 additions & 12 deletions detox/src/configuration/selectConfiguration.js
@@ -1,7 +1,6 @@
const _ = require('lodash');
const util = require('util');

const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
const DetoxConfigError = require('../errors/DetoxConfigError');

function hintConfigurations(configurations) {
return _.keys(configurations).map(c => `* ${c}`).join('\n')
Expand All @@ -11,14 +10,10 @@ function selectConfiguration({ detoxConfig, cliConfig }) {
const { configurations } = detoxConfig;

if (_.isEmpty(configurations)) {
throw new DetoxRuntimeError({
throw new DetoxConfigError({
message: `There are no device configurations in the given Detox config:`,
debugInfo: util.inspect(detoxConfig, {
colors: false,
compact: false,
depth: 1,
showHidden: false,
}),
debugInfo: detoxConfig,
inspectOptions: { depth: 1 },
});
}

Expand All @@ -28,14 +23,14 @@ function selectConfiguration({ detoxConfig, cliConfig }) {
}

if (!configurationName) {
throw new DetoxRuntimeError({
throw new DetoxConfigError({
message: 'Cannot determine which configuration to use.',
hint: 'Use --configuration to choose one of the following:\n' + hintConfigurations(configurations),
});
}

if (!configurations.hasOwnProperty(configurationName)) {
throw new DetoxRuntimeError({
throw new DetoxConfigError({
message: `Failed to find a configuration named "${configurationName}" in Detox config`,
hint: 'Below are the configurations Detox has been able to find:\n' + hintConfigurations(configurations),
});
Expand All @@ -44,4 +39,4 @@ function selectConfiguration({ detoxConfig, cliConfig }) {
return configurationName;
}

module.exports = selectConfiguration;
module.exports = selectConfiguration;
9 changes: 7 additions & 2 deletions detox/src/errors/DetoxConfigError.js
@@ -1,5 +1,10 @@
const CustomError = require('./CustomError');
const DetoxRuntimeError = require('./DetoxRuntimeError');

class DetoxConfigError extends CustomError {}
class DetoxConfigError extends DetoxRuntimeError {
constructor(opts) {
super(opts);
this.name = 'DetoxConfigError';
}
}

module.exports = DetoxConfigError;
21 changes: 19 additions & 2 deletions detox/src/errors/DetoxRuntimeError.js
@@ -1,16 +1,33 @@
const _ = require('lodash');
const util = require('util');

class DetoxRuntimeError extends Error {
constructor({ message = '', hint = '', debugInfo = '' } = {}) {
constructor({
message = '',
hint = '',
debugInfo = '',
inspectOptions,
} = {}) {
const formattedMessage = _.compact([
message,
hint && `HINT: ${hint}`,
debugInfo
_.isObject(debugInfo) ? inspectObj(debugInfo, inspectOptions) : debugInfo,
]).join('\n\n');

super(formattedMessage);
this.name = 'DetoxRuntimeError';
}
}

function inspectObj(obj, options) {
return util.inspect(obj, {
colors: false,
compact: false,
depth: 0,
showHidden: false,

...options,
});
}

module.exports = DetoxRuntimeError;
8 changes: 8 additions & 0 deletions detox/src/errors/DetoxRuntimeError.test.js
Expand Up @@ -30,6 +30,14 @@ describe(DetoxRuntimeError, () => {
suffix: undefined,
}, null, 2),
}),
'message with debug info object': new DetoxRuntimeError({
message: 'no filename was given to constructSafeFilename()',
debugInfo: {
prefix: 'detox - ',
trimmable: undefined,
suffix: undefined,
},
}),
'message with hint and debug info': new DetoxRuntimeError({
message: `Invalid test summary was passed to detox.beforeEach(testSummary)` +
'\nExpected to get an object of type: { title: string; fullName: string; status: "running" | "passed" | "failed"; }',
Expand Down

0 comments on commit 05936f5

Please sign in to comment.