From 674943b001469096a9760652b452308cb014be16 Mon Sep 17 00:00:00 2001 From: brennj Date: Wed, 16 Aug 2023 10:44:11 +0200 Subject: [PATCH 1/7] feat: allow consts to support single values only --- src/helpers.js | 1 + src/tests/const.test.js | 58 +++++++++++++++++++++++++++++++++++++++++ src/yupSchema.js | 18 +++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 src/tests/const.test.js 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..4438ea070 --- /dev/null +++ b/src/tests/const.test.js @@ -0,0 +1,58 @@ +import { createHeadlessForm } from '../createHeadlessForm'; + +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).toEqual(undefined); +}); + +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); +}); 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); } From e872fdc5a227857557557844a73a455f63a6bd60 Mon Sep 17 00:00:00 2001 From: brennj Date: Wed, 16 Aug 2023 10:49:36 +0200 Subject: [PATCH 2/7] chore: custom error message test --- src/tests/const.test.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/tests/const.test.js b/src/tests/const.test.js index 4438ea070..04056d42e 100644 --- a/src/tests/const.test.js +++ b/src/tests/const.test.js @@ -56,3 +56,23 @@ it('Should work for a conditionally applied const', () => { }); 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); +}); From ff0d02bf9ac532d3ee1e42761316b5f8ac0aaa03 Mon Sep 17 00:00:00 2001 From: brennj Date: Tue, 29 Aug 2023 12:20:47 +0200 Subject: [PATCH 3/7] Release 0.4.4-dev.20230829102031 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a64d5962..d6710cca7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.3-beta.0", + "version": "0.4.4-dev.20230829102031", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@remoteoss/json-schema-form", - "version": "0.4.3-beta.0", + "version": "0.4.4-dev.20230829102031", "license": "MIT", "dependencies": { "lodash": "^4.17.21", diff --git a/package.json b/package.json index 9ae29288e..daa0602f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.3-beta.0", + "version": "0.4.4-dev.20230829102031", "description": "Headless UI form powered by JSON Schemas", "author": "Remote.com (https://remote.com/)", "license": "MIT", From 031706249ec7eca8bc18f6f553dd5ecfcc71324d Mon Sep 17 00:00:00 2001 From: brennj Date: Tue, 29 Aug 2023 12:25:41 +0200 Subject: [PATCH 4/7] Revert "Release 0.4.4-dev.20230829102031" This reverts commit ff0d02bf9ac532d3ee1e42761316b5f8ac0aaa03. --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d6710cca7..7a64d5962 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.4-dev.20230829102031", + "version": "0.4.3-beta.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@remoteoss/json-schema-form", - "version": "0.4.4-dev.20230829102031", + "version": "0.4.3-beta.0", "license": "MIT", "dependencies": { "lodash": "^4.17.21", diff --git a/package.json b/package.json index daa0602f5..9ae29288e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.4-dev.20230829102031", + "version": "0.4.3-beta.0", "description": "Headless UI form powered by JSON Schemas", "author": "Remote.com (https://remote.com/)", "license": "MIT", From 143a3d9c9435e27230299aabd14eb2dfb25d77f3 Mon Sep 17 00:00:00 2001 From: brennj Date: Tue, 29 Aug 2023 21:16:17 +0200 Subject: [PATCH 5/7] chore: feedback from sandrina --- src/tests/const.test.js | 134 +++++++++++++++++++----------------- src/tests/helpers.custom.js | 1 - 2 files changed, 71 insertions(+), 64 deletions(-) diff --git a/src/tests/const.test.js b/src/tests/const.test.js index 04056d42e..ccb6a1e13 100644 --- a/src/tests/const.test.js +++ b/src/tests/const.test.js @@ -1,78 +1,86 @@ import { createHeadlessForm } from '../createHeadlessForm'; -it('Should work for number', () => { - const { handleValidation } = createHeadlessForm( - { - properties: { - ten_only: { type: 'number', const: 10 }, +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.', + { 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(); }); - expect(handleValidation({ ten_only: 10 }).formErrors).toEqual(undefined); -}); -it('Should work for text', () => { - const { handleValidation } = createHeadlessForm( - { - properties: { - hello_only: { type: 'string', const: 'hello' }, + 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.', + { 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); }); - 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'] }, + 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', + }, }, - ], - }, - { 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.', + 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); }); - 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!!!' }, + 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!!!', + { 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); }); - 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', }, }, From 2c2c5242952a55dd945ba82fede149eef031f180 Mon Sep 17 00:00:00 2001 From: brennj Date: Tue, 29 Aug 2023 21:17:07 +0200 Subject: [PATCH 6/7] Release 0.4.4-dev.20230829191632 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a64d5962..4a11365d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.3-beta.0", + "version": "0.4.4-dev.20230829191632", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@remoteoss/json-schema-form", - "version": "0.4.3-beta.0", + "version": "0.4.4-dev.20230829191632", "license": "MIT", "dependencies": { "lodash": "^4.17.21", diff --git a/package.json b/package.json index 9ae29288e..9e4cb6e0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.3-beta.0", + "version": "0.4.4-dev.20230829191632", "description": "Headless UI form powered by JSON Schemas", "author": "Remote.com (https://remote.com/)", "license": "MIT", From 4bdcf84ff038a80629e6fa8956937fdc5ac3c8a9 Mon Sep 17 00:00:00 2001 From: brennj Date: Tue, 29 Aug 2023 21:17:28 +0200 Subject: [PATCH 7/7] Revert "Release 0.4.4-dev.20230829191632" This reverts commit 2c2c5242952a55dd945ba82fede149eef031f180. --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4a11365d0..7a64d5962 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.4-dev.20230829191632", + "version": "0.4.3-beta.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@remoteoss/json-schema-form", - "version": "0.4.4-dev.20230829191632", + "version": "0.4.3-beta.0", "license": "MIT", "dependencies": { "lodash": "^4.17.21", diff --git a/package.json b/package.json index 9e4cb6e0c..9ae29288e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.4.4-dev.20230829191632", + "version": "0.4.3-beta.0", "description": "Headless UI form powered by JSON Schemas", "author": "Remote.com (https://remote.com/)", "license": "MIT",