mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-24 07:17:18 +00:00
refactor(errors): createError and createUserError accept an object (#1322)
Currently, both of these functions accept two arguments: the error title, and the error description. This function signature makes is hard to keep adding options to these error creation functions, like an error code, so this commit refactors them to take a single argument: an options object containing `title` and `description` properties. Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
parent
b93fd86092
commit
fe91be11e8
@ -152,7 +152,9 @@ return permissions.isElevated().then((elevated) => {
|
||||
name: packageJSON.displayName
|
||||
}).then((stdout, stderr) => {
|
||||
if (!_.isEmpty(stderr)) {
|
||||
throw errors.createError(stderr);
|
||||
throw errors.createError({
|
||||
title: stderr
|
||||
});
|
||||
}
|
||||
|
||||
// We're hardcoding internal error messages declared by `sudo-prompt`.
|
||||
@ -167,10 +169,10 @@ return permissions.isElevated().then((elevated) => {
|
||||
}).catch({
|
||||
message: 'No polkit authentication agent found.'
|
||||
}, () => {
|
||||
throw errors.createUserError(
|
||||
'No polkit authentication agent found',
|
||||
'Please install a polkit authentication agent for your desktop environment of choice to continue'
|
||||
);
|
||||
throw errors.createUserError({
|
||||
title: 'No polkit authentication agent found',
|
||||
description: 'Please install a polkit authentication agent for your desktop environment of choice to continue'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,10 @@ const imagePath = options._[ARGV_IMAGE_PATH_INDEX];
|
||||
|
||||
permissions.isElevated().then((elevated) => {
|
||||
if (!elevated) {
|
||||
throw errors.createUserError(
|
||||
messages.error.elevationRequired(),
|
||||
'This tool requires special permissions to write to external drives'
|
||||
);
|
||||
throw errors.createUserError({
|
||||
title: messages.error.elevationRequired(),
|
||||
description: 'This tool requires special permissions to write to external drives'
|
||||
});
|
||||
}
|
||||
|
||||
return form.run([
|
||||
@ -66,7 +66,10 @@ permissions.isElevated().then((elevated) => {
|
||||
});
|
||||
}).then((answers) => {
|
||||
if (!answers.yes) {
|
||||
throw errors.createUserError('Aborted', 'We can\'t proceed without confirmation');
|
||||
throw errors.createUserError({
|
||||
title: 'Aborted',
|
||||
description: 'We can\'t proceed without confirmation'
|
||||
});
|
||||
}
|
||||
|
||||
const progressBars = {
|
||||
@ -80,10 +83,10 @@ permissions.isElevated().then((elevated) => {
|
||||
});
|
||||
|
||||
if (!selectedDrive) {
|
||||
throw errors.createUserError(
|
||||
'The selected drive was not found',
|
||||
`We can't find ${answers.drive} in your system. Did you unplug the drive?`
|
||||
);
|
||||
throw errors.createUserError({
|
||||
title: 'The selected drive was not found',
|
||||
description: `We can't find ${answers.drive} in your system. Did you unplug the drive?`
|
||||
});
|
||||
}
|
||||
|
||||
return writer.writeImage(imagePath, selectedDrive, {
|
||||
|
@ -93,7 +93,9 @@ module.exports = yargs
|
||||
|
||||
// Error reporting
|
||||
.fail((message, error) => {
|
||||
const errorObject = error || errors.createUserError(message);
|
||||
const errorObject = error || errors.createUserError({
|
||||
title: message
|
||||
});
|
||||
|
||||
if (robot.isEnabled(process.env)) {
|
||||
robot.printError(errorObject);
|
||||
@ -112,7 +114,10 @@ module.exports = yargs
|
||||
try {
|
||||
fs.accessSync(imagePath);
|
||||
} catch (error) {
|
||||
throw errors.createUserError('Unable to access file', `The image ${imagePath} is not accessible`);
|
||||
throw errors.createUserError({
|
||||
title: 'Unable to access file',
|
||||
description: `The image ${imagePath} is not accessible`
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -120,10 +125,10 @@ module.exports = yargs
|
||||
|
||||
.check((argv) => {
|
||||
if (robot.isEnabled(process.env) && !argv.drive) {
|
||||
throw errors.createUserError(
|
||||
'Missing drive',
|
||||
'You need to explicitly pass a drive when enabling robot mode'
|
||||
);
|
||||
throw errors.createUserError({
|
||||
title: 'Missing drive',
|
||||
description: 'You need to explicitly pass a drive when enabling robot mode'
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -70,10 +70,10 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
|
||||
}).then((driveFileDescriptor) => {
|
||||
return imageStream.getFromFilePath(imagePath).then((image) => {
|
||||
if (!constraints.isDriveLargeEnough(drive, image)) {
|
||||
throw errors.createUserError(
|
||||
'The image you selected is too big for this drive',
|
||||
'Please connect a bigger drive and try again'
|
||||
);
|
||||
throw errors.createUserError({
|
||||
title: 'The image you selected is too big for this drive',
|
||||
description: 'Please connect a bigger drive and try again'
|
||||
});
|
||||
}
|
||||
|
||||
return imageWrite.write({
|
||||
|
@ -119,11 +119,15 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
|
||||
case ACTIONS.SET_AVAILABLE_DRIVES: {
|
||||
if (!action.data) {
|
||||
throw errors.createError('Missing drives');
|
||||
throw errors.createError({
|
||||
title: 'Missing drives'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isArray(action.data) || !_.every(action.data, _.isPlainObject)) {
|
||||
throw errors.createError(`Invalid drives: ${action.data}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid drives: ${action.data}`
|
||||
});
|
||||
}
|
||||
|
||||
const newState = state.set('availableDrives', Immutable.fromJS(action.data));
|
||||
@ -170,35 +174,51 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
|
||||
case ACTIONS.SET_FLASH_STATE: {
|
||||
if (!state.get('isFlashing')) {
|
||||
throw errors.createError('Can\'t set the flashing state when not flashing');
|
||||
throw errors.createError({
|
||||
title: 'Can\'t set the flashing state when not flashing'
|
||||
});
|
||||
}
|
||||
|
||||
if (!action.data.type) {
|
||||
throw errors.createError('Missing state type');
|
||||
throw errors.createError({
|
||||
title: 'Missing state type'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isString(action.data.type)) {
|
||||
throw errors.createError(`Invalid state type: ${action.data.type}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid state type: ${action.data.type}`
|
||||
});
|
||||
}
|
||||
|
||||
if (_.isNil(action.data.percentage)) {
|
||||
throw errors.createError('Missing state percentage');
|
||||
throw errors.createError({
|
||||
title: 'Missing state percentage'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isNumber(action.data.percentage)) {
|
||||
throw errors.createError(`Invalid state percentage: ${action.data.percentage}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid state percentage: ${action.data.percentage}`
|
||||
});
|
||||
}
|
||||
|
||||
if (_.isNil(action.data.eta)) {
|
||||
throw errors.createError('Missing state eta');
|
||||
throw errors.createError({
|
||||
title: 'Missing state eta'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isNumber(action.data.eta)) {
|
||||
throw errors.createError(`Invalid state eta: ${action.data.eta}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid state eta: ${action.data.eta}`
|
||||
});
|
||||
}
|
||||
|
||||
if (_.isNil(action.data.speed)) {
|
||||
throw errors.createError('Missing state speed');
|
||||
throw errors.createError({
|
||||
title: 'Missing state speed'
|
||||
});
|
||||
}
|
||||
|
||||
return state.set('flashState', Immutable.fromJS(action.data));
|
||||
@ -218,7 +238,9 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
|
||||
case ACTIONS.UNSET_FLASHING_FLAG: {
|
||||
if (!action.data) {
|
||||
throw errors.createError('Missing results');
|
||||
throw errors.createError({
|
||||
title: 'Missing results'
|
||||
});
|
||||
}
|
||||
|
||||
_.defaults(action.data, {
|
||||
@ -226,19 +248,27 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
});
|
||||
|
||||
if (!_.isBoolean(action.data.cancelled)) {
|
||||
throw errors.createError(`Invalid results cancelled: ${action.data.cancelled}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid results cancelled: ${action.data.cancelled}`
|
||||
});
|
||||
}
|
||||
|
||||
if (action.data.cancelled && action.data.sourceChecksum) {
|
||||
throw errors.createError('The sourceChecksum value can\'t exist if the flashing was cancelled');
|
||||
throw errors.createError({
|
||||
title: 'The sourceChecksum value can\'t exist if the flashing was cancelled'
|
||||
});
|
||||
}
|
||||
|
||||
if (action.data.sourceChecksum && !_.isString(action.data.sourceChecksum)) {
|
||||
throw errors.createError(`Invalid results sourceChecksum: ${action.data.sourceChecksum}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid results sourceChecksum: ${action.data.sourceChecksum}`
|
||||
});
|
||||
}
|
||||
|
||||
if (action.data.errorCode && !_.isString(action.data.errorCode) && !_.isNumber(action.data.errorCode)) {
|
||||
throw errors.createError(`Invalid results errorCode: ${action.data.errorCode}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid results errorCode: ${action.data.errorCode}`
|
||||
});
|
||||
}
|
||||
|
||||
return state
|
||||
@ -249,26 +279,36 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
|
||||
case ACTIONS.SELECT_DRIVE: {
|
||||
if (!action.data) {
|
||||
throw errors.createError('Missing drive');
|
||||
throw errors.createError({
|
||||
title: 'Missing drive'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isString(action.data)) {
|
||||
throw errors.createError(`Invalid drive: ${action.data}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid drive: ${action.data}`
|
||||
});
|
||||
}
|
||||
|
||||
const selectedDrive = findDrive(state, action.data);
|
||||
|
||||
if (!selectedDrive) {
|
||||
throw errors.createError(`The drive is not available: ${action.data}`);
|
||||
throw errors.createError({
|
||||
title: `The drive is not available: ${action.data}`
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedDrive.get('protected')) {
|
||||
throw errors.createError('The drive is write-protected');
|
||||
throw errors.createError({
|
||||
title: 'The drive is write-protected'
|
||||
});
|
||||
}
|
||||
|
||||
const image = state.getIn([ 'selection', 'image' ]);
|
||||
if (image && !constraints.isDriveLargeEnough(selectedDrive.toJS(), image.toJS())) {
|
||||
throw errors.createError('The drive is not large enough');
|
||||
throw errors.createError({
|
||||
title: 'The drive is not large enough'
|
||||
});
|
||||
}
|
||||
|
||||
return state.setIn([ 'selection', 'drive' ], Immutable.fromJS(action.data));
|
||||
@ -276,45 +316,65 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
|
||||
case ACTIONS.SELECT_IMAGE: {
|
||||
if (!action.data.path) {
|
||||
throw errors.createError('Missing image path');
|
||||
throw errors.createError({
|
||||
title: 'Missing image path'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isString(action.data.path)) {
|
||||
throw errors.createError(`Invalid image path: ${action.data.path}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid image path: ${action.data.path}`
|
||||
});
|
||||
}
|
||||
|
||||
if (!action.data.size) {
|
||||
throw errors.createError('Missing image size');
|
||||
throw errors.createError({
|
||||
title: 'Missing image size'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isPlainObject(action.data.size)) {
|
||||
throw errors.createError(`Invalid image size: ${action.data.size}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid image size: ${action.data.size}`
|
||||
});
|
||||
}
|
||||
|
||||
const MINIMUM_IMAGE_SIZE = 0;
|
||||
|
||||
if (!_.isInteger(action.data.size.original) || action.data.size.original < MINIMUM_IMAGE_SIZE) {
|
||||
throw errors.createError(`Invalid original image size: ${action.data.size.original}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid original image size: ${action.data.size.original}`
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isInteger(action.data.size.final.value) || action.data.size.final.value < MINIMUM_IMAGE_SIZE) {
|
||||
throw errors.createError(`Invalid final image size: ${action.data.size.final.value}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid final image size: ${action.data.size.final.value}`
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isBoolean(action.data.size.final.estimation)) {
|
||||
throw errors.createError(`Invalid final image size estimation flag: ${action.data.size.final.estimation}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid final image size estimation flag: ${action.data.size.final.estimation}`
|
||||
});
|
||||
}
|
||||
|
||||
if (action.data.url && !_.isString(action.data.url)) {
|
||||
throw errors.createError(`Invalid image url: ${action.data.url}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid image url: ${action.data.url}`
|
||||
});
|
||||
}
|
||||
|
||||
if (action.data.name && !_.isString(action.data.name)) {
|
||||
throw errors.createError(`Invalid image name: ${action.data.name}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid image name: ${action.data.name}`
|
||||
});
|
||||
}
|
||||
|
||||
if (action.data.logo && !_.isString(action.data.logo)) {
|
||||
throw errors.createError(`Invalid image logo: ${action.data.logo}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid image logo: ${action.data.logo}`
|
||||
});
|
||||
}
|
||||
|
||||
const selectedDrive = findDrive(state, state.getIn([ 'selection', 'drive' ]));
|
||||
@ -346,19 +406,27 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
const value = action.data.value;
|
||||
|
||||
if (!key) {
|
||||
throw errors.createError('Missing setting key');
|
||||
throw errors.createError({
|
||||
title: 'Missing setting key'
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isString(key)) {
|
||||
throw errors.createError(`Invalid setting key: ${key}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid setting key: ${key}`
|
||||
});
|
||||
}
|
||||
|
||||
if (!DEFAULT_STATE.get('settings').has(key)) {
|
||||
throw errors.createError(`Unsupported setting: ${key}`);
|
||||
throw errors.createError({
|
||||
title: `Unsupported setting: ${key}`
|
||||
});
|
||||
}
|
||||
|
||||
if (_.isObject(value)) {
|
||||
throw errors.createError(`Invalid setting value: ${value}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid setting value: ${value}`
|
||||
});
|
||||
}
|
||||
|
||||
return state.setIn([ 'settings', key ], value);
|
||||
|
@ -68,9 +68,12 @@ module.exports = function(
|
||||
*/
|
||||
this.selectImage = (image) => {
|
||||
if (!supportedFormats.isSupportedImage(image.path)) {
|
||||
const invalidImageError = errors.createUserError('Invalid image', messages.error.invalidImage({
|
||||
image
|
||||
}));
|
||||
const invalidImageError = errors.createUserError({
|
||||
title: 'Invalid image',
|
||||
description: messages.error.invalidImage({
|
||||
image
|
||||
})
|
||||
});
|
||||
|
||||
OSDialogService.showError(invalidImageError);
|
||||
AnalyticsService.logEvent('Invalid image', image);
|
||||
|
@ -41,7 +41,9 @@ module.exports = (ManifestBindService) => {
|
||||
const value = ManifestBindService.get(attributes.manifestBind);
|
||||
|
||||
if (!value) {
|
||||
throw errors.createError(`ManifestBind: Unknown property \`${attributes.manifestBind}\``);
|
||||
throw errors.createError({
|
||||
title: `ManifestBind: Unknown property \`${attributes.manifestBind}\``
|
||||
});
|
||||
}
|
||||
|
||||
element.html(value);
|
||||
|
@ -89,7 +89,9 @@ exports.extractFile = (archive, entries, file) => {
|
||||
if (!_.find(entries, {
|
||||
name: file
|
||||
})) {
|
||||
throw errors.createError(`Invalid entry: ${file}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid entry: ${file}`
|
||||
});
|
||||
}
|
||||
|
||||
yauzl.openAsync(archive, {
|
||||
|
@ -119,10 +119,10 @@ const extractArchiveMetadata = (archive, basePath, options) => {
|
||||
try {
|
||||
return JSON.parse(manifest);
|
||||
} catch (parseError) {
|
||||
throw errors.createUserError(
|
||||
'Invalid archive manifest.json',
|
||||
'The archive manifest.json file is not valid JSON'
|
||||
);
|
||||
throw errors.createUserError({
|
||||
title: 'Invalid archive manifest.json',
|
||||
description: 'The archive manifest.json file is not valid JSON'
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
@ -178,10 +178,10 @@ exports.extractImage = (archive, hooks) => {
|
||||
|
||||
const VALID_NUMBER_OF_IMAGE_ENTRIES = 1;
|
||||
if (imageEntries.length !== VALID_NUMBER_OF_IMAGE_ENTRIES) {
|
||||
throw errors.createUserError(
|
||||
'Invalid archive image',
|
||||
'The archive image should contain one and only one top image file'
|
||||
);
|
||||
throw errors.createUserError({
|
||||
title: 'Invalid archive image',
|
||||
description: 'The archive image should contain one and only one top image file'
|
||||
});
|
||||
}
|
||||
|
||||
const imageEntry = _.first(imageEntries);
|
||||
|
@ -69,12 +69,18 @@ const errors = require('../shared/errors');
|
||||
exports.getFromFilePath = (file) => {
|
||||
return fs.statAsync(file).then((fileStats) => {
|
||||
if (!fileStats.isFile()) {
|
||||
throw errors.createUserError('Invalid image', 'The image must be a file');
|
||||
throw errors.createUserError({
|
||||
title: 'Invalid image',
|
||||
description: 'The image must be a file'
|
||||
});
|
||||
}
|
||||
|
||||
return utils.getArchiveMimeType(file).then((type) => {
|
||||
if (!_.has(handlers, type)) {
|
||||
throw errors.createUserError('Invalid image', `The ${type} format is not supported`);
|
||||
throw errors.createUserError({
|
||||
title: 'Invalid image',
|
||||
description: `The ${type} format is not supported`
|
||||
});
|
||||
}
|
||||
|
||||
return _.invoke(handlers, type, file, {
|
||||
|
@ -231,23 +231,27 @@ exports.getDescription = (error, options = {}) => {
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} title - error title
|
||||
* @param {String} [description] - error description
|
||||
* @param {Object} [options] - options
|
||||
* @param {Object} options - options
|
||||
* @param {String} options.title - error title
|
||||
* @param {String} [options.description] - error description
|
||||
* @param {Boolean} [options.report] - report error
|
||||
* @returns {Error} error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createError('Foo', 'Bar');
|
||||
* const error = errors.createError({
|
||||
* title: 'Foo'
|
||||
* description: 'Bar'
|
||||
* });
|
||||
*
|
||||
* throw error;
|
||||
*/
|
||||
exports.createError = (title, description, options = {}) => {
|
||||
if (isBlank(title)) {
|
||||
throw new Error(`Invalid error title: ${title}`);
|
||||
exports.createError = (options) => {
|
||||
if (isBlank(options.title)) {
|
||||
throw new Error(`Invalid error title: ${options.title}`);
|
||||
}
|
||||
|
||||
const error = new Error(title);
|
||||
error.description = description;
|
||||
const error = new Error(options.title);
|
||||
error.description = options.description;
|
||||
|
||||
if (!_.isNil(options.report) && !options.report) {
|
||||
error.report = false;
|
||||
@ -267,16 +271,23 @@ exports.createError = (title, description, options = {}) => {
|
||||
* Therefore, user errors don't get reported to analytics
|
||||
* and error reporting services.
|
||||
*
|
||||
* @param {String} title - error title
|
||||
* @param {String} [description] - error description
|
||||
* @param {Object} options - options
|
||||
* @param {String} options.title - error title
|
||||
* @param {String} [options.description] - error description
|
||||
* @returns {Error} user error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createUserError('Foo', 'Bar');
|
||||
* const error = errors.createUserError({
|
||||
* title: 'Foo',
|
||||
* description: 'Bar'
|
||||
* });
|
||||
*
|
||||
* throw error;
|
||||
*/
|
||||
exports.createUserError = (title, description) => {
|
||||
return exports.createError(title, description, {
|
||||
exports.createUserError = (options) => {
|
||||
return exports.createError({
|
||||
title: options.title,
|
||||
description: options.description,
|
||||
report: false
|
||||
});
|
||||
};
|
||||
|
@ -120,7 +120,11 @@ functions: `.printError()` and `.recomposeErrorMessage()`.
|
||||
Here's an example of these functions in action:
|
||||
|
||||
```javascript
|
||||
const error = errors.createError('This is an error', 'My description');
|
||||
const error = errors.createError({
|
||||
title: 'This is an error',
|
||||
description: 'My description'
|
||||
});
|
||||
|
||||
robot.printError(error);
|
||||
```
|
||||
|
||||
|
@ -56,7 +56,9 @@ exports.isEnabled = (environment) => {
|
||||
*/
|
||||
exports.buildMessage = (title, data = {}) => {
|
||||
if (!_.isPlainObject(data)) {
|
||||
throw errors.createError(`Invalid data: ${data}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid data: ${data}`
|
||||
});
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
@ -117,11 +119,17 @@ exports.parseMessage = (string) => {
|
||||
try {
|
||||
output = JSON.parse(string);
|
||||
} catch (error) {
|
||||
throw errors.createError('Invalid message', `${string}, ${error.message}`);
|
||||
throw errors.createError({
|
||||
title: 'Invalid message',
|
||||
description: `${string}, ${error.message}`
|
||||
});
|
||||
}
|
||||
|
||||
if (!output.command || !output.data) {
|
||||
throw errors.createError('Invalid message', `No command or data: ${string}`);
|
||||
throw errors.createError({
|
||||
title: 'Invalid message',
|
||||
description: `No command or data: ${string}`
|
||||
});
|
||||
}
|
||||
|
||||
return output;
|
||||
|
@ -71,7 +71,9 @@ exports.isValidPercentage = (percentage) => {
|
||||
*/
|
||||
exports.percentageToFloat = (percentage) => {
|
||||
if (!exports.isValidPercentage(percentage)) {
|
||||
throw errors.createError(`Invalid percentage: ${percentage}`);
|
||||
throw errors.createError({
|
||||
title: `Invalid percentage: ${percentage}`
|
||||
});
|
||||
}
|
||||
|
||||
return percentage / PERCENTAGE_MAXIMUM;
|
||||
|
@ -390,12 +390,18 @@ describe('Shared: Errors', function() {
|
||||
describe('.createError()', function() {
|
||||
|
||||
it('should not set `error.report` by default', function() {
|
||||
const error = errors.createError('Foo', 'Something happened');
|
||||
const error = errors.createError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened'
|
||||
});
|
||||
|
||||
m.chai.expect(error.report).to.be.undefined;
|
||||
});
|
||||
|
||||
it('should set `error.report` to false if `options.report` is false', function() {
|
||||
const error = errors.createError('Foo', 'Something happened', {
|
||||
const error = errors.createError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened',
|
||||
report: false
|
||||
});
|
||||
|
||||
@ -403,7 +409,9 @@ describe('Shared: Errors', function() {
|
||||
});
|
||||
|
||||
it('should set `error.report` to false if `options.report` evaluates to false', function() {
|
||||
const error = errors.createError('Foo', 'Something happened', {
|
||||
const error = errors.createError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened',
|
||||
report: 0
|
||||
});
|
||||
|
||||
@ -411,47 +419,78 @@ describe('Shared: Errors', function() {
|
||||
});
|
||||
|
||||
it('should be an instance of Error', function() {
|
||||
const error = errors.createError('Foo', 'Something happened');
|
||||
const error = errors.createError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened'
|
||||
});
|
||||
|
||||
m.chai.expect(error).to.be.an.instanceof(Error);
|
||||
});
|
||||
|
||||
it('should correctly add both a message and a description', function() {
|
||||
const error = errors.createError('Foo', 'Something happened');
|
||||
it('should correctly add both a title and a description', function() {
|
||||
const error = errors.createError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened'
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||
m.chai.expect(errors.getDescription(error)).to.equal('Something happened');
|
||||
});
|
||||
|
||||
it('should correctly add only a message', function() {
|
||||
const error = errors.createError('Foo');
|
||||
it('should correctly add only a title', function() {
|
||||
const error = errors.createError({
|
||||
title: 'Foo'
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||
});
|
||||
|
||||
it('should ignore an empty description', function() {
|
||||
const error = errors.createError('Foo', '');
|
||||
const error = errors.createError({
|
||||
title: 'Foo',
|
||||
description: ''
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||
});
|
||||
|
||||
it('should ignore a blank description', function() {
|
||||
const error = errors.createError('Foo', ' ');
|
||||
const error = errors.createError({
|
||||
title: 'Foo',
|
||||
description: ' '
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||
});
|
||||
|
||||
it('should throw if no message', function() {
|
||||
it('should throw if no title', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createError();
|
||||
errors.createError({});
|
||||
}).to.throw('Invalid error title: undefined');
|
||||
});
|
||||
|
||||
it('should throw if message is empty', function() {
|
||||
it('should throw if there is a description but no title', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createError('');
|
||||
errors.createError({
|
||||
description: 'foo'
|
||||
});
|
||||
}).to.throw('Invalid error title: undefined');
|
||||
});
|
||||
|
||||
it('should throw if title is empty', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createError({
|
||||
title: ''
|
||||
});
|
||||
}).to.throw('Invalid error title: ');
|
||||
});
|
||||
|
||||
it('should throw if message is blank', function() {
|
||||
it('should throw if title is blank', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createError(' ');
|
||||
errors.createError({
|
||||
title: ' '
|
||||
});
|
||||
}).to.throw('Invalid error title: ');
|
||||
});
|
||||
|
||||
@ -460,52 +499,87 @@ describe('Shared: Errors', function() {
|
||||
describe('.createUserError()', function() {
|
||||
|
||||
it('should set the `report` flag to `false`', function() {
|
||||
const error = errors.createUserError('Foo', 'Something happened');
|
||||
const error = errors.createUserError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened'
|
||||
});
|
||||
|
||||
m.chai.expect(error.report).to.be.false;
|
||||
});
|
||||
|
||||
it('should be an instance of Error', function() {
|
||||
const error = errors.createUserError('Foo', 'Something happened');
|
||||
const error = errors.createUserError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened'
|
||||
});
|
||||
|
||||
m.chai.expect(error).to.be.an.instanceof(Error);
|
||||
});
|
||||
|
||||
it('should correctly add both a message and a description', function() {
|
||||
const error = errors.createUserError('Foo', 'Something happened');
|
||||
it('should correctly add both a title and a description', function() {
|
||||
const error = errors.createUserError({
|
||||
title: 'Foo',
|
||||
description: 'Something happened'
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||
m.chai.expect(errors.getDescription(error)).to.equal('Something happened');
|
||||
});
|
||||
|
||||
it('should correctly add only a message', function() {
|
||||
const error = errors.createUserError('Foo');
|
||||
it('should correctly add only a title', function() {
|
||||
const error = errors.createUserError({
|
||||
title: 'Foo'
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||
});
|
||||
|
||||
it('should ignore an empty description', function() {
|
||||
const error = errors.createUserError('Foo', '');
|
||||
const error = errors.createUserError({
|
||||
title: 'Foo',
|
||||
description: ''
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||
});
|
||||
|
||||
it('should ignore a blank description', function() {
|
||||
const error = errors.createUserError('Foo', ' ');
|
||||
const error = errors.createUserError({
|
||||
title: 'Foo',
|
||||
description: ' '
|
||||
});
|
||||
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||
});
|
||||
|
||||
it('should throw if no message', function() {
|
||||
it('should throw if no title', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createUserError();
|
||||
errors.createUserError({});
|
||||
}).to.throw('Invalid error title: undefined');
|
||||
});
|
||||
|
||||
it('should throw if message is empty', function() {
|
||||
it('should throw if title is empty', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createUserError('');
|
||||
errors.createUserError({
|
||||
title: ''
|
||||
});
|
||||
}).to.throw('Invalid error title: ');
|
||||
});
|
||||
|
||||
it('should throw if message is blank', function() {
|
||||
it('should throw if there is a description but no title', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createUserError(' ');
|
||||
errors.createUserError({
|
||||
description: 'foo'
|
||||
});
|
||||
}).to.throw('Invalid error title: undefined');
|
||||
});
|
||||
|
||||
it('should throw if title is blank', function() {
|
||||
m.chai.expect(() => {
|
||||
errors.createUserError({
|
||||
title: ' '
|
||||
});
|
||||
}).to.throw('Invalid error title: ');
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user