diff --git a/app/controllers/return-requirements.controller.js b/app/controllers/return-requirements.controller.js index cb651d0288..a3b3032971 100644 --- a/app/controllers/return-requirements.controller.js +++ b/app/controllers/return-requirements.controller.js @@ -6,6 +6,7 @@ */ const AbstractionPeriodService = require('../services/return-requirements/abstraction-period.service.js') +const AdditionalSubmissionOptionsService = require('../services/return-requirements/additional-submission-options.service.js') const AddService = require('../services/return-requirements/add.service.js') const AgreementsExceptionsService = require('../services/return-requirements/agreements-exceptions.service.js') const CancelService = require('../services/return-requirements/cancel.service.js') @@ -25,6 +26,7 @@ const SetupService = require('../services/return-requirements/setup.service.js') const SiteDescriptionService = require('../services/return-requirements/site-description.service.js') const StartDateService = require('../services/return-requirements/start-date.service.js') const SubmitAbstractionPeriod = require('../services/return-requirements/submit-abstraction-period.service.js') +const SubmitAdditionalSubmissionOptionsService = require('../services/return-requirements/submit-additional-submission-options.service.js') const SubmitAgreementsExceptions = require('../services/return-requirements/submit-agreements-exceptions.service.js') const SubmitCancel = require('../services/return-requirements/submit-cancel.service.js') const SubmitCheckService = require('../services/return-requirements/submit-check.service.js') @@ -59,6 +61,16 @@ async function add (request, h) { return h.redirect(`/system/return-requirements/${sessionId}/purpose/${requirementIndex}`) } +async function additionalSubmissionOptions (request, h) { + const { sessionId } = request.params + + const pageData = await AdditionalSubmissionOptionsService.go(sessionId) + + return h.view('return-requirements/additional-submission-options.njk', { + ...pageData + }) +} + async function agreementsExceptions (request, h) { const { requirementIndex, sessionId } = request.params @@ -265,6 +277,18 @@ async function submitAgreementsExceptions (request, h) { return h.redirect(`/system/return-requirements/${sessionId}/check`) } +async function submitAdditionalSubmissionOptions (request, h) { + const { params: { sessionId }, payload, yar } = request + + const pageData = await SubmitAdditionalSubmissionOptionsService.go(sessionId, payload, yar) + + if (pageData.error) { + return h.view('return-requirements/additional-submission-options.njk', pageData) + } + + return h.redirect(`/system/return-requirements/${sessionId}/check`) +} + async function submitCancel (request, h) { const { sessionId } = request.params const { licenceId } = request.payload @@ -468,6 +492,7 @@ async function submitStartDate (request, h) { module.exports = { abstractionPeriod, add, + additionalSubmissionOptions, agreementsExceptions, approved, cancel, @@ -487,6 +512,7 @@ module.exports = { siteDescription, startDate, submitAbstractionPeriod, + submitAdditionalSubmissionOptions, submitAgreementsExceptions, submitCancel, submitCheck, diff --git a/app/presenters/return-requirements/additional-submission-options.presenter.js b/app/presenters/return-requirements/additional-submission-options.presenter.js new file mode 100644 index 0000000000..520963171e --- /dev/null +++ b/app/presenters/return-requirements/additional-submission-options.presenter.js @@ -0,0 +1,30 @@ +'use strict' + +/** + * Formats data for the `/return-requirements/{sessionId}/additional-submission-options` page + * @module AdditionalSubmissionOptionsPresenter +*/ + +/** + * Formats data for the `/return-requirements/{sessionId}/additional-submission-options` page + * + * @param {module:SessionModel} session - The returns requirements session instance + * + * @returns {Object} - The data formatted for the view template + */ +function go (session) { + const { id: sessionId, licence: { id: licenceId, licenceRef }, additionalSubmissionOptions } = session + const data = { + additionalSubmissionOptions: additionalSubmissionOptions ?? [], + backLink: `/system/return-requirements/${sessionId}/check`, + licenceId, + licenceRef, + sessionId + } + + return data +} + +module.exports = { + go +} diff --git a/app/presenters/return-requirements/check.presenter.js b/app/presenters/return-requirements/check.presenter.js index c0deeeff03..b4e79b785f 100644 --- a/app/presenters/return-requirements/check.presenter.js +++ b/app/presenters/return-requirements/check.presenter.js @@ -9,9 +9,10 @@ const { formatLongDate } = require('../base.presenter.js') const { returnRequirementReasons } = require('../../lib/static-lookups.lib.js') function go (session) { - const { id: sessionId, journey, licence, note, reason } = session + const { additionalSubmissionOptions, id: sessionId, journey, licence, note, reason } = session return { + additionalSubmissionOptions: additionalSubmissionOptions ?? [], journey, licenceRef: licence.licenceRef, note: note ? note.content : null, diff --git a/app/routes/return-requirement.routes.js b/app/routes/return-requirement.routes.js index 94b2674e83..300ce2d5cf 100644 --- a/app/routes/return-requirement.routes.js +++ b/app/routes/return-requirement.routes.js @@ -43,6 +43,32 @@ const routes = [ } }, + { + method: 'GET', + path: '/return-requirements/{sessionId}/additional-submission-options', + handler: ReturnRequirementsController.additionalSubmissionOptions, + options: { + auth: { + access: { + scope: ['billing'] + } + }, + description: 'Select additional submission options for the return requirement' + } + }, + { + method: 'POST', + path: '/return-requirements/{sessionId}/additional-submission-options', + handler: ReturnRequirementsController.submitAdditionalSubmissionOptions, + options: { + auth: { + access: { + scope: ['billing'] + } + }, + description: 'Submit additional submission options for the return requirement' + } + }, { method: 'GET', path: '/return-requirements/{sessionId}/agreements-exceptions/{requirementIndex}', diff --git a/app/services/return-requirements/additional-submission-options.service.js b/app/services/return-requirements/additional-submission-options.service.js new file mode 100644 index 0000000000..a1d7c8224f --- /dev/null +++ b/app/services/return-requirements/additional-submission-options.service.js @@ -0,0 +1,37 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data for + * `/return-requirements/{sessionId}/additional-submission-options` page + * @module AdditionalSubmissionOptionsService + */ + +const AdditionalSubmissionOptionsPresenter = require('../../presenters/return-requirements/additional-submission-options.presenter.js') +const SessionModel = require('../../models/session.model.js') + +/** + * Orchestrates fetching and presenting the data for + * `/return-requirements/{sessionId}/additional-submission-options` page + * + * Supports generating the data needed for the points page in the return requirements setup journey. It fetches the + * current session record and combines it with the checkboxes and other information needed for the form. + * + * @param {string} sessionId - The UUID of the current session + * + * @returns {Promise} The view data for the points page +*/ +async function go (sessionId) { + const session = await SessionModel.query().findById(sessionId) + + const formattedData = AdditionalSubmissionOptionsPresenter.go(session) + + return { + activeNavBar: 'search', + pageTitle: 'Select any additional submission options for the return requirements', + ...formattedData + } +} + +module.exports = { + go +} diff --git a/app/services/return-requirements/submit-additional-submission-options.service.js b/app/services/return-requirements/submit-additional-submission-options.service.js new file mode 100644 index 0000000000..6f90d63e3c --- /dev/null +++ b/app/services/return-requirements/submit-additional-submission-options.service.js @@ -0,0 +1,108 @@ +'use strict' + +/** + * Orchestrates validating the data for `/return-requirements/{sessionId}/additional-submission-options` page + * @module AdditionalSubmissionOptionsService + */ + +const AdditionalSubmissionOptionsPresenter = require('../../presenters/return-requirements/additional-submission-options.presenter.js') +const AdditionalSubmissionOptionsValidator = require('../../validators/return-requirements/additional-submission-options.validator.js') +const SessionModel = require('../../models/session.model.js') + +/** + * Orchestrates validating the data for `/return-requirements/{sessionId}/additional-submission-options` page + * + * It first retrieves the session instance for the returns requirements journey in progress. + * + * The validation result is then combined with the output of the presenter to generate the page data needed by the view. + * If there was a validation error the controller will re-render the page so needs this information. If all is well the + * controller will redirect to the next page in the journey. + * + * @param {string} sessionId - The id of the current session + * @param {Object} payload - The submitted form data + * @param {Object} yar - The Hapi `request.yar` session manager passed on by the controller + * + * @returns {Promise} If no errors it returns an empty object else the page data for the note page including the + * validation error details + */ +async function go (sessionId, payload, yar) { + const session = await SessionModel.query().findById(sessionId) + + _handleOneOptionSelected(payload) + + const validationResult = _validate(payload) + + if (!validationResult) { + const notification = _notification(session, payload) + await _save(session, payload) + + if (notification) { + yar.flash('notification', notification) + } + + return {} + } + + const submittedSessionData = _submittedSessionData(session, payload) + + return { + activeNavBar: 'search', + error: validationResult, + pageTitle: 'Select any additional submission options for the return requirements', + ...submittedSessionData + } +} + +/** +* When a single additional submission option is checked by the user, it returns as a string. When multiple options are + * checked, the 'additionalSubmissionOptions' is returned as an array. + * This function works to make those single selected string 'additionalSubmissionOptions' into an array for uniformity. + */ +function _handleOneOptionSelected (payload) { + if (!Array.isArray(payload.additionalSubmissionOptions)) { + payload.additionalSubmissionOptions = [payload.additionalSubmissionOptions] + } +} + +function _notification (session, payload) { + const { additionalSubmissionOptions } = session ?? {} + + if (additionalSubmissionOptions !== payload.additionalSubmissionOptions) { + return { + text: 'Changes updated', + title: 'Updated' + } + } + + return null +} + +async function _save (session, payload) { + session.additionalSubmissionOptions = payload.additionalSubmissionOptions + + return session.$update() +} + +function _submittedSessionData (session, payload) { + session.additionalSubmissionOptions = payload.additionalSubmissionOptions ?? [] + + return AdditionalSubmissionOptionsPresenter.go(session) +} + +function _validate (payload) { + const validation = AdditionalSubmissionOptionsValidator.go(payload) + + if (!validation.error) { + return null + } + + const { message } = validation.error.details[0] + + return { + text: message + } +} + +module.exports = { + go +} diff --git a/app/validators/return-requirements/additional-submission-options.validator.js b/app/validators/return-requirements/additional-submission-options.validator.js new file mode 100644 index 0000000000..01eaf1b9e8 --- /dev/null +++ b/app/validators/return-requirements/additional-submission-options.validator.js @@ -0,0 +1,41 @@ +'use strict' + +/** + * Validates data submitted for the `/return-requirements/{sessionId}/additional-submission-options` page + * @module AdditionalSubmissionOptionsValidator + */ + +const Joi = require('joi') + +/** + * Validates data submitted for the `/return-requirements/{sessionId}/additional-submission-options` page + * + * When setting up a requirement users must specify additional-submission-options for the return requirement. + * Users must select one or more points linked to the licence. + * If these requirements are not met the validation will return an error. + * + * @param {Object} options - The options extracted from payload taken from the request to be validated + * + * @returns {Object} The result from calling Joi's schema.validate(). If any errors are found the `error:` property will + * also exist detailing what the issue is. + */ +function go (payload) { + const additionalSubmissionOptions = payload.additionalSubmissionOptions + + const errorMessage = 'Select additional submission options for the requirements for returns' + + const schema = Joi.object({ + additionalSubmissionOptions: Joi.array() + .items(Joi.string()) + .required() + }).messages({ + 'any.required': errorMessage, + 'array.sparse': errorMessage + }) + + return schema.validate({ additionalSubmissionOptions }, { abortEarly: false }) +} + +module.exports = { + go +} diff --git a/app/views/return-requirements/additional-submission-options.njk b/app/views/return-requirements/additional-submission-options.njk new file mode 100644 index 0000000000..9dc751b45e --- /dev/null +++ b/app/views/return-requirements/additional-submission-options.njk @@ -0,0 +1,73 @@ +{% extends 'layout.njk' %} +{% from "govuk/components/back-link/macro.njk" import govukBackLink %} +{% from "govuk/components/button/macro.njk" import govukButton %} +{% from "govuk/components/checkboxes/macro.njk" import govukCheckboxes %} +{% from 'govuk/components/error-summary/macro.njk' import govukErrorSummary %} + +{% block breadcrumbs %} + {# Back link #} + {{ + govukBackLink({ + text: 'Back', + href: backLink + }) + }} +{% endblock %} + +{% block content %} + {% if error %} + {{ govukErrorSummary({ + titleText: 'There is a problem', + errorList: [ + { + text: error.text, + href: '#additionalSubmissionOptions' + } + ] + }) }} + {% endif %} + + {# Main heading #} + {% set pageHeader %} + + Licence {{ licenceRef }} {{ pageTitle }} + + {% endset %} + +
+
+ {{ govukCheckboxes({ + name: "additionalSubmissionOptions", + fieldset: { + legend: { + html: pageHeader, + isPageHeading: true + } + }, + hint: { + text: "Select all that apply" + }, + errorMessage: { + text: error.text + } if error, + items: [ + { + value: "multiple-upload", + text: "Multiple upload", + checked: additionalSubmissionOptions.includes("multiple-upload") + }, + { + divider: "or" + }, + { + value: "none", + text: "None", + checked: additionalSubmissionOptions.includes("none"), + behaviour: "exclusive" + } + ] + }) }} + {{ govukButton({ text: "Confirm" }) }} +
+
+{% endblock %} diff --git a/app/views/return-requirements/check.njk b/app/views/return-requirements/check.njk index 6bdf0d60c1..6e91c9a756 100644 --- a/app/views/return-requirements/check.njk +++ b/app/views/return-requirements/check.njk @@ -131,6 +131,43 @@

Returns are not required for this licence


{% endif %} + {% if journey == 'returns-required' %} + {{ govukSummaryList({ + classes: 'govuk-!-margin-bottom-2', + rows: [ + { + classes: 'govuk-summary-list', + key: { + text: 'Additional submission options', + classes: "govuk-heading-m govuk-!-width-one-half" + }, + value: { + text: '' + }, + actions: { + items: [ + { + href: "additional-submission-options", + text: "Change" + } + ] + } + }, + { + classes: 'govuk-summary-list govuk-summary-list__row--no-border', + key: { + text: 'Multiple upload', + classes: "govuk-body " + }, + value: { + text: 'Yes' if additionalSubmissionOptions.includes('multiple-upload') else "No" + } + } + ] + }) }} + {% endif %} + +
{{ govukButton({ text: "Approve returns requirements", diff --git a/test/controllers/return-requirements.controller.test.js b/test/controllers/return-requirements.controller.test.js index cd15339b0c..bf69b2667f 100644 --- a/test/controllers/return-requirements.controller.test.js +++ b/test/controllers/return-requirements.controller.test.js @@ -10,6 +10,7 @@ const { expect } = Code // Things we need to stub const AbstractionPeriodService = require('../../app/services/return-requirements/abstraction-period.service.js') +const AdditionalSubmissionOptionsService = require('../../app/services/return-requirements/additional-submission-options.service.js') const AgreementsExceptionService = require('../../app/services/return-requirements/agreements-exceptions.service.js') const CancelService = require('../../app/services/return-requirements/cancel.service.js') const CheckService = require('../../app/services/return-requirements/check.service.js') @@ -68,6 +69,25 @@ describe('Return requirements controller', () => { }) }) + describe('GET /return-requirements/{sessionId}/additional-submission-options', () => { + beforeEach(async () => { + Sinon.stub(AdditionalSubmissionOptionsService, 'go').resolves({ + id: '8702b98f-ae51-475d-8fcc-e049af8b8d38', + pageTitle: 'Select any additional submission options for the return requirements', + additionalSubmissionOptions: [] + }) + }) + + describe('when the request succeeds', () => { + it('returns the page successfully', async () => { + const response = await server.inject(_options('additional-submission-options')) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Select any additional submission options for the return requirements') + }) + }) + }) + describe('GET /return-requirements/{sessionId}/note', () => { beforeEach(async () => { Sinon.stub(NoteService, 'go').resolves({ diff --git a/test/presenters/return-requirements/additional-submission-options.presenter.test.js b/test/presenters/return-requirements/additional-submission-options.presenter.test.js new file mode 100644 index 0000000000..61341c3138 --- /dev/null +++ b/test/presenters/return-requirements/additional-submission-options.presenter.test.js @@ -0,0 +1,78 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Thing under test +const AdditionalSubmissionOptionsPresenter = require('../../../app/presenters/return-requirements/additional-submission-options.presenter.js') + +describe('Return Requirements - Additional Submission Options presenter', () => { + let session + + beforeEach(() => { + session = { + id: '61e07498-f309-4829-96a9-72084a54996d', + checkPageVisited: false, + licence: { + id: '8b7f78ba-f3ad-4cb6-a058-78abc4d1383d', + currentVersionStartDate: '2023-01-01T00:00:00.000Z', + endDate: null, + licenceRef: '01/ABC', + licenceHolder: 'Turbo Kid', + startDate: '2022-04-01T00:00:00.000Z' + }, + journey: 'returns-required', + requirements: [{}], + startDateOptions: 'licenceStartDate', + reason: 'major-change' + } + }) + + describe('when provided with a session', () => { + it('correctly presents the data without additional submission options', () => { + const result = AdditionalSubmissionOptionsPresenter.go(session) + + expect(result).to.be.equal({ + backLink: `/system/return-requirements/${session.id}/check`, + licenceId: '8b7f78ba-f3ad-4cb6-a058-78abc4d1383d', + additionalSubmissionOptions: [], + licenceRef: '01/ABC', + sessionId: session.id + }) + }) + }) + + describe("the 'backLink' property", () => { + it("returns a link back to the 'check' page", () => { + const result = AdditionalSubmissionOptionsPresenter.go(session) + + expect(result.backLink).to.equal(`/system/return-requirements/${session.id}/check`) + }) + }) + + describe("the 'additionalSubmissionOptions' property", () => { + describe('when the user has previously submitted additional submission options', () => { + beforeEach(() => { + session.additionalSubmissionOptions = ['multiple-upload'] + }) + + it('returns the options', () => { + const result = AdditionalSubmissionOptionsPresenter.go(session) + + expect(result.additionalSubmissionOptions).to.include('multiple-upload') + }) + }) + + describe('when the user has not previously chosen options', () => { + it('returns empty options', () => { + const result = AdditionalSubmissionOptionsPresenter.go(session) + + expect(result.additionalSubmissionOptions).to.be.empty() + }) + }) + }) +}) diff --git a/test/presenters/return-requirements/check.presenter.test.js b/test/presenters/return-requirements/check.presenter.test.js index 81b73087ae..a773e051fa 100644 --- a/test/presenters/return-requirements/check.presenter.test.js +++ b/test/presenters/return-requirements/check.presenter.test.js @@ -37,6 +37,7 @@ describe('Return Requirements - Check presenter', () => { const result = CheckPresenter.go(session) expect(result).to.equal({ + additionalSubmissionOptions: [], journey: 'returns-required', licenceRef: '01/ABC', note: null, @@ -51,6 +52,28 @@ describe('Return Requirements - Check presenter', () => { }) }) + describe("the 'additionalSubmissionOptions' property", () => { + describe('when the user has checked additionalSubmissionOptions', () => { + beforeEach(() => { + session.additionalSubmissionOptions = ['multiple-upload'] + }) + + it('returns a checked option', () => { + const result = CheckPresenter.go(session) + + expect(result.additionalSubmissionOptions).to.include('multiple-upload') + }) + }) + + describe('when the user has not checked an option', () => { + it('returns no options', () => { + const result = CheckPresenter.go(session) + + expect(result.additionalSubmissionOptions).to.be.empty() + }) + }) + }) + describe("the 'note' property", () => { describe('when the user has added a note', () => { beforeEach(() => { diff --git a/test/services/return-requirements/additional-submission-options.service.test.js b/test/services/return-requirements/additional-submission-options.service.test.js new file mode 100644 index 0000000000..5fd3dfbb20 --- /dev/null +++ b/test/services/return-requirements/additional-submission-options.service.test.js @@ -0,0 +1,62 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const DatabaseSupport = require('../../support/database.js') +const SessionHelper = require('../../support/helpers/session.helper.js') + +// Thing under test +const AdditionalSubmissionOptionsService = require('../../../app/services/return-requirements/additional-submission-options.service.js') + +describe('Return Requirements - Additional Submission Options service', () => { + let session + + beforeEach(async () => { + await DatabaseSupport.clean() + + session = await SessionHelper.add({ + data: { + checkPageVisited: false, + licence: { + id: '8b7f78ba-f3ad-4cb6-a058-78abc4d1383d', + currentVersionStartDate: '2023-01-01T00:00:00.000Z', + endDate: null, + licenceRef: '01/ABC', + licenceHolder: 'Turbo Kid', + startDate: '2022-04-01T00:00:00.000Z' + }, + journey: 'returns-required', + requirements: [{}], + startDateOptions: 'licenceStartDate', + reason: 'major-change' + } + }) + }) + + describe('when called', () => { + it('fetches the current setup session record', async () => { + const result = await AdditionalSubmissionOptionsService.go(session.id) + + expect(result.sessionId).to.equal(session.id) + }) + + it('returns page data for the view', async () => { + const result = await AdditionalSubmissionOptionsService.go(session.id) + + expect(result).to.equal({ + activeNavBar: 'search', + additionalSubmissionOptions: [], + backLink: `/system/return-requirements/${session.id}/check`, + licenceId: '8b7f78ba-f3ad-4cb6-a058-78abc4d1383d', + licenceRef: '01/ABC', + pageTitle: 'Select any additional submission options for the return requirements' + }, { skip: ['sessionId'] }) + }) + }) +}) diff --git a/test/services/return-requirements/check.service.test.js b/test/services/return-requirements/check.service.test.js index 47d9f8b172..d51c205ab2 100644 --- a/test/services/return-requirements/check.service.test.js +++ b/test/services/return-requirements/check.service.test.js @@ -59,6 +59,7 @@ describe('Return Requirements - Check service', () => { expect(result).to.equal({ activeNavBar: 'search', + additionalSubmissionOptions: [], notification: undefined, journey: 'returns-required', licenceRef: '01/ABC', diff --git a/test/services/return-requirements/submit-additional-submission-options.service.test.js b/test/services/return-requirements/submit-additional-submission-options.service.test.js new file mode 100644 index 0000000000..b873355b1f --- /dev/null +++ b/test/services/return-requirements/submit-additional-submission-options.service.test.js @@ -0,0 +1,105 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const DatabaseSupport = require('../../support/database.js') +const SessionHelper = require('../../support/helpers/session.helper.js') + +// Thing under test +const SubmitAdditionalSubmissionOptionsService = require('../../../app/services/return-requirements/submit-additional-submission-options.service.js') + +describe('Return Requirements - Submit Additional Submission Options service', () => { + let payload + let session + let yarStub + + beforeEach(async () => { + await DatabaseSupport.clean() + + session = await SessionHelper.add({ + data: { + checkPageVisited: false, + licence: { + id: '8b7f78ba-f3ad-4cb6-a058-78abc4d1383d', + currentVersionStartDate: '2023-01-01T00:00:00.000Z', + endDate: null, + licenceRef: '01/ABC', + licenceHolder: 'Turbo Kid', + startDate: '2022-04-01T00:00:00.000Z' + }, + journey: 'returns-required', + requirements: [{}], + startDateOptions: 'licenceStartDate', + reason: 'major-change' + } + }) + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('with a valid payload', () => { + beforeEach(() => { + payload = { + additionalSubmissionOptions: 'multiple-upload' + } + }) + + it('saves the submitted value', async () => { + await SubmitAdditionalSubmissionOptionsService.go(session.id, payload, yarStub) + + const refreshedSession = await session.$query() + + expect(refreshedSession.additionalSubmissionOptions).to.include('multiple-upload') + }) + + it("sets the notification message to 'Updated'", async () => { + await SubmitAdditionalSubmissionOptionsService.go(session.id, payload, yarStub) + + const [flashType, notification] = yarStub.flash.args[0] + + expect(flashType).to.equal('notification') + expect(notification).to.equal({ title: 'Updated', text: 'Changes updated' }) + }) + }) + + describe('with an invalid payload', () => { + beforeEach(() => { + payload = {} + }) + + it('returns page data for the view', async () => { + const result = await SubmitAdditionalSubmissionOptionsService.go(session.id, payload, yarStub) + + expect(result).to.equal({ + activeNavBar: 'search', + backLink: `/system/return-requirements/${session.id}/check`, + pageTitle: 'Select any additional submission options for the return requirements', + licenceRef: '01/ABC', + additionalSubmissionOptions: [undefined] + }, { skip: ['id', 'sessionId', 'error', 'licenceId'] }) + }) + + describe('because the user has not checked anything', () => { + it('includes an error for the checkbox element', async () => { + const result = await SubmitAdditionalSubmissionOptionsService.go(session.id, payload, yarStub) + + expect(result.error).to.equal({ + text: 'Select additional submission options for the requirements for returns' + }) + }) + }) + }) + }) +}) diff --git a/test/validators/return-requirements/additional-submission-options.validator.test.js b/test/validators/return-requirements/additional-submission-options.validator.test.js new file mode 100644 index 0000000000..1f8d7ac2ec --- /dev/null +++ b/test/validators/return-requirements/additional-submission-options.validator.test.js @@ -0,0 +1,56 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it } = exports.lab = Lab.script() +const { expect } = Code + +// Thing under test +const AdditionalSubmissionOptionsValidator = require('../../../app/validators/return-requirements/additional-submission-options.validator.js') + +describe('Additional Submission Options validator', () => { + describe('when valid data is provided', () => { + const payload = { + additionalSubmissionOptions: [ + 'multiple-upload' + ] + } + + it('confirms the data is valid', () => { + const result = AdditionalSubmissionOptionsValidator.go(payload) + + expect(result.value).to.exist() + expect(result.error).not.to.exist() + }) + }) + + describe('when invalid data is provided', () => { + const payload = { + options: [ + 'Invalid option' + ] + } + + it('fails validation', () => { + const result = AdditionalSubmissionOptionsValidator.go(payload) + + expect(result.value).to.exist() + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('Select additional submission options for the requirements for returns') + }) + }) + + describe('when no data is provided', () => { + const payload = {} + + it('fails validation', () => { + const result = AdditionalSubmissionOptionsValidator.go(payload) + + expect(result.value).to.exist() + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('Select additional submission options for the requirements for returns') + }) + }) +})