From cf1a2317b56b52c85618a48cb401c47131686806 Mon Sep 17 00:00:00 2001 From: Steve Coleman-Williams Date: Wed, 8 Jan 2025 14:22:23 +0000 Subject: [PATCH 1/6] tests --- src/server/check-answers/index.test.js | 3 +- .../answer/receiveMethod/receiveMethod.js | 59 ++++++++++++ .../receiveMethod/receiveMethod.test.js | 94 +++++++++++++++++++ .../common/model/section/licence/licence.js | 4 +- .../model/section/licence/licence.test.js | 7 +- .../destination/another-destination/index.js | 2 + src/server/licence/postExitPage/index.js | 22 +++++ src/server/licence/postExitPage/index.njk | 12 +++ src/server/licence/postExitPage/index.test.js | 12 +++ src/server/licence/receiveMethod/index.js | 43 +++++++++ src/server/licence/receiveMethod/index.njk | 28 ++++++ .../licence/receiveMethod/index.test.js | 76 +++++++++++++++ .../origin/premises-type-exit-page/index.js | 1 + src/server/router.js | 7 +- src/server/task-list/controller.js | 2 +- 15 files changed, 364 insertions(+), 8 deletions(-) create mode 100644 src/server/common/model/answer/receiveMethod/receiveMethod.js create mode 100644 src/server/common/model/answer/receiveMethod/receiveMethod.test.js create mode 100644 src/server/licence/postExitPage/index.js create mode 100644 src/server/licence/postExitPage/index.njk create mode 100644 src/server/licence/postExitPage/index.test.js create mode 100644 src/server/licence/receiveMethod/index.js create mode 100644 src/server/licence/receiveMethod/index.njk create mode 100644 src/server/licence/receiveMethod/index.test.js diff --git a/src/server/check-answers/index.test.js b/src/server/check-answers/index.test.js index 1ab5b00a..d12b9d01 100644 --- a/src/server/check-answers/index.test.js +++ b/src/server/check-answers/index.test.js @@ -60,7 +60,8 @@ describe('#checkAnswers', () => { }) await session.setState('licence', { - emailAddress: 'here@there.com' + emailAddress: 'here@there.com', + receiveMethod: 'email' }) const { payload, statusCode } = await server.inject( diff --git a/src/server/common/model/answer/receiveMethod/receiveMethod.js b/src/server/common/model/answer/receiveMethod/receiveMethod.js new file mode 100644 index 00000000..4142eadc --- /dev/null +++ b/src/server/common/model/answer/receiveMethod/receiveMethod.js @@ -0,0 +1,59 @@ +import Joi from 'joi' +import { AnswerModel } from '../answer-model.js' +import { validateAnswerAgainstSchema } from '../validation.js' + +export const receiveMethodPayloadSchema = Joi.object({ + receiveMethod: Joi.string().required().valid('email', 'post').messages({ + 'any.required': 'Select how you would like this licence sent to you', + 'any.only': 'Select how you would like this licence sent to you' + }) +}) + +/** + * export @typedef {string} ReceiveMethodData + * @typedef {{ receiveMethod: string }} ReceiveMethodPayload + */ + +/** + * @augments AnswerModel + */ +export class ReceiveMethodAnswer extends AnswerModel { + /** + * @returns {string | undefined} + */ + get value() { + return this._data?.receiveMethod + } + + get html() { + return this._data?.receiveMethod ?? '' + } + + /** + * @returns { ReceiveMethodData} + */ + toState() { + return this.value?.replace(/\s+/g, '') ?? '' + } + + validate() { + return validateAnswerAgainstSchema( + receiveMethodPayloadSchema, + this._data ?? {} + ) + } + + _extractFields({ receiveMethod }) { + return { receiveMethod } + } + + /** + * @param { ReceiveMethodData | undefined} state + * @returns { ReceiveMethodAnswer} + */ + static fromState(state) { + return new ReceiveMethodAnswer( + state !== undefined ? { receiveMethod: state } : undefined + ) + } +} diff --git a/src/server/common/model/answer/receiveMethod/receiveMethod.test.js b/src/server/common/model/answer/receiveMethod/receiveMethod.test.js new file mode 100644 index 00000000..9c375eb1 --- /dev/null +++ b/src/server/common/model/answer/receiveMethod/receiveMethod.test.js @@ -0,0 +1,94 @@ +import { ReceiveMethodAnswer } from './receiveMethod.js' + +const validReceiveMethodPayload = { + receiveMethod: 'email' +} + +describe('#ReceiveMethod.validate', () => { + it('should return true for valid receiveMethod', () => { + const receiveMethod = new ReceiveMethodAnswer(validReceiveMethodPayload) + const { isValid } = receiveMethod.validate() + + expect(isValid).toBe(true) + }) + + it('should return false for an empty input', () => { + const receiveMethod = new ReceiveMethodAnswer({ + receiveMethod: 'invalid value' + }) + + const { isValid, errors } = receiveMethod.validate() + + expect(isValid).toBe(false) + expect(errors.receiveMethod.text).toBe( + 'Select how you would like this licence sent to you' + ) + }) + + it('should return false for malformed input', () => { + const receiveMethod = new ReceiveMethodAnswer({ + receiveMethod: 'unknown response' + }) + + const { isValid, errors } = receiveMethod.validate() + + expect(isValid).toBe(false) + expect(errors.receiveMethod.text).toBe( + 'Select how you would like this licence sent to you' + ) + }) +}) + +describe('#ReceiveMethod.toState', () => { + it('should replace missing data with blank string', () => { + const receiveMethod = new ReceiveMethodAnswer() + const data = receiveMethod.toState() + + expect(data).toBe('') + }) + + it('should pass through valid data unaltered', () => { + const receiveMethod = new ReceiveMethodAnswer(validReceiveMethodPayload) + const data = receiveMethod.toState() + + expect(data).toEqual(validReceiveMethodPayload.receiveMethod) + }) + + it('should remove whitespace', () => { + const receiveMethod = new ReceiveMethodAnswer({ + receiveMethod: 'p o s t' + }) + + expect(receiveMethod.toState()).toBe('post') + }) +}) + +describe('#ReceiveMethod.fromState', () => { + it('should return just the receiveMethod from the payload', () => { + const receiveMethod = new ReceiveMethodAnswer(validReceiveMethodPayload) + const state = receiveMethod.toState() + expect(ReceiveMethodAnswer.fromState(state).value).toEqual( + validReceiveMethodPayload.receiveMethod + ) + }) + + it('should return an undefined value if the state is undefined', () => { + expect(ReceiveMethodAnswer.fromState(undefined).value).toBeUndefined() + }) + + it('should return an empty object if the state is undefined', () => { + expect(ReceiveMethodAnswer.fromState(undefined)._data).toBeUndefined() + }) +}) + +describe('#ReceiveMethod.html', () => { + it('should return the receiveMethod if present', () => { + const receiveMethod = new ReceiveMethodAnswer(validReceiveMethodPayload) + expect(receiveMethod.html).toBe(validReceiveMethodPayload.receiveMethod) + }) + + it('should return an empty string if receiveMethod is not present', () => { + const receiveMethod = new ReceiveMethodAnswer() + expect(receiveMethod.html).toBe('') + }) +}) diff --git a/src/server/common/model/section/licence/licence.js b/src/server/common/model/section/licence/licence.js index 4eb87b48..2d2090bf 100644 --- a/src/server/common/model/section/licence/licence.js +++ b/src/server/common/model/section/licence/licence.js @@ -1,5 +1,5 @@ import { SectionModel } from '../section-model/section-model.js' -import { emailAddressPage } from '~/src/server/licence/email-address/index.js' +import { receiveMethodPage } from '~/src/server/licence/receiveMethod/index.js' /** * export @typedef {{ @@ -9,7 +9,7 @@ import { emailAddressPage } from '~/src/server/licence/email-address/index.js' */ export class LicenceSection extends SectionModel { - static firstPageFactory = () => emailAddressPage + static firstPageFactory = () => receiveMethodPage /** * @param {LicenceData | undefined} data diff --git a/src/server/common/model/section/licence/licence.test.js b/src/server/common/model/section/licence/licence.test.js index bd2a0007..8bcd0b1f 100644 --- a/src/server/common/model/section/licence/licence.test.js +++ b/src/server/common/model/section/licence/licence.test.js @@ -1,4 +1,4 @@ -import { EmailAddressPage } from '~/src/server/licence/email-address/index.js' +import { ReceiveMethodPage } from '~/src/server/licence/receiveMethod/index.js' import { LicenceSection } from './licence.js' const testEmail = 'test@domain.com' @@ -7,7 +7,8 @@ describe('Licence', () => { describe('validate', () => { it('should return valid if all nested objects are valid', () => { const originData = { - emailAddress: testEmail + emailAddress: testEmail, + receiveMethod: 'email' } const result = LicenceSection.fromState(originData).validate() @@ -22,7 +23,7 @@ describe('Licence', () => { const result = LicenceSection.fromState(originData).validate() expect(result.isValid).toBe(false) - expect(result.firstInvalidPage).toBeInstanceOf(EmailAddressPage) + expect(result.firstInvalidPage).toBeInstanceOf(ReceiveMethodPage) }) }) }) diff --git a/src/server/destination/another-destination/index.js b/src/server/destination/another-destination/index.js index 79e0af6d..827439cf 100644 --- a/src/server/destination/another-destination/index.js +++ b/src/server/destination/another-destination/index.js @@ -9,6 +9,8 @@ export class AnotherDestinationExitPage extends ExitPage { pageTitle = 'This service is not available for your movement type' urlPath = `/destination/can-not-use-service` view = `destination/another-destination/index` + sectionKey = 'destination' + key = 'another-destination' } export const anotherDestinationPage = new AnotherDestinationExitPage() diff --git a/src/server/licence/postExitPage/index.js b/src/server/licence/postExitPage/index.js new file mode 100644 index 00000000..e2f37efc --- /dev/null +++ b/src/server/licence/postExitPage/index.js @@ -0,0 +1,22 @@ +import { ExitPage } from '../../common/model/page/exit-page-model.js' +import { PageController } from '../../common/controller/page-controller/page-controller.js' + +/** + * @import { ServerRegisterPluginObject } from '@hapi/hapi' + */ + +export class ExitPagePost extends ExitPage { + urlPath = '/licence/post' + pageTitle = 'This service does not currently send licences by post' + view = `licence/postExitPage/index` + // sectionKey = 'licence' + // key = 'post' +} +export const exitPagePost = new ExitPagePost() + +/** + * @satisfies {ServerRegisterPluginObject} + */ +export const postExitPage = new PageController(exitPagePost, { + methods: ['GET'] +}).plugin() diff --git a/src/server/licence/postExitPage/index.njk b/src/server/licence/postExitPage/index.njk new file mode 100644 index 00000000..5238dc1f --- /dev/null +++ b/src/server/licence/postExitPage/index.njk @@ -0,0 +1,12 @@ +{% from "govuk/components/radios/macro.njk" import govukRadios %} +{% extends 'layouts/page.njk' %} +{% block content %} +
+
+

+
+ +
+
+
+{% endblock %} diff --git a/src/server/licence/postExitPage/index.test.js b/src/server/licence/postExitPage/index.test.js new file mode 100644 index 00000000..99382ce8 --- /dev/null +++ b/src/server/licence/postExitPage/index.test.js @@ -0,0 +1,12 @@ +import { ExitPagePost } from './index.js' + +describe('#PostController', () => { + it('should have the correct properties', () => { + const page = new ExitPagePost() + expect(page.pageTitle).toBe( + 'This service does not currently send licences by post' + ) + expect(page.urlPath).toBe('/licence/post') + expect(page.view).toBe('licence/postExitPage/index') + }) +}) diff --git a/src/server/licence/receiveMethod/index.js b/src/server/licence/receiveMethod/index.js new file mode 100644 index 00000000..9526a82e --- /dev/null +++ b/src/server/licence/receiveMethod/index.js @@ -0,0 +1,43 @@ +/** + * Sets up the routes used in the cph number page. + * These routes are registered in src/server/router.js. + */ + +import { ReceiveMethodAnswer } from '~/src/server/common/model/answer/receiveMethod/receiveMethod.js' +import { QuestionPage } from '../../common/model/page/question-page-model.js' +import { QuestionPageController } from '../../common/controller/question-page-controller/question-page-controller.js' + +import { emailAddressPage } from '../email-address/index.js' +import { exitPagePost } from '../postExitPage/index.js' + +export class ReceiveMethodPage extends QuestionPage { + urlPath = '/receiving-the-licence/licence-email-or-post' + sectionKey = 'licence' + + question = 'How would you like this licence sent to you?' + + questionKey = 'receiveMethod' + + view = 'licence/receiveMethod/index' + Answer = ReceiveMethodAnswer + + /** @param {ReceiveMethodAnswer} answer */ + nextPage(answer) { + if (answer.value === 'post') { + return exitPagePost + } + return emailAddressPage + } +} +export const receiveMethodPage = new ReceiveMethodPage() + +/** + * @satisfies {ServerRegisterPluginObject} + */ +export const receiveMethod = new QuestionPageController( + receiveMethodPage +).plugin() + +/** + * @import { ServerRegisterPluginObject } from '@hapi/hapi' + */ diff --git a/src/server/licence/receiveMethod/index.njk b/src/server/licence/receiveMethod/index.njk new file mode 100644 index 00000000..275ddba8 --- /dev/null +++ b/src/server/licence/receiveMethod/index.njk @@ -0,0 +1,28 @@ +{% from "govuk/components/radios/macro.njk" import govukRadios %} +{% from "govuk/components/fieldset/macro.njk" import govukFieldset %} +{% extends 'layouts/questions.njk' %} +{% block questions %} + {% call govukFieldset() %} + {{ + govukRadios({ + name: "receiveMethod", + id: "receive-method", + fieldset:{}, + value: value, + items: [ + { + id: "email", + value: "email", + text: "Email" + }, + { + id: "post", + value: "post", + text: "Post" + } + ], + errorMessage: errors.receiveMethod + }) + }} + {% endcall %} +{% endblock %} diff --git a/src/server/licence/receiveMethod/index.test.js b/src/server/licence/receiveMethod/index.test.js new file mode 100644 index 00000000..1e8013ce --- /dev/null +++ b/src/server/licence/receiveMethod/index.test.js @@ -0,0 +1,76 @@ +import { receiveMethod, receiveMethodPage, ReceiveMethodPage } from './index.js' +import { ReceiveMethodAnswer } from '../../common/model/answer/receiveMethod/receiveMethod.js' +import { emailAddressPage } from '../email-address/index.js' +import { exitPagePost } from '../postExitPage/index.js' + +// TODO: import next page object + +const sectionKey = 'licence' +const question = 'How would you like this licence sent to you?' +const questionKey = 'receiveMethod' +const view = 'licence/receiveMethod/index' +const pageUrl = '/receiving-the-licence/licence-email-or-post' + +describe('ReceiveMethodPage', () => { + let page + + beforeEach(() => { + page = new ReceiveMethodPage() + }) + + it('should have the correct urlPath', () => { + expect(page.urlPath).toBe(pageUrl) + }) + + it('should have the correct sectionKey', () => { + expect(page.sectionKey).toBe(sectionKey) + }) + + it('should have the correct question', () => { + expect(page.question).toBe(question) + }) + + it('should have the correct questionKey', () => { + expect(page.questionKey).toBe(questionKey) + }) + + it('should have the correct view', () => { + expect(page.view).toBe(view) + }) + + it('should have the correct Answer model', () => { + expect(page.Answer).toBe(ReceiveMethodAnswer) + }) + + it('nextPage should correct next page', () => { + const nextPage = page.nextPage({ + value: 'email' + }) + + expect(nextPage).toBe(emailAddressPage) + }) + + it('nextPage should correct exit page', () => { + const nextPage = page.nextPage({ + value: 'post' + }) + + expect(nextPage).toBe(exitPagePost) + }) + + it('should export page', () => { + expect(receiveMethodPage).toBeInstanceOf(ReceiveMethodPage) + }) + + it('should export ReceiveMethod as a plugin', () => { + expect(receiveMethod).toHaveProperty('plugin') + const plugin = /** @type {PluginBase & PluginNameVersion} */ ( + receiveMethod.plugin + ) + expect(plugin).toHaveProperty('name') + expect(plugin.name).toBe(`${sectionKey}-${questionKey}`) + expect(plugin).toHaveProperty('register') + }) +}) + +/** @import { PluginBase, PluginNameVersion } from '@hapi/hapi' */ diff --git a/src/server/origin/premises-type-exit-page/index.js b/src/server/origin/premises-type-exit-page/index.js index 6535dea6..66e21d46 100644 --- a/src/server/origin/premises-type-exit-page/index.js +++ b/src/server/origin/premises-type-exit-page/index.js @@ -10,6 +10,7 @@ export class ExitPagePremisesType extends ExitPage { pageTitle = 'This service is not available for your movement type' view = `origin/premises-type-exit-page/index` key = 'ExitPagePremisesType' + sectionKey = 'origin' } export const exitPagePremisesType = new ExitPagePremisesType() diff --git a/src/server/router.js b/src/server/router.js index afed867b..6d02f7a8 100644 --- a/src/server/router.js +++ b/src/server/router.js @@ -11,6 +11,9 @@ import { destination } from './destination/index.js' import { privacyPolicy } from './privacy-policy/index.js' import { submitSummary } from './check-answers/index.js' import { premisesType } from './origin/premises-type-exit-page/index.js' +import { receiveMethod } from './licence/receiveMethod/index.js' +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { postExitPage } from './licence/postExitPage/index.js' /** * @satisfies {ServerRegisterPluginObject} @@ -34,7 +37,9 @@ export const router = { taskList, taskListIncomplete, premisesType, - submitSummary + submitSummary, + receiveMethod + // postExitPage - TODO: Uncomment this line to enable the post exit page ]) // Static assets diff --git a/src/server/task-list/controller.js b/src/server/task-list/controller.js index 62696d7a..e8c7d2a8 100644 --- a/src/server/task-list/controller.js +++ b/src/server/task-list/controller.js @@ -42,7 +42,7 @@ export const taskListGetController = { const licenceGdsTask = buildGdsTaskItem({ title: 'Receiving the licence', - initialLink: '/receiving-the-licence/licence-enter-email-address', + initialLink: '/receiving-the-licence/licence-email-or-post', summaryLink: '/receiving-the-licence/check-answers', isValid: licence.validate().isValid, isEnabled: true From 3bd40d9126a865b2b6ffc97a209a3e7027ad5b2b Mon Sep 17 00:00:00 2001 From: Steve Coleman-Williams Date: Thu, 9 Jan 2025 08:23:49 +0000 Subject: [PATCH 2/6] review comments --- .../answer/receiveMethod/receiveMethod.test.js | 13 ------------- src/server/licence/postExitPage/index.js | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/server/common/model/answer/receiveMethod/receiveMethod.test.js b/src/server/common/model/answer/receiveMethod/receiveMethod.test.js index 9c375eb1..8476b301 100644 --- a/src/server/common/model/answer/receiveMethod/receiveMethod.test.js +++ b/src/server/common/model/answer/receiveMethod/receiveMethod.test.js @@ -24,19 +24,6 @@ describe('#ReceiveMethod.validate', () => { 'Select how you would like this licence sent to you' ) }) - - it('should return false for malformed input', () => { - const receiveMethod = new ReceiveMethodAnswer({ - receiveMethod: 'unknown response' - }) - - const { isValid, errors } = receiveMethod.validate() - - expect(isValid).toBe(false) - expect(errors.receiveMethod.text).toBe( - 'Select how you would like this licence sent to you' - ) - }) }) describe('#ReceiveMethod.toState', () => { diff --git a/src/server/licence/postExitPage/index.js b/src/server/licence/postExitPage/index.js index e2f37efc..7d035c30 100644 --- a/src/server/licence/postExitPage/index.js +++ b/src/server/licence/postExitPage/index.js @@ -9,8 +9,8 @@ export class ExitPagePost extends ExitPage { urlPath = '/licence/post' pageTitle = 'This service does not currently send licences by post' view = `licence/postExitPage/index` - // sectionKey = 'licence' - // key = 'post' + sectionKey = 'licence' + key = 'post' } export const exitPagePost = new ExitPagePost() From 89d35cc6d2a2c5c5e5172a0fd0dd34d34a47cfaf Mon Sep 17 00:00:00 2001 From: Jose Luis Garcia Ramos <11478086+joseluisgraa@users.noreply.github.com> Date: Fri, 10 Jan 2025 11:29:39 +0000 Subject: [PATCH 3/6] Fixed a couple of merge conflicts --- src/server/check-answers/index.test.js | 32 ++++++-------------------- src/server/router.js | 2 +- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/server/check-answers/index.test.js b/src/server/check-answers/index.test.js index fa363753..ffb8341a 100644 --- a/src/server/check-answers/index.test.js +++ b/src/server/check-answers/index.test.js @@ -19,6 +19,7 @@ const testAddress = { addressPostcode: 'RG24 8RR' } const testEmailAddress = 'name@example.com' +const testReceiveMethod = 'email' const originDefaultState = { onOffFarm: 'off', @@ -28,7 +29,8 @@ const originDefaultState = { } const licenceDefaultState = { - emailAddress: testEmailAddress + emailAddress: testEmailAddress, + receiveMethod: testReceiveMethod } const destinationDefaultState = { @@ -56,6 +58,8 @@ const emailContent = [ testAddress.addressPostcode, '## Where are the animals going to?', expectedDestinationText, + '## How would you like this licence sent to you?', + testReceiveMethod, '## What email address would you like the licence sent to?', testEmailAddress ].join('\n') @@ -109,7 +113,8 @@ describe('#CheckAnswers', () => { expect(taskListValues[2].innerHTML).toContain(testCphNumber) expect(taskListValues[3].innerHTML).toContain(testAddress.addressLine1) expect(taskListValues[4].innerHTML).toContain(expectedDestinationText) - expect(taskListValues[5].innerHTML).toContain(testEmailAddress) + expect(taskListValues[5].innerHTML).toContain(testReceiveMethod) + expect(taskListValues[6].innerHTML).toContain(testEmailAddress) expect(statusCode).toBe(statusCodes.ok) }) @@ -133,29 +138,6 @@ describe('#CheckAnswers', () => { expect(headers.location).toBe(taskListIncompleteUri) }) - it('Should provide expected response', async () => { - await session.setState('origin', { - onOffFarm: 'off', - originType: 'afu', - cphNumber: '12/345/6789', - address: { - addressLine1: '73 OCEANA CRESCENT', - addressLine2: 'Archronos Ltd', - addressTown: 'Basingstoke', - addressCounty: 'Hampshire', - addressPostcode: 'RG224FF' - } - }) - - await session.setState('destination', { - destinationType: 'afu' - }) - - await session.setState('licence', { - emailAddress: 'here@there.com', - receiveMethod: 'email' - }) - it('Should stay in check-answers if all tasks are valid', async () => { const { statusCode } = await server.inject( withCsrfProtection( diff --git a/src/server/router.js b/src/server/router.js index 53bc928e..78f6d13b 100644 --- a/src/server/router.js +++ b/src/server/router.js @@ -37,7 +37,7 @@ export const router = { licence, taskList, taskListIncomplete, - receiveMethod + receiveMethod, // postExitPage - TODO: Uncomment this line to enable the post exit page submit, submitSummary, From b93f68b6094ebe87494c4daaa31a76c8c54bf28b Mon Sep 17 00:00:00 2001 From: Steve Coleman-Williams Date: Wed, 8 Jan 2025 14:22:23 +0000 Subject: [PATCH 4/6] tests --- src/server/router.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/router.js b/src/server/router.js index 78f6d13b..821d88a3 100644 --- a/src/server/router.js +++ b/src/server/router.js @@ -41,7 +41,9 @@ export const router = { // postExitPage - TODO: Uncomment this line to enable the post exit page submit, submitSummary, - premisesType + premisesType, + receiveMethod + // postExitPage - TODO: Uncomment this line to enable the post exit page ]) // Static assets From eaa830af61f4bfc54b05539fed55a347cf18dead Mon Sep 17 00:00:00 2001 From: Steve Coleman-Williams Date: Fri, 10 Jan 2025 11:41:21 +0000 Subject: [PATCH 5/6] remove duplicatea fter conflict --- src/server/router.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/server/router.js b/src/server/router.js index 821d88a3..d8b275a6 100644 --- a/src/server/router.js +++ b/src/server/router.js @@ -38,12 +38,10 @@ export const router = { taskList, taskListIncomplete, receiveMethod, - // postExitPage - TODO: Uncomment this line to enable the post exit page + // postExitPage, - TODO: Uncomment this line to enable the post exit page submit, submitSummary, - premisesType, - receiveMethod - // postExitPage - TODO: Uncomment this line to enable the post exit page + premisesType ]) // Static assets From 825cfae3a02169a4b7b6431b148fb621baeaefc4 Mon Sep 17 00:00:00 2001 From: Jose Luis Garcia Ramos <11478086+joseluisgraa@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:15:50 +0000 Subject: [PATCH 6/6] User journey tests --- src/server/licence/receiveMethod/index.njk | 2 +- .../helpers/testHelpers/checkAnswers.js | 10 ++++ .../helpers/testHelpers/receivingLicence.js | 2 + .../page-objects/finalAnswersPage.js | 4 +- .../licenceAnswersPage.js | 7 ++- .../receiveMethodPage.js | 50 +++++++++++++++++++ user-journey-tests/specs/finalAnswers.spec.js | 11 +++- .../emailForLicence.spec.js | 4 -- .../receiveMethod.spec.js | 28 +++++++++++ user-journey-tests/specs/taskList.spec.js | 4 +- 10 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 user-journey-tests/page-objects/receiving-the-licence/receiveMethodPage.js create mode 100644 user-journey-tests/specs/receiving-the-licence/receiveMethod.spec.js diff --git a/src/server/licence/receiveMethod/index.njk b/src/server/licence/receiveMethod/index.njk index 275ddba8..7d32ca5b 100644 --- a/src/server/licence/receiveMethod/index.njk +++ b/src/server/licence/receiveMethod/index.njk @@ -11,7 +11,7 @@ value: value, items: [ { - id: "email", + id: "receiveMethod", value: "email", text: "Email" }, diff --git a/user-journey-tests/helpers/testHelpers/checkAnswers.js b/user-journey-tests/helpers/testHelpers/checkAnswers.js index cc4e61cf..ce815b3e 100644 --- a/user-journey-tests/helpers/testHelpers/checkAnswers.js +++ b/user-journey-tests/helpers/testHelpers/checkAnswers.js @@ -12,6 +12,7 @@ import { import taskListIncompletePage from '../../page-objects/taskListIncompletePage.js' import finalAnswersPage from '../../page-objects/finalAnswersPage.js' import originTypePage from '../../page-objects/origin/originTypePage.js' +import receiveMethodPage from '../../page-objects/receiving-the-licence/receiveMethodPage.js' export const validateOnOffFarm = async (changeLink, valueElement) => { await selectElement(changeLink) @@ -104,6 +105,15 @@ export const validateAndAdjustEmail = async ( await validateElementVisibleAndText(valueElement, inputEmail) } +export const validateReceiveMethod = async (changeLink, valueElement) => { + await selectElement(changeLink) + + await expect(receiveMethodPage.emailRadio).toBeSelected() + await receiveMethodPage.selectEmailAndContinue() + + await validateElementVisibleAndText(valueElement, 'email') +} + export const validateOnFarmErrorHandling = async ( changeElement, final = false diff --git a/user-journey-tests/helpers/testHelpers/receivingLicence.js b/user-journey-tests/helpers/testHelpers/receivingLicence.js index 1180c0b8..584bd3ce 100644 --- a/user-journey-tests/helpers/testHelpers/receivingLicence.js +++ b/user-journey-tests/helpers/testHelpers/receivingLicence.js @@ -1,6 +1,7 @@ import landingPage from '../../page-objects/landingPage.js' import emailPage from '../../page-objects/receiving-the-licence/emailPage.js' import licenceAnswersPage from '../../page-objects/receiving-the-licence/licenceAnswersPage.js' +import receiveMethodPage from '../../page-objects/receiving-the-licence/receiveMethodPage.js' import taskListPage from '../../page-objects/taskListPage.js' import { validateElementVisibleAndText } from '../page.js' @@ -13,6 +14,7 @@ const completeLicenceTask = async ({ email = defaultEmail } = {}) => { await landingPage.navigateToPageAndVerifyTitle() await landingPage.verifyStartNowButton('Start now', true) await taskListPage.selectReceiveTheLicence() + await receiveMethodPage.selectEmailAndContinue() await emailPage.inputEmailAndContinue(email) await validateElementVisibleAndText(licenceAnswersPage.emailValue, email) } diff --git a/user-journey-tests/page-objects/finalAnswersPage.js b/user-journey-tests/page-objects/finalAnswersPage.js index b806d3b6..4c305832 100644 --- a/user-journey-tests/page-objects/finalAnswersPage.js +++ b/user-journey-tests/page-objects/finalAnswersPage.js @@ -40,7 +40,7 @@ class FinalAnswersPage extends Page { return $$(valueIdentifier)[4] } - get receivingMethodValue() { + get receiveMethodValue() { return $$(valueIdentifier)[5] } @@ -68,7 +68,7 @@ class FinalAnswersPage extends Page { return $('[data-testid="destinationType-change-link"]') } - get receivingMethodChange() { + get receiveMethodChange() { return $('[data-testid="licence-choice-change-link"]') } diff --git a/user-journey-tests/page-objects/receiving-the-licence/licenceAnswersPage.js b/user-journey-tests/page-objects/receiving-the-licence/licenceAnswersPage.js index f07e1b79..c190d48a 100644 --- a/user-journey-tests/page-objects/receiving-the-licence/licenceAnswersPage.js +++ b/user-journey-tests/page-objects/receiving-the-licence/licenceAnswersPage.js @@ -14,9 +14,14 @@ class LicenceAnswersPage extends Page { } // Answer values - get emailValue() { + + get receiveMethodValue() { return $$('.govuk-summary-list__value')[0] } + + get emailValue() { + return $$('.govuk-summary-list__value')[1] + } } export default new LicenceAnswersPage() diff --git a/user-journey-tests/page-objects/receiving-the-licence/receiveMethodPage.js b/user-journey-tests/page-objects/receiving-the-licence/receiveMethodPage.js new file mode 100644 index 00000000..f3104387 --- /dev/null +++ b/user-journey-tests/page-objects/receiving-the-licence/receiveMethodPage.js @@ -0,0 +1,50 @@ +import { Page } from '../page.js' + +const emailId = 'receiveMethod' +const postId = 'post' +const pageHeadingAndTitle = 'How would you like this licence sent to you?' + +class ReceiveMethodPage extends Page { + pagePath = '/receiving-the-licence/licence-email-or-post' + pageHeading = pageHeadingAndTitle + pageTitle = pageHeadingAndTitle + noSelectionError = 'Select how you would like this licence sent to you' + + get emailRadio() { + return super.getInputField(emailId) + } + + get postRadio() { + return super.getInputField(postId) + } + + get receiveMethodRadioError() { + return super.getErrorElement(emailId) + } + + get receiveMethodSummaryErrorLink() { + return super.getErrorLink(emailId) + } + + async selectEmailAndContinue() { + await super.selectRadioAndContinue(this.emailRadio) + } + + async selectPostAndContinue() { + await super.selectRadioAndContinue(this.postRadio) + } + + async receiveMethodErrorTest() { + await super.selectContinue() + await super.verifyErrorsOnPage( + this.receiveMethodRadioError, + this.noSelectionError + ) + await super.verifySummaryErrorLink( + this.receiveMethodSummaryErrorLink, + this.emailRadio + ) + } +} + +export default new ReceiveMethodPage() diff --git a/user-journey-tests/specs/finalAnswers.spec.js b/user-journey-tests/specs/finalAnswers.spec.js index be9d1692..1d5d5ca5 100644 --- a/user-journey-tests/specs/finalAnswers.spec.js +++ b/user-journey-tests/specs/finalAnswers.spec.js @@ -6,7 +6,8 @@ import { validateAndAdjustParishNumber, validateOnFarmErrorHandling, validateOnOffFarm, - validateOriginType + validateOriginType, + validateReceiveMethod } from '../helpers/testHelpers/checkAnswers.js' import { completeOriginTaskAnswersCustom } from '../helpers/testHelpers/movementLicence.js' import { completeLicenceTaskAnswersCustom } from '../helpers/testHelpers/receivingLicence.js' @@ -132,6 +133,14 @@ describe('Check your final answers test', () => { ) }) + it('Should verify the method to receive the licence', async () => { + await finalAnswersPage.navigateToPageAndVerifyTitle() + validateReceiveMethod( + finalAnswersPage.receiveMethodChange, + finalAnswersPage.receiveMethodValue + ) + }) + it('Should submit the page after selecting first declaration', async () => { await finalAnswersPage.navigateToPageAndVerifyTitle() await finalAnswersPage.selectADeclarationAndContinue() diff --git a/user-journey-tests/specs/receiving-the-licence/emailForLicence.spec.js b/user-journey-tests/specs/receiving-the-licence/emailForLicence.spec.js index 170ea6aa..19141db0 100644 --- a/user-journey-tests/specs/receiving-the-licence/emailForLicence.spec.js +++ b/user-journey-tests/specs/receiving-the-licence/emailForLicence.spec.js @@ -1,8 +1,6 @@ import { browser } from '@wdio/globals' -import { waitForPagePath } from '../../helpers/page.js' import emailPage from '../../page-objects/receiving-the-licence/emailPage.js' -import licenceAnswersPage from '../../page-objects/receiving-the-licence/licenceAnswersPage.js' const validSubmissionCheck = async (input, whitespace = false) => { let expected @@ -56,8 +54,6 @@ describe('Email address for licence page test', () => { await emailPage.inputEmailAndContinue('bruce.wayne@gotham.com') await expect(emailPage.emailFieldError()).not.toBeDisplayed() await expect(emailPage.errorSummary).not.toBeDisplayed() - - await waitForPagePath(licenceAnswersPage.pagePath) }) it.skip('Should check answer is maintained when submitting after an error', async () => { diff --git a/user-journey-tests/specs/receiving-the-licence/receiveMethod.spec.js b/user-journey-tests/specs/receiving-the-licence/receiveMethod.spec.js new file mode 100644 index 00000000..704a216b --- /dev/null +++ b/user-journey-tests/specs/receiving-the-licence/receiveMethod.spec.js @@ -0,0 +1,28 @@ +import { browser } from '@wdio/globals' +import receiveMethodPage from '../../page-objects/receiving-the-licence/receiveMethodPage.js' +import emailPage from '../../page-objects/receiving-the-licence/emailPage.js' + +describe('Receive method for licence page test', () => { + beforeEach('Reset browser state and navigate to page', async () => { + await browser.reloadSession() + await receiveMethodPage.navigateToPageAndVerifyTitle() + }) + + it('Should verify that the page errors when no option is selected', async () => { + await receiveMethodPage.receiveMethodErrorTest() + }) + + it('Should select email and continue', async () => { + await receiveMethodPage.selectEmailAndContinue() + await expect(receiveMethodPage.pageError).not.toBeDisplayed() + await expect(receiveMethodPage.errorSummary).not.toBeDisplayed() + await emailPage.verifyPageHeadingAndTitle() + }) + + it('Should choose an option and check its maintained', async () => { + await receiveMethodPage.selectEmailAndContinue() + await emailPage.verifyPageHeadingAndTitle() + await browser.back() + await expect(receiveMethodPage.emailRadio).toBeSelected() + }) +}) diff --git a/user-journey-tests/specs/taskList.spec.js b/user-journey-tests/specs/taskList.spec.js index ec17aa7b..a1195771 100644 --- a/user-journey-tests/specs/taskList.spec.js +++ b/user-journey-tests/specs/taskList.spec.js @@ -2,13 +2,13 @@ import { waitForPagePath } from '../helpers/page.js' import taskListPage from '../page-objects/taskListPage.js' import toFromFarmPage from '../page-objects/origin/toFromFarmPage.js' import checkAnswersPage from '../page-objects/origin/checkAnswersPage.js' -import emailPage from '../page-objects/receiving-the-licence/emailPage.js' import taskListIncompletePage from '../page-objects/taskListIncompletePage.js' import completeOriginTaskAnswers from '../helpers/testHelpers/movementLicence.js' import completeLicenceTaskAnswers from '../helpers/testHelpers/receivingLicence.js' import licenceAnswersPage from '../page-objects/receiving-the-licence/licenceAnswersPage.js' import completeDestinationTask from '../helpers/testHelpers/destination.js' import destinationAnswersPage from '../page-objects/destination/destinationAnswersPage.js' +import receiveMethodPage from '../page-objects/receiving-the-licence/receiveMethodPage.js' describe('Task list page test', () => { beforeEach('Navigate to task list page', async () => { @@ -44,7 +44,7 @@ describe('Task list page test', () => { it('Should link to receiving the licence first question before an application has been started', async () => { await taskListPage.selectReceiveTheLicence() - await waitForPagePath(emailPage.pagePath) + await waitForPagePath(receiveMethodPage.pagePath) }) it('Should link to movement origin summary once that selection has been completed', async () => {