diff --git a/src/helpers.js b/src/helpers.js index 47cb7b893..d6b1f1664 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -425,6 +425,7 @@ export function extractParametersFromNode(schemaNode) { return omitBy( { + const: node.const, label: node.title, readOnly: node.readOnly, ...(node.deprecated && { diff --git a/src/tests/const.test.js b/src/tests/const.test.js new file mode 100644 index 000000000..ccb6a1e13 --- /dev/null +++ b/src/tests/const.test.js @@ -0,0 +1,86 @@ +import { createHeadlessForm } from '../createHeadlessForm'; + +describe('validations: const', () => { + it('Should work for number', () => { + const { handleValidation } = createHeadlessForm( + { + properties: { + ten_only: { type: 'number', const: 10 }, + }, + }, + { strictInputType: false } + ); + expect(handleValidation({}).formErrors).toEqual(undefined); + expect(handleValidation({ ten_only: 1 }).formErrors).toEqual({ + ten_only: 'The only accepted value is 10.', + }); + expect(handleValidation({ ten_only: 10 }).formErrors).toBeUndefined(); + // null is also considered valid until we fix @BUG RMT-518 + // Expectation: To fail with error "The only accepted value is 10." + expect(handleValidation({ ten_only: null }).formErrors).toBeUndefined(); + }); + + it('Should work for text', () => { + const { handleValidation } = createHeadlessForm( + { + properties: { + hello_only: { type: 'string', const: 'hello' }, + }, + }, + { strictInputType: false } + ); + expect(handleValidation({}).formErrors).toEqual(undefined); + expect(handleValidation({ hello_only: 'what' }).formErrors).toEqual({ + hello_only: 'The only accepted value is hello.', + }); + expect(handleValidation({ hello_only: 'hello' }).formErrors).toEqual(undefined); + }); + + it('Should work for a conditionally applied const', () => { + const { handleValidation } = createHeadlessForm( + { + properties: { + answer: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] }, + amount: { + description: 'If you select yes, this needs to be exactly 10.', + type: 'number', + }, + }, + allOf: [ + { + if: { properties: { answer: { const: 'yes' } }, required: ['answer'] }, + then: { properties: { amount: { const: 10 } }, required: ['amount'] }, + }, + ], + }, + { strictInputType: false } + ); + expect(handleValidation({}).formErrors).toEqual(undefined); + expect(handleValidation({ answer: 'no' }).formErrors).toEqual(undefined); + expect(handleValidation({ answer: 'yes' }).formErrors).toEqual({ amount: 'Required field' }); + expect(handleValidation({ answer: 'yes', amount: 1 }).formErrors).toEqual({ + amount: 'The only accepted value is 10.', + }); + expect(handleValidation({ answer: 'yes', amount: 10 }).formErrors).toEqual(undefined); + }); + + it('Should show the custom error message', () => { + const { handleValidation } = createHeadlessForm( + { + properties: { + string: { + type: 'string', + const: 'hello', + 'x-jsf-errorMessage': { const: 'You must say hello!!!' }, + }, + }, + }, + { strictInputType: false } + ); + expect(handleValidation({}).formErrors).toEqual(undefined); + expect(handleValidation({ string: 'hi' }).formErrors).toEqual({ + string: 'You must say hello!!!', + }); + expect(handleValidation({ string: 'hello' }).formErrors).toEqual(undefined); + }); +}); diff --git a/src/tests/helpers.custom.js b/src/tests/helpers.custom.js index e3cdb66b1..024a255dc 100644 --- a/src/tests/helpers.custom.js +++ b/src/tests/helpers.custom.js @@ -207,7 +207,6 @@ export const schemaInputTypeHidden = { title: 'Select multi hidden', default: ['Albania, Algeria'], 'x-jsf-presentation': { inputType: 'hidden' }, - const: ['Albania, Algeria'], type: 'array', }, }, diff --git a/src/yupSchema.js b/src/yupSchema.js index 42f30a30f..45db9812e 100644 --- a/src/yupSchema.js +++ b/src/yupSchema.js @@ -304,6 +304,19 @@ export function buildYupSchema(field, config) { ); } + function withConst(yupSchema) { + return yupSchema.test( + 'isConst', + errorMessage.const ?? + errorMessageFromConfig.const ?? + `The only accepted value is ${propertyFields.const}.`, + (value) => + (propertyFields.required === false && value === undefined) || + value === null || + value === propertyFields.const + ); + } + function withBaseSchema() { const customErrorMsg = errorMessage.type || errorMessageFromConfig.type; if (customErrorMsg) { @@ -388,6 +401,11 @@ export function buildYupSchema(field, config) { if (propertyFields.accept) { validators.push(withFileFormat); } + + if (propertyFields.const) { + validators.push(withConst); + } + return flow(validators); }