Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ROE-2313 Trim leading zeros from date fields #995

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
37 changes: 36 additions & 1 deletion src/validation/fields/date.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ import { conditionalDateValidations, dateContext, dateContextWithCondition, date

// to prevent more than 1 error reported on the date fields we check if the year is valid before doing some checks.
// This means that the year check is checked before some others
// Need to trim leading zeros before custom validations as these reference day month year fields.
export const start_date_validations = [
body("start_date-day")
.ltrim("0"),
mwestacott marked this conversation as resolved.
Show resolved Hide resolved
body("start_date-month")
.ltrim("0"),
mwestacott marked this conversation as resolved.
Show resolved Hide resolved
body("start_date-year")
.ltrim("0"),
body("start_date-day")
.custom((value, { req }) => checkDateFieldDay(req.body["start_date-day"], req.body["start_date-month"], req.body["start_date-year"])),
body("start_date-month")
Expand All @@ -35,7 +42,14 @@ export const start_date_validations = [
.custom((value, { req }) => checkDate(req.body["start_date-day"], req.body["start_date-month"], req.body["start_date-year"])),
];

// Need to trim leading zeros before custom validations as these reference day month year fields.
const is_still_active_validations = (date_field_id: string, radio_button_id: string, error_message: string) => [
body(date_field_id + "-day")
.ltrim("0"),
body(date_field_id + "-month")
.ltrim("0"),
body(date_field_id + "-year")
.ltrim("0"),
body(date_field_id + "-day")
.if(body(radio_button_id).equals('0'))
.custom((value, { req }) => checkDateFieldDay(req.body[date_field_id + "-day"], req.body[date_field_id + "-month"], req.body[date_field_id + "-year"])),
Expand All @@ -60,8 +74,15 @@ export const ceased_date_validations = is_still_active_validations("ceased_date"
export const resigned_on_validations = is_still_active_validations("resigned_on", "is_still_mo", ErrorMessages.RESIGNED_ON_BEFORE_START_DATE);

// to prevent more than 1 error reported on the date fields we check if the year is valid before doing some checks.
// This means that the year check is checked before some others
// This means that the year check is checked before some others.
// Need to trim leading zeros before custom validations as these reference day month year fields.
export const date_of_birth_validations = [
body("date_of_birth-day")
.ltrim("0"),
body("date_of_birth-month")
.ltrim("0"),
body("date_of_birth-year")
.ltrim("0"),
body("date_of_birth-day")
.custom((value, { req }) => checkDateFieldDayOfBirth(req.body["date_of_birth-day"], req.body["date_of_birth-month"], req.body["date_of_birth-year"])),
body("date_of_birth-month")
Expand All @@ -74,7 +95,14 @@ export const date_of_birth_validations = [

// to prevent more than 1 error reported on the date fields we check if the year is valid before doing some checks.
// This means that the year check is checked before some others
// Need to trim leading zeros before custom validations as these reference day month year fields.
export const identity_check_date_validations = [
body("identity_date-day")
.ltrim("0"),
body("identity_date-month")
.ltrim("0"),
body("identity_date-year")
.ltrim("0"),
body("identity_date-day")
.custom((value, { req }) => checkDateFieldDay(req.body["identity_date-day"], req.body["identity_date-month"], req.body["identity_date-year"])),
body("identity_date-month")
Expand All @@ -85,7 +113,14 @@ export const identity_check_date_validations = [
.custom((value, { req }) => checkIdentityDate(req.body["identity_date-day"], req.body["identity_date-month"], req.body["identity_date-year"])),
];

// Need to trim leading zeros before custom validations as these reference day month year fields.
export const filing_date_validations = [
body("filing_date-day")
.ltrim("0"),
body("filing_date-month")
.ltrim("0"),
body("filing_date-year")
.ltrim("0"),
body("filing_date-day")
.custom((value, { req }) => checkDateFieldDay(req.body["filing_date-day"], req.body["filing_date-month"], req.body["filing_date-year"])),
body("filing_date-month")
Expand Down
14 changes: 14 additions & 0 deletions src/validation/fields/helper/date.validation.helper.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { body } from "express-validator";
import { DayFieldErrors, MonthFieldErrors, YearFieldErrors, checkDayFieldForErrors, checkMonthFieldForErrors, checkYearFieldForErrors } from "../../custom.validation";

// Need to trim leading zeros before custom validations as these reference day month year fields.
export const dateValidations = (dateContext: dateContext) => {
return [
body(dateContext.dayInput.name)
.ltrim("0"),
body(dateContext.monthInput.name)
.ltrim("0"),
body(dateContext.yearInput.name)
.ltrim("0"),
body(dateContext.dayInput.name)
.if(body(dateContext.monthInput.name).notEmpty({ ignore_whitespace: true }))
.if(body(dateContext.yearInput.name).notEmpty({ ignore_whitespace: true }))
Expand All @@ -20,8 +27,15 @@ export const dateValidations = (dateContext: dateContext) => {
];
};

// Need to trim leading zeros before custom validations as these reference day month year fields.
export const conditionalDateValidations = (dateContextWithCondition: dateContextWithCondition) => {
return [
body(dateContextWithCondition.dayInput.name)
.ltrim("0"),
body(dateContextWithCondition.monthInput.name)
.ltrim("0"),
body(dateContextWithCondition.yearInput.name)
.ltrim("0"),
body(dateContextWithCondition.dayInput.name)
.if(body(dateContextWithCondition.condition.elementName).equals(dateContextWithCondition.condition.expectedValue))
.if(body(dateContextWithCondition.monthInput.name).notEmpty({ ignore_whitespace: true }))
Expand Down
12 changes: 9 additions & 3 deletions src/validation/overseas.entity.due.diligence.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ import {
} from "./custom.validation";
import { email_validations } from "./fields/email.validation";

// to prevent more than 1 error reported on the date fields we check if the year is valid before doing some checks.
// This means that the year check is checked before some others.
// Need to trim leading zeros before custom validations as these reference day month year fields.
export const overseasEntityDueDiligence = [

// to prevent more than 1 error reported on the date fields we check if the year is valid before doing some checks.
// This means that the year check is checked before some others
body("identity_date-day")
.ltrim("0"),
body("identity_date-month")
.ltrim("0"),
body("identity_date-year")
.ltrim("0"),
body("identity_date-day")
.custom((value, { req }) => checkDateFieldDayForOptionalDates(req.body["identity_date-day"], req.body["identity_date-month"], req.body["identity_date-year"])),
body("identity_date-month")
Expand Down
91 changes: 83 additions & 8 deletions test/controllers/beneficial.owner.gov.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,9 @@ describe("BENEFICIAL OWNER GOV controller", () => {
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only INVALID_DATE error when day is zero`, async () => {
test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only missing DAY error when day is zero`, async () => {
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
beneficialOwnerGov["start_date-day"] = "0";
beneficialOwnerGov["start_date-day"] = "00";
beneficialOwnerGov["start_date-month"] = "12";
beneficialOwnerGov["start_date-year"] = "2020";
const resp = await request(app)
Expand All @@ -440,18 +440,18 @@ describe("BENEFICIAL OWNER GOV controller", () => {
expect(resp.status).toEqual(200);
expect(resp.text).toContain(BENEFICIAL_OWNER_GOV_PAGE_HEADING);
expect(resp.text).not.toContain(ErrorMessages.ENTER_DATE);
expect(resp.text).not.toContain(ErrorMessages.DAY);
expect(resp.text).toContain(ErrorMessages.DAY);
expect(resp.text).not.toContain(ErrorMessages.MONTH);
expect(resp.text).not.toContain(ErrorMessages.YEAR);
expect(resp.text).toContain(ErrorMessages.INVALID_DATE);
expect(resp.text).not.toContain(ErrorMessages.INVALID_DATE);
expect(resp.text).not.toContain(ErrorMessages.DATE_NOT_IN_PAST_OR_TODAY);
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only INVALID_DATE error when month is zero`, async () => {
test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only missing MONTH error when month is zero`, async () => {
mwestacott marked this conversation as resolved.
Show resolved Hide resolved
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
beneficialOwnerGov["start_date-day"] = "30";
beneficialOwnerGov["start_date-month"] = "0";
beneficialOwnerGov["start_date-month"] = "00";
beneficialOwnerGov["start_date-year"] = "2020";
const resp = await request(app)
.post(config.BENEFICIAL_OWNER_GOV_URL)
Expand All @@ -460,13 +460,49 @@ describe("BENEFICIAL OWNER GOV controller", () => {
expect(resp.text).toContain(BENEFICIAL_OWNER_GOV_PAGE_HEADING);
expect(resp.text).not.toContain(ErrorMessages.ENTER_DATE);
expect(resp.text).not.toContain(ErrorMessages.DAY);
expect(resp.text).not.toContain(ErrorMessages.MONTH);
expect(resp.text).toContain(ErrorMessages.MONTH);
expect(resp.text).not.toContain(ErrorMessages.YEAR);
expect(resp.text).toContain(ErrorMessages.INVALID_DATE);
expect(resp.text).not.toContain(ErrorMessages.INVALID_DATE);
expect(resp.text).not.toContain(ErrorMessages.DATE_NOT_IN_PAST_OR_TODAY);
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only missing YEAR error when year is zero`, async () => {
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
beneficialOwnerGov["start_date-day"] = "30";
beneficialOwnerGov["start_date-month"] = "11";
beneficialOwnerGov["start_date-year"] = "00";
const resp = await request(app)
.post(config.BENEFICIAL_OWNER_GOV_URL)
.send(beneficialOwnerGov);
expect(resp.status).toEqual(200);
expect(resp.text).toContain(BENEFICIAL_OWNER_GOV_PAGE_HEADING);
expect(resp.text).not.toContain(ErrorMessages.ENTER_DATE);
expect(resp.text).not.toContain(ErrorMessages.DAY);
expect(resp.text).not.toContain(ErrorMessages.MONTH);
expect(resp.text).toContain(ErrorMessages.YEAR);
expect(resp.text).not.toContain(ErrorMessages.INVALID_DATE);
expect(resp.text).not.toContain(ErrorMessages.DATE_NOT_IN_PAST_OR_TODAY);
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`leading zeros are stripped from start date`, async () => {
mockPrepareData.mockReturnValueOnce(BENEFICIAL_OWNER_GOV_OBJECT_MOCK);
const beneficialOwnerGov = { ...BENEFICIAL_OWNER_GOV_BODY_OBJECT_MOCK_WITH_ADDRESS };
beneficialOwnerGov["start_date-day"] = "0030";
mwestacott marked this conversation as resolved.
Show resolved Hide resolved
beneficialOwnerGov["start_date-month"] = "0011";
beneficialOwnerGov["start_date-year"] = "001234";
const resp = await request(app)
.post(config.BENEFICIAL_OWNER_GOV_URL)
.send(beneficialOwnerGov);
expect(resp.status).toEqual(302);

const reqBody = mockPrepareData.mock.calls[0][0];
expect(reqBody["start_date-day"]).toEqual("30");
expect(reqBody["start_date-month"]).toEqual("11");
expect(reqBody["start_date-year"]).toEqual("1234");
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only YEAR_LENGTH error when invalid characters are used`, async () => {
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
beneficialOwnerGov["start_date-day"] = "a";
Expand Down Expand Up @@ -505,6 +541,25 @@ describe("BENEFICIAL OWNER GOV controller", () => {
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only INVALID_DATE error when invalid date is used with leading zeroes`, async () => {
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
beneficialOwnerGov["start_date-day"] = "0033";
beneficialOwnerGov["start_date-month"] = "0033";
beneficialOwnerGov["start_date-year"] = "2022";
const resp = await request(app)
.post(config.BENEFICIAL_OWNER_GOV_URL)
.send(beneficialOwnerGov);
expect(resp.status).toEqual(200);
expect(resp.text).toContain(BENEFICIAL_OWNER_GOV_PAGE_HEADING);
expect(resp.text).not.toContain(ErrorMessages.ENTER_DATE);
expect(resp.text).not.toContain(ErrorMessages.DAY);
expect(resp.text).not.toContain(ErrorMessages.MONTH);
expect(resp.text).not.toContain(ErrorMessages.YEAR);
expect(resp.text).toContain(ErrorMessages.INVALID_DATE);
expect(resp.text).not.toContain(ErrorMessages.DATE_NOT_IN_PAST_OR_TODAY);
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only YEAR_LENGTH error when year length is not 4 digits`, async () => {
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
beneficialOwnerGov["start_date-day"] = "10";
Expand All @@ -525,6 +580,26 @@ describe("BENEFICIAL OWNER GOV controller", () => {
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only YEAR_LENGTH error when year length is not 4 digits with leading zero`, async () => {
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
beneficialOwnerGov["start_date-day"] = "10";
beneficialOwnerGov["start_date-month"] = "12";
beneficialOwnerGov["start_date-year"] = "0020";
const resp = await request(app)
.post(config.BENEFICIAL_OWNER_GOV_URL)
.send(beneficialOwnerGov);
expect(resp.status).toEqual(200);
expect(resp.text).toContain(BENEFICIAL_OWNER_GOV_PAGE_HEADING);
expect(resp.text).toContain(ErrorMessages.YEAR_LENGTH);
expect(resp.text).not.toContain(ErrorMessages.ENTER_DATE);
expect(resp.text).not.toContain(ErrorMessages.DAY);
expect(resp.text).not.toContain(ErrorMessages.MONTH);
expect(resp.text).not.toContain(ErrorMessages.YEAR);
expect(resp.text).not.toContain(ErrorMessages.INVALID_DATE);
expect(resp.text).not.toContain(ErrorMessages.DATE_NOT_IN_PAST_OR_TODAY);
expect(mockSaveAndContinue).not.toHaveBeenCalled();
});

test(`renders the current page ${config.BENEFICIAL_OWNER_GOV_PAGE} with only DATE_NOT_IN_PAST_OR_TODAY error when start date is not in the past`, async () => {
const beneficialOwnerGov = { ...REQ_BODY_BENEFICIAL_OWNER_GOV_FOR_START_DATE_VALIDATION };
const inTheFuture = DateTime.now().plus({ days: 1 });
Expand Down
Loading