From d5a4bae115a3365ee2d25ead7633d332a695b5e4 Mon Sep 17 00:00:00 2001 From: Kevin Foong <55353265+kevin9foong@users.noreply.github.com> Date: Mon, 18 Nov 2024 17:17:55 +0800 Subject: [PATCH] fix(mrf be val): skip validation for unchanged mrf responses (#7894) * feat: add more specific logs for date validation failures * feat: remove validation for unchanged mrf responses * feat: refactor isChanged to its own util to be testable, add tc * fix: change shared import to relative * chore: wrap case body in scope to remove disable-eslint lines --------- Co-authored-by: Ken --- .../__tests__/field-validation.utils.spec.ts | 555 ++++++++++++++++++ .../field-validation.utils.ts | 93 +++ src/app/utils/field-validation/index.ts | 15 +- .../__tests__/email-validation.spec.ts | 127 ---- .../__tests__/mobile-num-validation.spec.ts | 127 ---- .../validators/dateValidator.ts | 12 +- 6 files changed, 662 insertions(+), 267 deletions(-) create mode 100644 src/app/utils/field-validation/__tests__/field-validation.utils.spec.ts create mode 100644 src/app/utils/field-validation/field-validation.utils.ts diff --git a/src/app/utils/field-validation/__tests__/field-validation.utils.spec.ts b/src/app/utils/field-validation/__tests__/field-validation.utils.spec.ts new file mode 100644 index 0000000000..42ce0f23fc --- /dev/null +++ b/src/app/utils/field-validation/__tests__/field-validation.utils.spec.ts @@ -0,0 +1,555 @@ +import { + generateAttachmentResponseV3, + generateCheckboxResponseV3, + generateRadioResponseV3, + generateTableResponseV3, + generateVerifiableAnswerResponseV3, + generateYesNoAnswerResponseV3, +} from '__tests__/unit/backend/helpers/generate-form-data' +import { CLIENT_CHECKBOX_OTHERS_INPUT_VALUE } from 'shared/constants' +import { BasicField } from 'shared/types' + +import { checkIsResponseChangedV3 } from '../field-validation.utils' + +describe('checkIsResponseChangedV3', () => { + describe('yes/no field type', () => { + it('returns false if previous response is present but has not changed', () => { + const response = generateYesNoAnswerResponseV3('Yes') + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: { ...response }, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns true if no previous response is present', () => { + const response = generateYesNoAnswerResponseV3('Yes') + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: undefined, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response has changed', () => { + const response = generateYesNoAnswerResponseV3('Yes') + const prevResponse = generateYesNoAnswerResponseV3('No') + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + }) + + describe('mobile field type', () => { + it('returns false if previous response is present but has not changed', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Mobile, + answer: { + value: '+6598765432', + signature: 'some signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: { ...response }, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns true if no previous response is present', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Mobile, + answer: { + value: '+6598765432', + signature: 'some signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: undefined, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response value has changed', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Mobile, + answer: { + value: '+6598765432', + signature: 'some signature', + }, + }) + const prevResponse = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Mobile, + answer: { + value: '+6587654321', + signature: 'some signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response signature has changed', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Mobile, + answer: { + value: '+6598765432', + signature: 'new signature', + }, + }) + const prevResponse = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Mobile, + answer: { + value: '+6598765432', + signature: 'old signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + }) + + describe('email field type', () => { + it('returns false if previous response is present but has not changed', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Email, + answer: { + value: 'valid@email.com', + signature: 'some signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: { ...response }, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns true if no previous response is present', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Email, + answer: { + value: 'valid@email.com', + signature: 'some signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: undefined, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response value has changed', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Email, + answer: { + value: 'valid@email.com', + signature: 'some signature', + }, + }) + const prevResponse = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Email, + answer: { + value: 'different@email.com', + signature: 'some signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response signature has changed', () => { + const response = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Email, + answer: { + value: 'valid@email.com', + signature: 'new signature', + }, + }) + const prevResponse = generateVerifiableAnswerResponseV3({ + fieldType: BasicField.Email, + answer: { + value: 'valid@email.com', + signature: 'old signature', + }, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + }) + + describe('radio field type', () => { + it('returns false if previous response is present but has not changed', () => { + const response = generateRadioResponseV3({ + value: 'a', + }) + const prevResponse = generateRadioResponseV3({ + value: 'a', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns false if previous response changes to othersInput but the string is equal', () => { + const response = generateRadioResponseV3({ + value: 'a', + }) + const prevResponse = generateRadioResponseV3({ + othersInput: 'a', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns true if no previous response is present', () => { + const response = generateRadioResponseV3({ + value: 'a', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: undefined, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response value has changed', () => { + const response = generateRadioResponseV3({ + value: 'a', + }) + const prevResponse = generateRadioResponseV3({ + value: 'b', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response value changes from othersInput to value and the string is not equal', () => { + const response = generateRadioResponseV3({ + value: 'new input', + }) + const prevResponse = generateRadioResponseV3({ + othersInput: 'old input', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response value changes from value to othersInput and the string is not equal', () => { + const response = generateRadioResponseV3({ + othersInput: 'new input', + }) + const prevResponse = generateRadioResponseV3({ + value: 'old input', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response othersInput has changed', () => { + const response = generateRadioResponseV3({ + othersInput: 'new input', + }) + const prevResponse = generateRadioResponseV3({ + othersInput: 'old input', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + }) + + describe('checkbox field type', () => { + it('returns false if previous response is present but has not changed', () => { + const response = generateCheckboxResponseV3({ + value: ['a', 'b'], + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: { ...response }, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns false when othersInput value is changed but not selected for current and previous responses', () => { + const response = generateCheckboxResponseV3({ + value: ['a'], + }) + const prevResponse = generateCheckboxResponseV3({ + value: ['a'], + othersInput: 'old input', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns true if the othersInput value is different', () => { + const response = generateCheckboxResponseV3({ + value: ['a', CLIENT_CHECKBOX_OTHERS_INPUT_VALUE], + othersInput: 'new input', + }) + const prevResponse = generateCheckboxResponseV3({ + value: ['a', CLIENT_CHECKBOX_OTHERS_INPUT_VALUE], + othersInput: 'old input', + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true when new othersInput is added', () => { + const response = generateCheckboxResponseV3({ + value: ['a', CLIENT_CHECKBOX_OTHERS_INPUT_VALUE], + othersInput: 'new input', + }) + const prevResponse = generateCheckboxResponseV3({ + value: ['a'], + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true when othersInput is removed', () => { + const response = generateCheckboxResponseV3({ + value: ['a'], + }) + const prevResponse = generateCheckboxResponseV3({ + value: ['a', CLIENT_CHECKBOX_OTHERS_INPUT_VALUE], + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if no previous response is present', () => { + const response = generateCheckboxResponseV3({ + value: ['a', 'b'], + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: undefined, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response has changed', () => { + const response = generateCheckboxResponseV3({ + value: ['a', 'b'], + }) + const prevResponse = generateCheckboxResponseV3({ + value: ['b', 'c'], + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + }) + + describe('table field type', () => { + it('returns false if previous response is present but has not changed', () => { + const response = generateTableResponseV3([ + { + '000000000000000000000001': 'hello', + '000000000000000000000002': 'world', + }, + ]) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: { ...response }, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns true if no previous response is present', () => { + const response = generateTableResponseV3([ + { + '000000000000000000000001': 'hello', + '000000000000000000000002': 'world', + }, + ]) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: undefined, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response row content has changed', () => { + const response = generateTableResponseV3([ + { + '000000000000000000000001': 'hello', + '000000000000000000000002': 'new world', + }, + ]) + const prevResponse = generateTableResponseV3([ + { + '000000000000000000000001': 'hello', + '000000000000000000000002': 'old world', + }, + ]) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if number of rows has changed', () => { + const response = generateTableResponseV3([ + { + '000000000000000000000001': 'hello', + '000000000000000000000002': 'world', + }, + { + '000000000000000000000001': 'hello2', + '000000000000000000000002': 'world2', + }, + ]) + const prevResponse = generateTableResponseV3([ + { + '000000000000000000000001': 'hello', + '000000000000000000000002': 'world', + }, + ]) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + }) + + describe('attachment field type', () => { + it('returns false if previous response is present but has not changed', () => { + const response = generateAttachmentResponseV3({ + content: Buffer.from('test content'), + answer: 'test answer', + filename: 'test.txt', + hasBeenScanned: false, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: { ...response }, + }) + expect(checkIsResponseChangedV3Result).toBe(false) + }) + + it('returns true if no previous response is present', () => { + const response = generateAttachmentResponseV3({ + content: Buffer.from('test content'), + answer: 'test answer', + filename: 'test.txt', + hasBeenScanned: false, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse: undefined, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response content has changed', () => { + const response = generateAttachmentResponseV3({ + content: Buffer.from('new content'), + answer: 'test answer', + filename: 'test.txt', + hasBeenScanned: false, + }) + const prevResponse = generateAttachmentResponseV3({ + content: Buffer.from('old content'), + answer: 'test answer', + filename: 'test.txt', + hasBeenScanned: false, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response answer has changed', () => { + const response = generateAttachmentResponseV3({ + content: Buffer.from('test content'), + answer: 'new answer', + filename: 'test.txt', + hasBeenScanned: false, + }) + const prevResponse = generateAttachmentResponseV3({ + content: Buffer.from('test content'), + answer: 'old answer', + filename: 'test.txt', + hasBeenScanned: false, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + + it('returns true if response filename has changed', () => { + const response = generateAttachmentResponseV3({ + content: Buffer.from('test content'), + answer: 'test answer', + filename: 'new.txt', + hasBeenScanned: false, + }) + const prevResponse = generateAttachmentResponseV3({ + content: Buffer.from('test content'), + answer: 'test answer', + filename: 'old.txt', + hasBeenScanned: false, + }) + const checkIsResponseChangedV3Result = checkIsResponseChangedV3({ + response, + prevResponse, + }) + expect(checkIsResponseChangedV3Result).toBe(true) + }) + }) +}) diff --git a/src/app/utils/field-validation/field-validation.utils.ts b/src/app/utils/field-validation/field-validation.utils.ts new file mode 100644 index 0000000000..bfe8f7f5d3 --- /dev/null +++ b/src/app/utils/field-validation/field-validation.utils.ts @@ -0,0 +1,93 @@ +import { isEqual } from 'lodash' + +import { CLIENT_CHECKBOX_OTHERS_INPUT_VALUE } from '../../../../shared/constants' +import { BasicField } from '../../../../shared/types' +import { ParsedClearFormFieldResponseV3 } from '../../../types/api/submission' + +import { isGenericStringAnswerResponseV3 } from './field-validation.guards' + +export const checkIsResponseChangedV3 = ({ + response, + prevResponse, +}: { + response: ParsedClearFormFieldResponseV3 + prevResponse?: ParsedClearFormFieldResponseV3 +}): boolean => { + if (!prevResponse) { + return true + } + if (response.fieldType !== prevResponse.fieldType) { + return true + } + + if (isGenericStringAnswerResponseV3(response)) { + return response.answer.toString() !== prevResponse.answer.toString() + } + + switch (response.fieldType) { + case BasicField.YesNo: + return response.answer !== prevResponse.answer + case BasicField.Email: + case BasicField.Mobile: + return !( + response.fieldType === prevResponse.fieldType && + prevResponse.answer.value === response.answer.value && + prevResponse.answer.signature === response.answer.signature + ) + case BasicField.Radio: { + if (prevResponse.fieldType !== response.fieldType) { + return true + } + const prevResponseValue = + 'value' in prevResponse.answer + ? prevResponse.answer.value + : 'othersInput' in prevResponse.answer + ? prevResponse.answer.othersInput + : null + const responseValue = + 'value' in response.answer + ? response.answer.value + : 'othersInput' in response.answer + ? response.answer.othersInput + : null + return prevResponseValue !== responseValue + } + case BasicField.Checkbox: { + if (prevResponse.fieldType !== response.fieldType) { + return true + } + const isOthersInputSelected = response.answer.value.includes( + CLIENT_CHECKBOX_OTHERS_INPUT_VALUE, + ) + const isOthersInputSelectedPrev = prevResponse.answer.value.includes( + CLIENT_CHECKBOX_OTHERS_INPUT_VALUE, + ) + return ( + !isEqual( + new Set(response.answer.value), + new Set(prevResponse.answer.value), + ) || + isOthersInputSelected !== isOthersInputSelectedPrev || + // if the othersInput is selected in both response and prevResponse, then return true if the othersInput values are different + (isOthersInputSelected && + isOthersInputSelectedPrev && + response.answer.othersInput !== prevResponse.answer.othersInput) + ) + } + case BasicField.Table: + return ( + JSON.stringify(response.answer) !== JSON.stringify(prevResponse.answer) + ) + case BasicField.Attachment: + if (prevResponse.fieldType !== response.fieldType) { + return true + } + return ( + response.answer.filename !== prevResponse.answer.filename || + response.answer.answer !== prevResponse.answer.answer || + response.answer.content !== prevResponse.answer.content + ) + default: + return true + } +} diff --git a/src/app/utils/field-validation/index.ts b/src/app/utils/field-validation/index.ts index 6826ad742a..3bbd28b676 100644 --- a/src/app/utils/field-validation/index.ts +++ b/src/app/utils/field-validation/index.ts @@ -40,6 +40,7 @@ import { isProcessedSingleAnswerResponse, isProcessedTableResponse, } from './field-validation.guards' +import { checkIsResponseChangedV3 } from './field-validation.utils' const logger = createLoggerWithLabel(module) @@ -361,6 +362,10 @@ const isValidationRequiredV3 = ({ isVisible: boolean formId: string }): Result => { + if (!checkIsResponseChangedV3({ response, prevResponse })) { + return ok(false) + } + if (isGenericStringAnswerResponseV3(response)) { return ok( (formField.required && isVisible) || @@ -375,16 +380,6 @@ const isValidationRequiredV3 = ({ ) case BasicField.Email: case BasicField.Mobile: - // For verifiable field, if the value and signature are the same as the previous response, - // then the field does not need to be validated again. - if ( - prevResponse && - response.fieldType === prevResponse.fieldType && - prevResponse.answer.value === response.answer.value && - prevResponse.answer.signature === response.answer.signature - ) { - return ok(false) - } return ok( (formField.required && isVisible) || response.answer.value.trim() !== '' || diff --git a/src/app/utils/field-validation/validators/__tests__/email-validation.spec.ts b/src/app/utils/field-validation/validators/__tests__/email-validation.spec.ts index 0d38454a41..ea547e8031 100644 --- a/src/app/utils/field-validation/validators/__tests__/email-validation.spec.ts +++ b/src/app/utils/field-validation/validators/__tests__/email-validation.spec.ts @@ -1052,131 +1052,4 @@ describe('Email field validation V3', () => { new ValidateFieldError('Invalid answer submitted'), ) }) - - describe('validation occurs based on if the value and signature of the current response are the same as the previous response', () => { - let authenticateSpy: jest.SpyInstance - - beforeEach(() => { - authenticateSpy = jest - .spyOn( - formsgSdk.verification as unknown as VerificationMock, - 'authenticate', - ) - .mockImplementation(() => true) - }) - - afterEach(() => { - authenticateSpy.mockClear() - }) - - it('should validate if no previous response is present', () => { - const formField = generateDefaultFieldV3(BasicField.Email, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Email, - answer: { - value: 'valid@email.com', - signature: 'some signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse: undefined, - isVisible: true, - }) - expect(validateResult.isOk()).toBe(true) - expect(validateResult._unsafeUnwrap()).toEqual(true) - expect(authenticateSpy).toHaveBeenCalled() - }) - - it('should not validate if the value and signature are the same as the previous response', () => { - const formField = generateDefaultFieldV3(BasicField.Email, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Email, - answer: { - value: 'valid@email.com', - signature: 'some signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse: { ...response }, - isVisible: true, - }) - expect(authenticateSpy).not.toHaveBeenCalled() - expect(validateResult.isOk()).toBe(true) - expect(validateResult._unsafeUnwrap()).toEqual(true) - }) - - it('should validate if the value is different from the previous response', () => { - authenticateSpy.mockImplementation(() => false) - - const formField = generateDefaultFieldV3(BasicField.Email, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Email, - answer: { - value: 'valid@email.com', - signature: 'some signature', - }, - }) - const prevResponse = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Email, - answer: { - value: 'different@email.com', - signature: 'some signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse, - isVisible: true, - }) - expect(authenticateSpy).toHaveBeenCalled() - expect(validateResult.isErr()).toBe(true) - expect(validateResult._unsafeUnwrapErr()).toEqual( - new ValidateFieldError('Invalid answer submitted'), - ) - }) - - it('should validate if the signature is different from the previous response', () => { - const formField = generateDefaultFieldV3(BasicField.Email, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Email, - answer: { - value: 'valid@email.com', - signature: 'new signature', - }, - }) - const prevResponse = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Email, - answer: { - value: 'valid@email.com', - signature: 'old signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse, - isVisible: true, - }) - expect(authenticateSpy).toHaveBeenCalled() - expect(validateResult.isOk()).toBe(true) - expect(validateResult._unsafeUnwrap()).toEqual(true) - }) - }) }) diff --git a/src/app/utils/field-validation/validators/__tests__/mobile-num-validation.spec.ts b/src/app/utils/field-validation/validators/__tests__/mobile-num-validation.spec.ts index 17aad674a0..1e86649ac5 100644 --- a/src/app/utils/field-validation/validators/__tests__/mobile-num-validation.spec.ts +++ b/src/app/utils/field-validation/validators/__tests__/mobile-num-validation.spec.ts @@ -473,131 +473,4 @@ describe('Mobile number validation tests V3', () => { ) }) }) - - describe('validation occurs based on if the value and signature of the current response are the same as the previous response', () => { - let authenticateSpy: jest.SpyInstance - - beforeEach(() => { - authenticateSpy = jest - .spyOn( - formsgSdk.verification as unknown as VerificationMock, - 'authenticate', - ) - .mockImplementation(() => true) - }) - - afterEach(() => { - authenticateSpy.mockClear() - }) - - it('should validate if no previous response is present', () => { - const formField = generateDefaultFieldV3(BasicField.Mobile, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Mobile, - answer: { - value: '+6598765432', - signature: 'some signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse: undefined, - isVisible: true, - }) - expect(validateResult.isOk()).toBe(true) - expect(validateResult._unsafeUnwrap()).toEqual(true) - expect(authenticateSpy).toHaveBeenCalled() - }) - - it('should not validate if the value and signature are the same as the previous response', () => { - const formField = generateDefaultFieldV3(BasicField.Mobile, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Mobile, - answer: { - value: '+6598765432', - signature: 'some signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse: { ...response }, - isVisible: true, - }) - expect(authenticateSpy).not.toHaveBeenCalled() - expect(validateResult.isOk()).toBe(true) - expect(validateResult._unsafeUnwrap()).toEqual(true) - }) - - it('should validate if the value is different from the previous response', () => { - authenticateSpy.mockImplementation(() => false) - - const formField = generateDefaultFieldV3(BasicField.Mobile, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Mobile, - answer: { - value: '+6598765432', - signature: 'some signature', - }, - }) - const prevResponse = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Mobile, - answer: { - value: '+6587654321', - signature: 'some signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse, - isVisible: true, - }) - expect(authenticateSpy).toHaveBeenCalled() - expect(validateResult.isErr()).toBe(true) - expect(validateResult._unsafeUnwrapErr()).toEqual( - new ValidateFieldError('Invalid answer submitted'), - ) - }) - - it('should validate if the signature is different from the previous response', () => { - const formField = generateDefaultFieldV3(BasicField.Mobile, { - isVerifiable: true, - }) - const response = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Mobile, - answer: { - value: '+6598765432', - signature: 'new signature', - }, - }) - const prevResponse = generateVerifiableAnswerResponseV3({ - fieldType: BasicField.Mobile, - answer: { - value: '+6598765432', - signature: 'old signature', - }, - }) - const validateResult = validateFieldV3({ - formId: 'formId', - formField, - response, - prevResponse, - isVisible: true, - }) - expect(authenticateSpy).toHaveBeenCalled() - expect(validateResult.isOk()).toBe(true) - expect(validateResult._unsafeUnwrap()).toEqual(true) - }) - }) }) diff --git a/src/app/utils/field-validation/validators/dateValidator.ts b/src/app/utils/field-validation/validators/dateValidator.ts index 14bf235091..55c458223f 100644 --- a/src/app/utils/field-validation/validators/dateValidator.ts +++ b/src/app/utils/field-validation/validators/dateValidator.ts @@ -191,7 +191,9 @@ const pastOnlyValidatorV3: ResponseValidator = (response) => { const answerDate = createMomentFromDateStringV3(answer) return answerDate.isAfter(todayMax) - ? left(`DateValidatorV3:\t answer does not pass date logic validation`) + ? left( + `DateValidatorV3:\t answer does not pass past only date logic validation`, + ) : right(response) } @@ -208,7 +210,9 @@ const futureOnlyValidatorV3: ResponseValidator = (response) => { const answerDate = createMomentFromDateStringV3(answer) return answerDate.isBefore(todayMin) - ? left(`DateValidatorV3:\t answer does not pass date logic validation`) + ? left( + `DateValidatorV3:\t answer does not pass future only date logic validation`, + ) : right(response) } @@ -227,7 +231,9 @@ const makeCustomDateValidatorV3: ResponseValidatorConstructor< return (customMinDate && answerDate.isBefore(customMinDate)) || (customMaxDate && answerDate.isAfter(customMaxDate)) - ? left(`DateValidatorV3:\t answer does not pass date logic validation`) + ? left( + `DateValidatorV3:\t answer does not pass custom date logic validation`, + ) : right(response) }