-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add country field backend (#3770)
* feat: add country field backend * fix: Fix Property 'country' is missing * fix: replace BasicField.Dropdown in CountryField story * fix: import CountryField into FieldFactory * fix: fix type errors due to lack of handling for new country field Co-authored-by: Kar Rui <[email protected]>
- Loading branch information
Showing
23 changed files
with
222 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { CountryField as default } from './CountryField' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { BasicField, MyInfoableFieldBase } from './base' | ||
import { Country } from '../../constants/countries' | ||
|
||
export interface CountryFieldBase extends MyInfoableFieldBase { | ||
fieldType: BasicField.Country | ||
fieldOptions: Country[] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Schema } from 'mongoose' | ||
|
||
import { ICountryFieldSchema } from '../../../types' | ||
|
||
const createCountryFieldSchema = () => { | ||
return new Schema<ICountryFieldSchema>({}) | ||
} | ||
|
||
export default createCountryFieldSchema |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
src/app/utils/field-validation/validators/__tests__/country-validation.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { ValidateFieldError } from 'src/app/modules/submission/submission.errors' | ||
import { validateField } from 'src/app/utils/field-validation' | ||
|
||
import { | ||
generateDefaultField, | ||
generateNewSingleAnswerResponse, | ||
} from 'tests/unit/backend/helpers/generate-form-data' | ||
|
||
import { Country } from '../../../../../../shared/constants/countries' | ||
import { BasicField } from '../../../../../../shared/types' | ||
|
||
describe('Country validation', () => { | ||
it('should allow valid option', () => { | ||
const formField = generateDefaultField(BasicField.Country, {}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Country, { | ||
answer: Country.Singapore, | ||
}) | ||
|
||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isOk()).toBe(true) | ||
expect(validateResult._unsafeUnwrap()).toEqual(true) | ||
}) | ||
|
||
it('should disallow invalid option', () => { | ||
const formField = generateDefaultField(BasicField.Dropdown, {}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Dropdown, { | ||
answer: 'NOT A COUNTRY', | ||
}) | ||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isErr()).toBe(true) | ||
expect(validateResult._unsafeUnwrapErr()).toEqual( | ||
new ValidateFieldError('Invalid answer submitted'), | ||
) | ||
}) | ||
|
||
it('should disallow empty answer when required', () => { | ||
const formField = generateDefaultField(BasicField.Country, {}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Country, { | ||
answer: '', | ||
}) | ||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isErr()).toBe(true) | ||
expect(validateResult._unsafeUnwrapErr()).toEqual( | ||
new ValidateFieldError('Invalid answer submitted'), | ||
) | ||
}) | ||
|
||
it('should allow empty answer when not required', () => { | ||
const formField = generateDefaultField(BasicField.Country, { | ||
required: false, | ||
}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Country, { | ||
answer: '', | ||
}) | ||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isOk()).toBe(true) | ||
expect(validateResult._unsafeUnwrap()).toEqual(true) | ||
}) | ||
|
||
it('should allow empty answer when it is required but not visible', () => { | ||
const formField = generateDefaultField(BasicField.Country, {}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Country, { | ||
answer: '', | ||
isVisible: false, | ||
}) | ||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isOk()).toBe(true) | ||
expect(validateResult._unsafeUnwrap()).toEqual(true) | ||
}) | ||
|
||
it('should disallow empty answer when it is required and visible', () => { | ||
const formField = generateDefaultField(BasicField.Country, {}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Country, { | ||
answer: '', | ||
}) | ||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isErr()).toBe(true) | ||
expect(validateResult._unsafeUnwrapErr()).toEqual( | ||
new ValidateFieldError('Invalid answer submitted'), | ||
) | ||
}) | ||
|
||
it('should disallow multiple answers', () => { | ||
const formField = generateDefaultField(BasicField.Country, {}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Country, { | ||
answer: [Country.Singapore, Country.Slovak_Republic] as unknown as string, | ||
}) | ||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isErr()).toBe(true) | ||
expect(validateResult._unsafeUnwrapErr()).toEqual( | ||
new ValidateFieldError('Response has invalid shape'), | ||
) | ||
}) | ||
it('should disallow responses submitted for hidden fields', () => { | ||
const formField = generateDefaultField(BasicField.Country, {}) | ||
const response = generateNewSingleAnswerResponse(BasicField.Country, { | ||
answer: Country.Singapore, | ||
isVisible: false, | ||
}) | ||
const validateResult = validateField('formId', formField, response) | ||
expect(validateResult.isErr()).toBe(true) | ||
expect(validateResult._unsafeUnwrapErr()).toEqual( | ||
new ValidateFieldError('Attempted to submit response on a hidden field'), | ||
) | ||
}) | ||
}) |
30 changes: 30 additions & 0 deletions
30
src/app/utils/field-validation/validators/countryValidator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { chain, left, right } from 'fp-ts/lib/Either' | ||
import { flow } from 'fp-ts/lib/function' | ||
|
||
import { Country } from '../../../../../shared/constants/countries' | ||
import { ResponseValidator } from '../../../../types/field/utils/validation' | ||
import { ProcessedSingleAnswerResponse } from '../../../modules/submission/submission.types' | ||
|
||
import { notEmptySingleAnswerResponse } from './common' | ||
import { isOneOfOptions } from './options' | ||
|
||
type CountryValidator = ResponseValidator<ProcessedSingleAnswerResponse> | ||
type CountryValidatorConstructor = () => CountryValidator | ||
|
||
/** | ||
* Returns a validation function | ||
* to check if country selection is one of the options. | ||
*/ | ||
const makeCountryValidator: CountryValidatorConstructor = () => (response) => { | ||
const validOptions = Object.values(Country) | ||
const { answer } = response | ||
return isOneOfOptions(validOptions, answer) | ||
? right(response) | ||
: left(`CountryValidator:\t answer is not a valid country option`) | ||
} | ||
|
||
/** | ||
* Returns a validation function for a country field when called. | ||
*/ | ||
export const constructCountryValidator: CountryValidatorConstructor = () => | ||
flow(notEmptySingleAnswerResponse, chain(makeCountryValidator())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { BasicField, CountryFieldBase } from '../../../shared/types' | ||
|
||
import { IFieldSchema } from './baseField' | ||
|
||
export interface ICountryFieldSchema extends CountryFieldBase, IFieldSchema { | ||
fieldType: BasicField.Country | ||
} |
Oops, something went wrong.