Skip to content

Commit

Permalink
Merge pull request #15 from DEFRA/exit-page
Browse files Browse the repository at this point in the history
[UNKNOWN] generic exit page
  • Loading branch information
eoin-corr-git authored Nov 19, 2024
2 parents 0a46788 + cea7a75 commit 42299a3
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 55 deletions.
3 changes: 2 additions & 1 deletion src/server/common/constants/status-codes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ export const statusCodes = {
unauthorized: 401,
forbidden: 403,
notFound: 404,
imATeapot: 418
imATeapot: 418,
redirect: 302
}
31 changes: 12 additions & 19 deletions src/server/cph-number/controller.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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
}
})
}
Expand Down
20 changes: 20 additions & 0 deletions src/server/cph-number/validator.js
Original file line number Diff line number Diff line change
@@ -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]
}
17 changes: 17 additions & 0 deletions src/server/exit-page/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* A GDS styled example home page controller.
* Provided as an example, remove or modify as required.
* @satisfies {Partial<ServerRoute>}
*/
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'
*/
34 changes: 34 additions & 0 deletions src/server/exit-page/controller.test.js
Original file line number Diff line number Diff line change
@@ -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'
*/
28 changes: 28 additions & 0 deletions src/server/exit-page/index.js
Original file line number Diff line number Diff line change
@@ -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<void>}
*/
export const exitPage = {
plugin: {
name: 'exitPage',
register(server) {
server.route([
{
method: 'GET',
path: '/exit-page',
...exitPageController
}
])
}
}
}

/**
* @import { ServerRegisterPluginObject } from '@hapi/hapi'
*/
33 changes: 33 additions & 0 deletions src/server/exit-page/index.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{% extends 'layouts/page.njk' %}

{% block content %}

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="gem-c-title__text govuk-heading-l">
{{ heading }}
</h1>

<div class="govuk-body" data-testid="app-page-body">
<p>
This service is currently only available for movements off your farm or premises.
</p>

<p>
You need to complete and submit the current form.
</p>

<p>
<a href="https://www.gov.uk/government/publications/tb-restricted-cattle-application-for-movement-licence-in-england">
View the application form
</a>
on
<a href="https://www.gov.uk/">
GOV.UK
</a>
</p>
</div>
</div>
</div>

{% endblock %}
23 changes: 13 additions & 10 deletions src/server/on-off-farm/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
})
}
}

Expand Down
51 changes: 27 additions & 24 deletions src/server/on-off-farm/controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
'<input class="govuk-radios__input" id="off-farm-radio" name="onOffFarm" type="radio" value="off">'
)
)
expect(statusCode).toBe(statusCodes.redirect)
})

expect(payload).toEqual(
expect.stringContaining(
'<input class="govuk-radios__input" id="on-farm-radio" name="onOffFarm" type="radio" value="on" checked>'
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 () => {
Expand Down
4 changes: 3 additions & 1 deletion src/server/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>}
*/
Expand All @@ -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])
Expand Down

0 comments on commit 42299a3

Please sign in to comment.