diff --git a/src/server/common/constants/status-codes.js b/src/server/common/constants/status-codes.js index c6094c76..6e311489 100644 --- a/src/server/common/constants/status-codes.js +++ b/src/server/common/constants/status-codes.js @@ -8,5 +8,6 @@ export const statusCodes = { unauthorized: 401, forbidden: 403, notFound: 404, - imATeapot: 418 + imATeapot: 418, + redirect: 302 } diff --git a/src/server/cph-number/controller.js b/src/server/cph-number/controller.js index 22b7ab7b..8215e549 100644 --- a/src/server/cph-number/controller.js +++ b/src/server/cph-number/controller.js @@ -1,3 +1,5 @@ +import validator from './validator.js' + export const pageTitle = 'What is the County Parish Holding (CPH) number of your farm or premises where the animals are moving off?' const indexView = 'cph-number/index' @@ -27,41 +29,32 @@ export const getController = { */ export const postController = { handler(req, res) { - const valid = /([0-9]{2})\/([0-9]{3})\/([0-9]{4})/g - let errorMessage = null const { cphNumber } = /** @type {CphNumberPayload} */ (req.payload) + // Remove whitespace from cphNumber + const input = cphNumber ? cphNumber.replace(/\s+/g, '') : cphNumber + const [isValid, message] = validator(input) - if (!cphNumber) { - errorMessage = { - text: 'Enter the farm or premises CPH number' - } - } - - if (cphNumber && (!valid.test(cphNumber) || cphNumber.length !== 11)) { - errorMessage = { - text: 'Enter the CPH number in the correct format, for example, 12/345/6789' - } - } - - if (errorMessage) { + if (!isValid) { req.yar.clear('cphNumber') return res.view(indexView, { pageTitle: `Error: ${pageTitle}`, heading: pageTitle, cphNumber: { - value: cphNumber + value: input }, - errorMessage + errorMessage: { + text: message + } }) } - req.yar.set('cphNumber', cphNumber) + req.yar.set('cphNumber', input) return res.view(indexView, { pageTitle, heading: pageTitle, cphNumber: { - value: cphNumber + value: input } }) } diff --git a/src/server/cph-number/validator.js b/src/server/cph-number/validator.js new file mode 100644 index 00000000..b2a2eac5 --- /dev/null +++ b/src/server/cph-number/validator.js @@ -0,0 +1,20 @@ +/** + * @returns [ boolean | string | null ] + */ +export default (input) => { + const valid = /([0-9]{2})\/([0-9]{3})\/([0-9]{4})/g + const requiredLength = 11 + + if (!input) { + return [false, 'Enter the farm or premises CPH number'] + } + + if (input && (!valid.test(input) || input.length !== requiredLength)) { + return [ + false, + 'Enter the CPH number in the correct format, for example, 12/345/6789' + ] + } + + return [true, null] +} diff --git a/src/server/exit-page/controller.js b/src/server/exit-page/controller.js new file mode 100644 index 00000000..0f77cc03 --- /dev/null +++ b/src/server/exit-page/controller.js @@ -0,0 +1,17 @@ +/** + * A GDS styled example home page controller. + * Provided as an example, remove or modify as required. + * @satisfies {Partial} + */ +export const exitPageController = { + handler(_request, h) { + return h.view('exit-page/index', { + pageTitle: 'This service is not available for your movement type', + heading: 'This service is not available for your movement type' + }) + } +} + +/** + * @import { ServerRoute } from '@hapi/hapi' + */ diff --git a/src/server/exit-page/controller.test.js b/src/server/exit-page/controller.test.js new file mode 100644 index 00000000..0d0ac5a7 --- /dev/null +++ b/src/server/exit-page/controller.test.js @@ -0,0 +1,34 @@ +import { createServer } from '~/src/server/index.js' +import { statusCodes } from '~/src/server/common/constants/status-codes.js' + +describe('#exitPageController', () => { + /** @type {Server} */ + let server + + beforeAll(async () => { + server = await createServer() + await server.initialize() + }) + + afterAll(async () => { + await server.stop({ timeout: 0 }) + }) + + test('Should provide expected response', async () => { + const { result, statusCode } = await server.inject({ + method: 'GET', + url: '/exit-page' + }) + + expect(result).toEqual( + expect.stringContaining( + 'This service is not available for your movement type' + ) + ) + expect(statusCode).toBe(statusCodes.ok) + }) +}) + +/** + * @import { Server } from '@hapi/hapi' + */ diff --git a/src/server/exit-page/index.js b/src/server/exit-page/index.js new file mode 100644 index 00000000..69554c05 --- /dev/null +++ b/src/server/exit-page/index.js @@ -0,0 +1,28 @@ +import { exitPageController } from '~/src/server/exit-page/controller.js' + +/** + * Sets up the routes used in the home page. + * These routes are registered in src/server/router.js. + */ + +/** + * @satisfies {ServerRegisterPluginObject} + */ +export const exitPage = { + plugin: { + name: 'exitPage', + register(server) { + server.route([ + { + method: 'GET', + path: '/exit-page', + ...exitPageController + } + ]) + } + } +} + +/** + * @import { ServerRegisterPluginObject } from '@hapi/hapi' + */ diff --git a/src/server/exit-page/index.njk b/src/server/exit-page/index.njk new file mode 100644 index 00000000..5ee338fc --- /dev/null +++ b/src/server/exit-page/index.njk @@ -0,0 +1,33 @@ +{% extends 'layouts/page.njk' %} + +{% block content %} + +
+
+

+ {{ heading }} +

+ +
+

+ This service is currently only available for movements off your farm or premises. +

+ +

+ You need to complete and submit the current form. +

+ +

+ + View the application form + + on + + GOV.UK + +

+
+
+
+ +{% endblock %} diff --git a/src/server/on-off-farm/controller.js b/src/server/on-off-farm/controller.js index d30a9abe..1e6a69ff 100644 --- a/src/server/on-off-farm/controller.js +++ b/src/server/on-off-farm/controller.js @@ -41,17 +41,20 @@ export const onOffFarmPostController = { req.yar.set('onOffFarm', onOffFarm) - if (onOffFarm === 'off') { - return res.redirect('/cph-number') + switch (onOffFarm) { + case 'off': + return res.redirect('/cph-number') + case 'on': + return res.redirect('/exit-page') + default: + return res.view(indexView, { + pageTitle: `Error: ${pageTitle}`, + heading: pageHeading, + errorMessage: { + text: 'Select if you are moving cattle on or off your farm' + } + }) } - - return res.view(indexView, { - pageTitle, - heading: pageHeading, - onOffFarm: { - value: onOffFarm - } - }) } } diff --git a/src/server/on-off-farm/controller.test.js b/src/server/on-off-farm/controller.test.js index 2ac5f3f1..a4452064 100644 --- a/src/server/on-off-farm/controller.test.js +++ b/src/server/on-off-farm/controller.test.js @@ -33,35 +33,38 @@ describe('#onOffFarmController', () => { expect(statusCode).toBe(statusCodes.ok) }) - test('Should process the result and provide expected response', async () => { - const { payload, statusCode } = await server.inject( - withCsrfProtection({ - method: 'POST', - url: '/to-or-from-own-premises', - payload: { - onOffFarm: 'on' - } - }) - ) + describe('Should process the result and provide expected response', () => { + test('should redirect to cph number page', async () => { + const { headers, statusCode } = await server.inject( + withCsrfProtection({ + method: 'POST', + url: '/to-or-from-own-premises', + payload: { + onOffFarm: 'off' + } + }) + ) - expect(parseDocument(payload).title).toBe( - 'Are you moving the cattle on or off your farm?' - ) - expect(payload).toEqual(expect.not.stringContaining('There is a problem')) + expect(headers.location).toBe('/cph-number') - expect(payload).toEqual( - expect.stringContaining( - '' - ) - ) + expect(statusCode).toBe(statusCodes.redirect) + }) - expect(payload).toEqual( - expect.stringContaining( - '' + test('should redirect to exit page', async () => { + const { headers, statusCode } = await server.inject( + withCsrfProtection({ + method: 'POST', + url: '/to-or-from-own-premises', + payload: { + onOffFarm: 'on' + } + }) ) - ) - expect(statusCode).toBe(statusCodes.ok) + expect(headers.location).toBe('/exit-page') + + expect(statusCode).toBe(statusCodes.redirect) + }) }) test('Should display an error to the user if no value selected', async () => { diff --git a/src/server/router.js b/src/server/router.js index 3757fe05..465e7ee9 100644 --- a/src/server/router.js +++ b/src/server/router.js @@ -5,6 +5,8 @@ import { home } from '~/src/server/home/index.js' import { serveStaticFiles } from '~/src/server/common/helpers/serve-static-files.js' import { onOffFarm } from '~/src/server/on-off-farm/index.js' import { cphNumber } from '~/src/server/cph-number/index.js' +import { exitPage } from './exit-page/index.js' + /** * @satisfies {ServerRegisterPluginObject} */ @@ -18,7 +20,7 @@ export const router = { await server.register([health]) // Application specific routes, add your own routes here - await server.register([home, onOffFarm, cphNumber]) + await server.register([home, onOffFarm, cphNumber, exitPage]) // Static assets await server.register([serveStaticFiles])