diff --git a/src/validation-errors/__tests__/__snapshots__/enum.js.snap b/src/validation-errors/__tests__/__snapshots__/enum.js.snap index 860494b4..04148a75 100644 --- a/src/validation-errors/__tests__/__snapshots__/enum.js.snap +++ b/src/validation-errors/__tests__/__snapshots__/enum.js.snap @@ -30,6 +30,18 @@ Array [ ] `; +exports[`Enum when value is an object prints correctly for allowedValues containing null 1`] = ` +Array [ + "ENUM should be equal to one of the allowed values", + "(one, two, null) +", + "  1 | { +> 2 |  \\"id\\": \\"baz\\" +  |  ^^^^^ 👈🏽 Unexpected value, should be equal to one of the allowed values +  3 | }", +] +`; + exports[`Enum when value is an object prints correctly for empty value 1`] = ` Array [ "ENUM should be equal to one of the allowed values", diff --git a/src/validation-errors/__tests__/enum.js b/src/validation-errors/__tests__/enum.js index 92a11a2a..f8eb87bb 100644 --- a/src/validation-errors/__tests__/enum.js +++ b/src/validation-errors/__tests__/enum.js @@ -55,6 +55,21 @@ describe('Enum', () => { expect(error.print(schema, { id: '' })).toMatchSnapshot(); }); + + it('prints correctly for allowedValues containing null', () => { + const error = new EnumValidationError( + { + keyword: 'enum', + dataPath: '/id', + schemaPath: '#/enum', + params: { allowedValues: ['one', 'two', null] }, + message: `should be equal to one of the allowed values`, + }, + { data, schema, jsonRaw, jsonAst } + ); + + expect(error.print()).toMatchSnapshot(); + }); }); describe('when value is a primitive', () => { diff --git a/src/validation-errors/enum.js b/src/validation-errors/enum.js index 276b114f..4a0129ce 100644 --- a/src/validation-errors/enum.js +++ b/src/validation-errors/enum.js @@ -3,6 +3,14 @@ import leven from 'leven'; import pointer from 'jsonpointer'; import BaseValidationError from './base'; +function printAllowedValues(allowedValues) { + return allowedValues + .map(value => + value === null || value === undefined ? String(value) : value + ) + .join(', '); +} + export default class EnumValidationError extends BaseValidationError { print() { const { @@ -13,7 +21,7 @@ export default class EnumValidationError extends BaseValidationError { const output = [ chalk`{red {bold ENUM} ${message}}`, - chalk`{red (${allowedValues.join(', ')})}\n`, + chalk`{red (${printAllowedValues(allowedValues)})}\n`, ]; return output.concat( @@ -33,7 +41,7 @@ export default class EnumValidationError extends BaseValidationError { ...this.getLocation(), error: `${this.getDecoratedPath( dataPath - )} ${message}: ${params.allowedValues.join(', ')}`, + )} ${message}: ${printAllowedValues(params.allowedValues)}`, path: dataPath, }; @@ -53,18 +61,23 @@ export default class EnumValidationError extends BaseValidationError { const currentValue = dataPath === '' ? this.data : pointer.get(this.data, dataPath); - if (!currentValue) { + if (typeof currentValue !== 'string') { return null; } - const bestMatch = allowedValues + const matches = allowedValues + .filter(value => typeof value === 'string') .map(value => ({ value, weight: leven(value, currentValue.toString()), })) - .sort((x, y) => - x.weight > y.weight ? 1 : x.weight < y.weight ? -1 : 0 - )[0]; + .sort((x, y) => (x.weight > y.weight ? 1 : x.weight < y.weight ? -1 : 0)); + + if (matches.length === 0) { + return; + } + + const bestMatch = matches[0]; return allowedValues.length === 1 || bestMatch.weight < bestMatch.value.length