From 98e84ec29652d1c792437f52946a6272becb00d3 Mon Sep 17 00:00:00 2001 From: ttbarnes Date: Fri, 27 Sep 2024 10:21:48 +0100 Subject: [PATCH] feat(EMS-3877): business - turnover currency - save and back --- .../turnover-currency-page.spec.js | 3 +- .../currency-of-late-payments.spec.js | 1 - .../form-submission/index.js | 32 ++--- .../currency-form-fields/index.js | 3 - .../business/turnover-currency/index.ts | 8 +- .../save-and-back/index.test.ts | 125 ++++++++++++++++++ .../turnover-currency/save-and-back/index.ts | 53 ++++++++ .../routes/insurance/business/index.test.js | 4 +- .../server/routes/insurance/business/index.ts | 2 + src/ui/server/routes/insurance/index.test.ts | 2 +- 10 files changed, 203 insertions(+), 30 deletions(-) create mode 100644 src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.test.ts create mode 100644 src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.ts diff --git a/e2e-tests/insurance/cypress/e2e/journeys/your-business/turnover-currency/turnover-currency-page.spec.js b/e2e-tests/insurance/cypress/e2e/journeys/your-business/turnover-currency/turnover-currency-page.spec.js index 0f4cae7dfa..4e313b91f0 100644 --- a/e2e-tests/insurance/cypress/e2e/journeys/your-business/turnover-currency/turnover-currency-page.spec.js +++ b/e2e-tests/insurance/cypress/e2e/journeys/your-business/turnover-currency/turnover-currency-page.spec.js @@ -17,7 +17,7 @@ const { const baseUrl = Cypress.config('baseUrl'); context( - 'Insurance - Your business - Turnover - Alternative currency page - As an Exporter I want to enter the turnover of my business so that UKEF can have clarity on my business financial position when processing my Export Insurance Application', + 'Insurance - Your business - Turnover - Currency page - As an Exporter I want to enter the turnover of my business so that UKEF can have clarity on my business financial position when processing my Export Insurance Application', () => { let referenceNumber; let url; @@ -70,7 +70,6 @@ context( const { rendering, formSubmission } = assertCurrencyFormFields({ errors: ERRORS, expectedRedirectUrl: TURNOVER_ROOT, - hasSaveAndBack: false, }); rendering(); diff --git a/e2e-tests/insurance/cypress/e2e/journeys/your-buyer/currency-of-late-payments/currency-of-late-payments.spec.js b/e2e-tests/insurance/cypress/e2e/journeys/your-buyer/currency-of-late-payments/currency-of-late-payments.spec.js index f885275d7a..fa20351444 100644 --- a/e2e-tests/insurance/cypress/e2e/journeys/your-buyer/currency-of-late-payments/currency-of-late-payments.spec.js +++ b/e2e-tests/insurance/cypress/e2e/journeys/your-buyer/currency-of-late-payments/currency-of-late-payments.spec.js @@ -76,7 +76,6 @@ context( const { rendering, formSubmission } = assertCurrencyFormFields({ errors: ERRORS, expectedRedirectUrl: OUTSTANDING_OR_OVERDUE_PAYMENTS, - hasSaveAndBack: false, }); rendering(); diff --git a/e2e-tests/shared-test-assertions/currency-form-fields/form-submission/index.js b/e2e-tests/shared-test-assertions/currency-form-fields/form-submission/index.js index 7b3aeb14d9..f60644de83 100644 --- a/e2e-tests/shared-test-assertions/currency-form-fields/form-submission/index.js +++ b/e2e-tests/shared-test-assertions/currency-form-fields/form-submission/index.js @@ -16,7 +16,6 @@ const { ALL_SECTIONS } = INSURANCE_ROUTES; * @param {Function} submitAlternativeCurrencyAndAssertUrl: Submit an alternative currency and assert the URL. * @param {Function} submitAlternativeCurrencyAndAssertInput: Submit an alternative currency and assert the input. * @param {Function} completeNonCurrencyFieldsFunction: Optional function to complete non-currency form fields. - * @param {Boolean} hasSaveAndBack: Temporary Flag for if the form has "save and back" functionality * @returns {Object} Object with Mocha describe blocks and assertions for particular scenarios. */ const formSubmissionAssertions = ({ @@ -28,7 +27,6 @@ const formSubmissionAssertions = ({ submitAlternativeCurrencyAndAssertUrl, submitAlternativeCurrencyAndAssertInput, completeNonCurrencyFieldsFunction, - hasSaveAndBack, }) => { const executeTests = () => { describe('currency form fields - form submission', () => { @@ -49,24 +47,22 @@ const formSubmissionAssertions = ({ }); }); - if (hasSaveAndBack) { - describe('via `save and back` button', () => { - submitASupportedCurrency({ - completeNonCurrencyFieldsFunction, - submitRadioAndAssertUrl, - submitAndAssertRadioIsChecked, - expectedRedirectUrl: ALL_SECTIONS, - viaSaveAndBack: true, - }); + describe('via `save and back` button', () => { + submitASupportedCurrency({ + completeNonCurrencyFieldsFunction, + submitRadioAndAssertUrl, + submitAndAssertRadioIsChecked, + expectedRedirectUrl: ALL_SECTIONS, + viaSaveAndBack: true, + }); - submitAlternativeCurrency({ - expectedRedirectUrl: ALL_SECTIONS, - submitAlternativeCurrencyAndAssertUrl, - submitAlternativeCurrencyAndAssertInput, - viaSaveAndBack: true, - }); + submitAlternativeCurrency({ + expectedRedirectUrl: ALL_SECTIONS, + submitAlternativeCurrencyAndAssertUrl, + submitAlternativeCurrencyAndAssertInput, + viaSaveAndBack: true, }); - } + }); }); }; diff --git a/e2e-tests/shared-test-assertions/currency-form-fields/index.js b/e2e-tests/shared-test-assertions/currency-form-fields/index.js index fcf6ff544d..0392b7c03a 100644 --- a/e2e-tests/shared-test-assertions/currency-form-fields/index.js +++ b/e2e-tests/shared-test-assertions/currency-form-fields/index.js @@ -21,7 +21,6 @@ const { * @param {Function} hint: Hint selector * @param {Function} legend: Legend selector * @param {String} expectedRedirectUrl: Page URL to assert after successful form submission - * @param {Boolean} hasSaveAndBack: Temporary Flag for if the form has "save and back" functionality * @returns {Object} Rendering and form submission assertion functions */ export const assertCurrencyFormFields = ({ @@ -34,7 +33,6 @@ export const assertCurrencyFormFields = ({ hint, legend, expectedRedirectUrl, - hasSaveAndBack, }) => { const assertions = fieldAssertions({ alternativeCurrencyText: FIELDS[ALTERNATIVE_CURRENCY_CODE].TEXT, @@ -52,7 +50,6 @@ export const assertCurrencyFormFields = ({ completeNonCurrencyFieldsFunction, errorIndex, expectedRedirectUrl, - hasSaveAndBack, }), prefixAssertions: () => prefixAssertions({ fieldId, clickAlternativeCurrencyLink }), }; diff --git a/src/ui/server/controllers/insurance/business/turnover-currency/index.ts b/src/ui/server/controllers/insurance/business/turnover-currency/index.ts index cc8f5979f1..ea83fe096e 100644 --- a/src/ui/server/controllers/insurance/business/turnover-currency/index.ts +++ b/src/ui/server/controllers/insurance/business/turnover-currency/index.ts @@ -48,10 +48,10 @@ export const PAGE_VARIABLES = { }; /** - * gets the template for Business - Turnover - Alternative currency page + * gets the template for Business - Turnover - Currency page * @param {Express.Request} Express request * @param {Express.Response} Express response - * @returns {Express.Response.render} renders Business - Turnover - Alternative currency page with/without previously submitted details + * @returns {Express.Response.render} renders Business - Turnover - Currency page with/without previously submitted details */ export const get = async (req: Request, res: Response) => { try { @@ -85,7 +85,7 @@ export const get = async (req: Request, res: Response) => { /** * post - * Check Business - Turnover - Alternative currency page validation errors and if successful, redirect to the next part of the flow. + * Check Business - Turnover - Currency page validation errors and if successful, redirect to the next part of the flow. * @param {Express.Request} Express request * @param {Express.Response} Express response * @returns {Express.Response.redirect} Next part of the flow or error page @@ -151,7 +151,7 @@ export const post = async (req: Request, res: Response) => { return res.redirect(`${INSURANCE_ROOT}/${referenceNumber}${TURNOVER_ROOT}`); } catch (error) { - console.error('Error posting Business - Turnover currency %O', error); + console.error('Error posting business - turnover currency %O', error); return res.redirect(PROBLEM_WITH_SERVICE); } diff --git a/src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.test.ts b/src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.test.ts new file mode 100644 index 0000000000..5adb95c4ea --- /dev/null +++ b/src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.test.ts @@ -0,0 +1,125 @@ +import { FIELD_IDS } from '..'; +import { post } from '.'; +import { INSURANCE_ROUTES } from '../../../../../constants/routes/insurance'; +import INSURANCE_FIELD_IDS from '../../../../../constants/field-ids/insurance'; +import constructPayload from '../../../../../helpers/construct-payload'; +import generateValidationErrors from '../validation'; +import mapAndSave from '../../map-and-save/turnover'; +import { Request, Response } from '../../../../../../types'; +import { EUR, mockReq, mockRes, mockSpyPromiseRejection, referenceNumber } from '../../../../../test-mocks'; + +const { + CURRENCY: { CURRENCY_CODE }, +} = INSURANCE_FIELD_IDS; + +const { INSURANCE_ROOT, ALL_SECTIONS, PROBLEM_WITH_SERVICE } = INSURANCE_ROUTES; + +describe('controllers/insurance/business/turnover-currency/save-and-back', () => { + let req: Request; + let res: Response; + + jest.mock('../../map-and-save/turnover'); + + let mapAndSaveSpy = jest.fn(() => Promise.resolve(true)); + + const mockFormBody = { + [CURRENCY_CODE]: EUR.isoCode, + }; + + beforeEach(() => { + req = mockReq(); + res = mockRes(); + + req.body = mockFormBody; + + mapAndSave.turnover = mapAndSaveSpy; + }); + + afterAll(() => { + jest.resetAllMocks(); + }); + + describe('when the form has data', () => { + beforeEach(() => { + jest.resetAllMocks(); + + mapAndSaveSpy = jest.fn(() => Promise.resolve(true)); + mapAndSave.turnover = mapAndSaveSpy; + }); + + it('should call mapAndSave.turnover with data from constructPayload function, application and validationErrors', async () => { + await post(req, res); + + const payload = constructPayload(req.body, FIELD_IDS); + + const validationErrors = generateValidationErrors(payload); + + expect(mapAndSave.turnover).toHaveBeenCalledTimes(1); + expect(mapAndSave.turnover).toHaveBeenCalledWith(payload, res.locals.application, validationErrors); + }); + + it(`should redirect to ${ALL_SECTIONS}`, async () => { + mapAndSave.turnover = mapAndSaveSpy; + + await post(req, res); + + const expected = `${INSURANCE_ROOT}/${referenceNumber}${ALL_SECTIONS}`; + + expect(res.redirect).toHaveBeenCalledWith(expected); + }); + }); + + describe('when the form does not have any data', () => { + it(`should redirect to ${ALL_SECTIONS}`, async () => { + req.body = { _csrf: '1234' }; + + await post(req, res); + + const expected = `${INSURANCE_ROOT}/${referenceNumber}${ALL_SECTIONS}`; + + expect(res.redirect).toHaveBeenCalledWith(expected); + }); + }); + + describe('when there is no application', () => { + beforeEach(() => { + delete res.locals.application; + }); + + it(`should redirect to ${PROBLEM_WITH_SERVICE}`, async () => { + await post(req, res); + + expect(res.redirect).toHaveBeenCalledWith(PROBLEM_WITH_SERVICE); + }); + }); + + describe('api error handling', () => { + describe('when mapAndSave.turnover returns false', () => { + beforeEach(() => { + res.locals = mockRes().locals; + mapAndSaveSpy = jest.fn(() => Promise.resolve(false)); + mapAndSave.turnover = mapAndSaveSpy; + }); + + it(`should redirect to ${PROBLEM_WITH_SERVICE}`, async () => { + await post(req, res); + + expect(res.redirect).toHaveBeenCalledWith(PROBLEM_WITH_SERVICE); + }); + }); + + describe('when mapAndSave.turnover fails', () => { + beforeEach(() => { + res.locals = mockRes().locals; + mapAndSaveSpy = mockSpyPromiseRejection; + mapAndSave.turnover = mapAndSaveSpy; + }); + + it(`should redirect to ${PROBLEM_WITH_SERVICE}`, async () => { + await post(req, res); + + expect(res.redirect).toHaveBeenCalledWith(PROBLEM_WITH_SERVICE); + }); + }); + }); +}); diff --git a/src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.ts b/src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.ts new file mode 100644 index 0000000000..6cebab86ff --- /dev/null +++ b/src/ui/server/controllers/insurance/business/turnover-currency/save-and-back/index.ts @@ -0,0 +1,53 @@ +import { INSURANCE_ROUTES } from '../../../../../constants/routes/insurance'; +import hasFormData from '../../../../../helpers/has-form-data'; +import { FIELD_IDS } from '..'; +import constructPayload from '../../../../../helpers/construct-payload'; +import generateValidationErrors from '../validation'; +import mapAndSave from '../../map-and-save/turnover'; +import { Request, Response } from '../../../../../../types'; + +const { INSURANCE_ROOT, ALL_SECTIONS, PROBLEM_WITH_SERVICE } = INSURANCE_ROUTES; + +/** + * post + * Save any valid currency of Business - Turnover - Currency form fields and if successful, redirect to the all sections page + * @param {Express.Request} Express request + * @param {Express.Response} Express response + * @returns {Express.Response.redirect} All sections page or error page + */ +export const post = async (req: Request, res: Response) => { + try { + const { application } = res.locals; + + if (!application) { + return res.redirect(PROBLEM_WITH_SERVICE); + } + + const { referenceNumber } = req.params; + + /** + * If form data is populated: + * 1) generate a payload. + * 2) generate validation errors. + * 3) call mapAndSave + * 4) redirect + */ + if (hasFormData(req.body)) { + const payload = constructPayload(req.body, FIELD_IDS); + + const validationErrors = generateValidationErrors(payload); + + const saveResponse = await mapAndSave.turnover(payload, application, validationErrors); + + if (!saveResponse) { + return res.redirect(PROBLEM_WITH_SERVICE); + } + } + + return res.redirect(`${INSURANCE_ROOT}/${referenceNumber}${ALL_SECTIONS}`); + } catch (error) { + console.error('Error updating application - business - turnover currency (save and back) %O', error); + + return res.redirect(PROBLEM_WITH_SERVICE); + } +}; diff --git a/src/ui/server/routes/insurance/business/index.test.js b/src/ui/server/routes/insurance/business/index.test.js index e9ca68177c..e6bb125796 100644 --- a/src/ui/server/routes/insurance/business/index.test.js +++ b/src/ui/server/routes/insurance/business/index.test.js @@ -23,6 +23,7 @@ import { get as getTurnover, post as postTurnover } from '../../../controllers/i import { post as postTurnoverSaveAndBack } from '../../../controllers/insurance/business/turnover/save-and-back'; import { get as getTurnoverCurrency, post as postTurnoverCurrency } from '../../../controllers/insurance/business/turnover-currency'; +import { post as postTurnoverCurrencySaveAndBack } from '../../../controllers/insurance/business/turnover-currency/save-and-back'; import { get as getCreditControl, post as postCreditControl } from '../../../controllers/insurance/business/credit-control'; import { post as postCreditControlSaveAndBack } from '../../../controllers/insurance/business/credit-control/save-and-back'; @@ -40,7 +41,7 @@ describe('routes/insurance/your-business', () => { it('should setup all routes', () => { expect(get).toHaveBeenCalledTimes(28); - expect(post).toHaveBeenCalledTimes(32); + expect(post).toHaveBeenCalledTimes(33); expect(get).toHaveBeenCalledWith(ROUTES.INSURANCE.EXPORTER_BUSINESS.ROOT, getYourBusiness); @@ -84,6 +85,7 @@ describe('routes/insurance/your-business', () => { expect(get).toHaveBeenCalledWith(ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_ROOT, getTurnoverCurrency); expect(post).toHaveBeenCalledWith(ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_ROOT, postTurnoverCurrency); + expect(post).toHaveBeenCalledWith(ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_SAVE_AND_BACK, postTurnoverCurrencySaveAndBack); expect(get).toHaveBeenCalledWith(ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_CHANGE, getTurnoverCurrency); expect(post).toHaveBeenCalledWith(ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_CHANGE, postTurnoverCurrency); expect(get).toHaveBeenCalledWith(ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_CHECK_AND_CHANGE, getTurnoverCurrency); diff --git a/src/ui/server/routes/insurance/business/index.ts b/src/ui/server/routes/insurance/business/index.ts index cda433cb8c..ec9c6d9c0a 100644 --- a/src/ui/server/routes/insurance/business/index.ts +++ b/src/ui/server/routes/insurance/business/index.ts @@ -22,6 +22,7 @@ import { get as getTurnover, post as postTurnover } from '../../../controllers/i import { post as postTurnoverSaveAndBack } from '../../../controllers/insurance/business/turnover/save-and-back'; import { get as getTurnoverCurrency, post as postTurnoverCurrency } from '../../../controllers/insurance/business/turnover-currency'; +import { post as postTurnoverCurrencySaveAndBack } from '../../../controllers/insurance/business/turnover-currency/save-and-back'; import { get as getCreditControl, post as postCreditControl } from '../../../controllers/insurance/business/credit-control'; import { post as postCreditControlSaveAndBack } from '../../../controllers/insurance/business/credit-control/save-and-back'; @@ -79,6 +80,7 @@ insuranceBusinessRouter.post(`/:referenceNumber${ROUTES.INSURANCE.EXPORTER_BUSIN insuranceBusinessRouter.get(`/:referenceNumber${ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_ROOT}`, getTurnoverCurrency); insuranceBusinessRouter.post(`/:referenceNumber${ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_ROOT}`, postTurnoverCurrency); +insuranceBusinessRouter.post(`/:referenceNumber${ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_SAVE_AND_BACK}`, postTurnoverCurrencySaveAndBack); insuranceBusinessRouter.get(`/:referenceNumber${ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_CHANGE}`, getTurnoverCurrency); insuranceBusinessRouter.post(`/:referenceNumber${ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_CHANGE}`, postTurnoverCurrency); insuranceBusinessRouter.get(`/:referenceNumber${ROUTES.INSURANCE.EXPORTER_BUSINESS.TURNOVER_CURRENCY_CHECK_AND_CHANGE}`, getTurnoverCurrency); diff --git a/src/ui/server/routes/insurance/index.test.ts b/src/ui/server/routes/insurance/index.test.ts index b8067b1aeb..db75b1a19d 100644 --- a/src/ui/server/routes/insurance/index.test.ts +++ b/src/ui/server/routes/insurance/index.test.ts @@ -22,7 +22,7 @@ describe('routes/insurance', () => { it('should setup all routes', () => { expect(get).toHaveBeenCalledTimes(216); - expect(post).toHaveBeenCalledTimes(224); + expect(post).toHaveBeenCalledTimes(225); expect(get).toHaveBeenCalledWith(INSURANCE_ROUTES.START, startGet);