diff --git a/src/mutations.ts b/src/mutations.ts index ec6c57cd..6e9665af 100644 --- a/src/mutations.ts +++ b/src/mutations.ts @@ -69,7 +69,7 @@ function evaluateConditional( } const fieldSchema = schema.properties[fieldName] const fieldValue = values[fieldName] - const fieldErrors = validateSchema(fieldValue, fieldSchema, options.legacyOptions ?? {}) + const fieldErrors = validateSchema(fieldValue, fieldSchema, options.legacyOptions ?? {}, [], jsonLogicContext) return fieldErrors.some(error => error.validation === 'type') }) } diff --git a/test/validation/json-logic-v0.test.js b/test/validation/json-logic-v0.test.js index 2c7f6bc8..aae92442 100644 --- a/test/validation/json-logic-v0.test.js +++ b/test/validation/json-logic-v0.test.js @@ -19,6 +19,7 @@ import { schemaWithCustomValidationFunction, schemaWithDeepVarThatDoesNotExist, schemaWithDeepVarThatDoesNotExistOnFieldset, + schemaWithIfRequiredAndLogicValidationOnSameField, schemaWithInlinedRuleOnComputedAttributeThatReferencesUnknownVar, schemaWithMissingComputedValue, schemaWithMissingRule, @@ -491,3 +492,47 @@ describe('jsonLogic: cross-values validations', () => { }) }) }) + +describe('jsonLogic: if.required with x-jsf-logic-validations on the same field', () => { + it('does not throw at build time when an if.required field carries validations', () => { + expect(() => + createHeadlessForm(schemaWithIfRequiredAndLogicValidationOnSameField, { + strictInputType: false, + initialValues: { field_a: 5, field_c: 'x' }, + }), + ).not.toThrow() + }) + + it('runs the field validation instead of throwing (then branch)', () => { + const { handleValidation } = createHeadlessForm( + schemaWithIfRequiredAndLogicValidationOnSameField, + { strictInputType: false }, + ) + + // field_a === 5 -> if matches -> field_c required; validation a_at_least_ten fails (5 < 10) + expect(handleValidation({ field_a: 5, field_c: 'x' }).formErrors).toEqual({ + field_a: 'Field A must be at least 10', + }) + + // field_a === 5, field_c missing -> both the validation error AND field_c required + expect(handleValidation({ field_a: 5 }).formErrors).toEqual({ + field_a: 'Field A must be at least 10', + field_c: 'Required field', + }) + }) + + it('applies the else branch and validation when the condition is false', () => { + const { handleValidation } = createHeadlessForm( + schemaWithIfRequiredAndLogicValidationOnSameField, + { strictInputType: false }, + ) + + // field_a === 20 -> if false -> else hides field_c; validation passes (20 >= 10) + expect(handleValidation({ field_a: 20 }).formErrors).toBeUndefined() + + // field_a === 8 -> if false -> validation fails (8 < 10) + expect(handleValidation({ field_a: 8 }).formErrors).toEqual({ + field_a: 'Field A must be at least 10', + }) + }) +}) diff --git a/test/validation/json-logic.fixtures.ts b/test/validation/json-logic.fixtures.ts index 313b7a56..15b2149e 100644 --- a/test/validation/json-logic.fixtures.ts +++ b/test/validation/json-logic.fixtures.ts @@ -796,3 +796,47 @@ export const schemaWithCustomComputedValueFunction = { }, }, } + +// A field named in if.required that ALSO carries x-jsf-logic-validations. +// Reproduces the "required validation doesn't exist" throw when context is dropped. +export const schemaWithIfRequiredAndLogicValidationOnSameField = { + 'type': 'object', + 'properties': { + field_a: { + 'type': 'number', + 'x-jsf-logic-validations': ['a_at_least_ten'], + }, + field_c: { + type: 'string', + }, + }, + 'required': ['field_a'], + 'allOf': [ + { + if: { + properties: { + field_a: { const: 5 }, + }, + required: ['field_a'], + }, + then: { + required: ['field_c'], + }, + else: { + properties: { + field_c: false, + }, + }, + }, + ], + 'x-jsf-logic': { + validations: { + a_at_least_ten: { + errorMessage: 'Field A must be at least 10', + rule: { + '>=': [{ var: 'field_a' }, 10], + }, + }, + }, + }, +}