diff --git a/src/process/validation/rules/__tests__/validateMask.test.ts b/src/process/validation/rules/__tests__/validateMask.test.ts index 3a6ae3ae..f01d8e19 100644 --- a/src/process/validation/rules/__tests__/validateMask.test.ts +++ b/src/process/validation/rules/__tests__/validateMask.test.ts @@ -86,3 +86,33 @@ it('Validating a mutil-mask component should return null if the value matches th result = await validateMask(context); expect(result).to.equal(null); }); + +it('Validating a mask component should return null if the instance contains a skipMaskValidation property', async () => { + const component = { ...simpleTextField, inputMask: '999-999-9999' }; + const data = { + component: '1234', + }; + const context = generateProcessorContext(component, data); + let result = await validateMask(context); + expect(result).to.be.instanceOf(FieldError); + expect(result?.errorKeyOrMessage).to.equal('mask'); + (context as any).instance = { skipMaskValidation: true }; + result = await validateMask(context); + expect(result).to.equal(null); +}); + +it('Validating a mask component should return null if the validate object contains a skipMaskValidation', async () => { + const component = { + ...simpleTextField, + inputMask: '999-999-9999', + validate: { + skipMaskValidation: true, + }, + }; + const data = { + component: '1234', + }; + const context = generateProcessorContext(component, data); + const result = await validateMask(context); + expect(result).to.equal(null); +}); diff --git a/src/process/validation/rules/validateMask.ts b/src/process/validation/rules/validateMask.ts index a30c4ff3..c56e11a0 100644 --- a/src/process/validation/rules/validateMask.ts +++ b/src/process/validation/rules/validateMask.ts @@ -13,12 +13,19 @@ const isMaskType = (obj: any): obj is DataObject & { maskName: string; value: st ); }; -const isValidatableComponent = (component: any): component is TextFieldComponent => { +const isValidatableComponent = (component: any, instance: any): component is TextFieldComponent => { + if (!component) return false; + + const { type, inputMask, inputMasks, validate } = component; + // For some reason we skip mask validation for time components - return ((component && component.type && component.type !== 'time') && - (component && component.hasOwnProperty('inputMask') && !!component.inputMask) || - (component && component.hasOwnProperty('inputMasks') && !isEmpty(component.inputMasks)) - ); + if (type === 'time') return false; + + const hasInputMask = inputMask || !isEmpty(inputMasks); + // Include instance.skipMaskValidation check to maintain backward compatibility + const skipMaskValidation = validate?.skipMaskValidation || instance?.skipMaskValidation; + + return hasInputMask && !skipMaskValidation; }; function getMaskByLabel(component: TextFieldComponent, maskName: string | undefined) { @@ -90,8 +97,8 @@ export function matchInputMask(value: any, inputMask: any) { } export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableComponent(component) || !value) { + const { component, value, instance } = context; + if (!isValidatableComponent(component, instance) || !value) { return false; } if (value == null) { diff --git a/src/types/Component.ts b/src/types/Component.ts index 5fec266f..c81139de 100644 --- a/src/types/Component.ts +++ b/src/types/Component.ts @@ -72,6 +72,7 @@ export type TextFieldComponent = BaseComponent & { maxWords?: number | string; pattern?: string; patternMessage?: string; + skipMaskValidation?: boolean; }; };