diff --git a/app/controllers/return-logs-setup.controller.js b/app/controllers/return-logs-setup.controller.js index 03fbe23a9c..a266563aa3 100644 --- a/app/controllers/return-logs-setup.controller.js +++ b/app/controllers/return-logs-setup.controller.js @@ -6,15 +6,18 @@ */ const CheckService = require('../services/return-logs/setup/check.service.js') +const DeleteNoteService = require('../services/return-logs/setup/delete-note.service.js') const InitiateSessionService = require('../services/return-logs/setup/initiate-session.service.js') const MeterDetailsService = require('../services/return-logs/setup/meter-details.service.js') const MeterProvidedService = require('../services/return-logs/setup/meter-provided.service.js') +const NoteService = require('../services/return-logs/setup/note.service.js') const ReceivedService = require('../services/return-logs/setup/received.service.js') const ReportedService = require('../services/return-logs/setup/reported.service.js') const SingleVolumeService = require('../services/return-logs/setup/single-volume.service.js') const SubmissionService = require('../services/return-logs/setup/submission.service.js') const SubmitMeterDetailsService = require('../services/return-logs/setup/submit-meter-details.service.js') const SubmitMeterProvidedService = require('../services/return-logs/setup/submit-meter-provided.service.js') +const SubmitNoteService = require('../services/return-logs/setup/submit-note.service.js') const SubmitReceivedService = require('../services/return-logs/setup/submit-received.service.js') const SubmitReportedService = require('../services/return-logs/setup/submit-reported.service.js') const SubmitSingleVolumeService = require('../services/return-logs/setup/submit-single-volume.service.js') @@ -24,11 +27,19 @@ const UnitsService = require('../services/return-logs/setup/units.service.js') async function check(request, h) { const { sessionId } = request.params - const pageData = await CheckService.go(sessionId) + const pageData = await CheckService.go(sessionId, request.yar) return h.view('return-logs/setup/check.njk', pageData) } +async function deleteNote(request, h) { + const { sessionId } = request.params + + await DeleteNoteService.go(sessionId, request.yar) + + return h.redirect(`/system/return-logs/setup/${sessionId}/check`) +} + async function guidance(_request, h) { return h.view('return-logs/setup/guidance.njk') } @@ -47,6 +58,14 @@ async function meterProvided(request, h) { return h.view('return-logs/setup/meter-provided.njk', pageData) } +async function note(request, h) { + const { sessionId } = request.params + + const pageData = await NoteService.go(sessionId) + + return h.view('return-logs/setup/note.njk', pageData) +} + async function received(request, h) { const { sessionId } = request.params const pageData = await ReceivedService.go(sessionId) @@ -116,6 +135,19 @@ async function submitMeterProvided(request, h) { return h.redirect(`/system/return-logs/setup/${sessionId}/meter-details`) } +async function submitNote(request, h) { + const { sessionId } = request.params + const { user } = request.auth.credentials + + const pageData = await SubmitNoteService.go(sessionId, request.payload, user, request.yar) + + if (pageData.error) { + return h.view('return-logs/setup/note.njk', pageData) + } + + return h.redirect(`/system/return-logs/setup/${sessionId}/check`) +} + async function submitReceived(request, h) { const { params: { sessionId }, @@ -201,9 +233,11 @@ async function units(request, h) { module.exports = { check, + deleteNote, guidance, meterDetails, meterProvided, + note, received, reported, setup, @@ -211,6 +245,7 @@ module.exports = { submission, submitMeterDetails, submitMeterProvided, + submitNote, submitReceived, submitReported, submitSingleVolume, diff --git a/app/presenters/return-logs/setup/note.presenter.js b/app/presenters/return-logs/setup/note.presenter.js new file mode 100644 index 0000000000..c9b75b095e --- /dev/null +++ b/app/presenters/return-logs/setup/note.presenter.js @@ -0,0 +1,29 @@ +'use strict' + +/** + * Formats data for the `/return-logs/setup/{sessionId}/note` page + * @module NotePresenter + */ + +/** + * Formats data for the `/return-logs/setup/{sessionId}/note` page + * + * @param {module:SessionModel} session - The returns log session instance + * + * @returns {object} The data formatted for the view template + */ +function go(session) { + const { id: sessionId, note, returnReference } = session + + return { + backLink: `/system/return-logs/setup/${sessionId}/check`, + note: note ? note.content : null, + pageTitle: 'Add a note', + returnReference, + sessionId + } +} + +module.exports = { + go +} diff --git a/app/routes/return-logs-setup.routes.js b/app/routes/return-logs-setup.routes.js index f47d7f6492..2b2132ce9d 100644 --- a/app/routes/return-logs-setup.routes.js +++ b/app/routes/return-logs-setup.routes.js @@ -39,6 +39,42 @@ const routes = [ } } }, + { + method: 'GET', + path: '/return-logs/setup/{sessionId}/delete-note', + options: { + handler: ReturnLogsSetupController.deleteNote, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'GET', + path: '/return-logs/setup/{sessionId}/note', + options: { + handler: ReturnLogsSetupController.note, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'POST', + path: '/return-logs/setup/{sessionId}/note', + options: { + handler: ReturnLogsSetupController.submitNote, + auth: { + access: { + scope: ['billing'] + } + } + } + }, { method: 'GET', path: '/return-logs/setup/{sessionId}/received', diff --git a/app/services/return-logs/setup/check.service.js b/app/services/return-logs/setup/check.service.js index fab54ac831..ee415c77e5 100644 --- a/app/services/return-logs/setup/check.service.js +++ b/app/services/return-logs/setup/check.service.js @@ -12,20 +12,32 @@ const CheckPresenter = require('../../../presenters/return-logs/setup/check.pres * Orchestrates fetching and presenting the data needed for the `/return-logs/setup/{sessionId}/check` page * * @param {string} sessionId - The UUID of the current session + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller * * @returns {Promise} page data needed by the view template */ -async function go(sessionId) { +async function go(sessionId, yar) { const session = await SessionModel.query().findById(sessionId) + await _markCheckPageVisited(session) + const formattedData = CheckPresenter.go(session) + const notification = yar.flash('notification')[0] + return { activeNavBar: 'search', - ...formattedData + ...formattedData, + notification } } +async function _markCheckPageVisited(session) { + session.checkPageVisited = true + + return session.$update() +} + module.exports = { go } diff --git a/app/services/return-logs/setup/delete-note.service.js b/app/services/return-logs/setup/delete-note.service.js new file mode 100644 index 0000000000..5c73e0eea7 --- /dev/null +++ b/app/services/return-logs/setup/delete-note.service.js @@ -0,0 +1,39 @@ +'use strict' + +/** + * Deletes the note from the return log currently being setup + * @module DeleteNoteService + */ + +const SessionModel = require('../../../models/session.model.js') + +/** + * Deletes the note from the return log currently being setup + * + * It first retrieves the session instance for the return log journey in progress. Then it removes the notes + * data from the session. + * + * @param {string} sessionId - The id of the current session + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + */ +async function go(sessionId, yar) { + const session = await SessionModel.query().findById(sessionId) + const notification = { + title: 'Removed', + text: 'Note removed' + } + + yar.flash('notification', notification) + + await _save(session) +} + +async function _save(session) { + delete session.note + + return session.$update() +} + +module.exports = { + go +} diff --git a/app/services/return-logs/setup/note.service.js b/app/services/return-logs/setup/note.service.js new file mode 100644 index 0000000000..ddf3c4109e --- /dev/null +++ b/app/services/return-logs/setup/note.service.js @@ -0,0 +1,34 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data for `/return-logs/setup/{sessionId}/note` page + * @module NoteService + */ + +const NotePresenter = require('../../../presenters/return-logs/setup/note.presenter.js') +const SessionModel = require('../../../models/session.model.js') + +/** + * Orchestrates fetching and presenting the data for `/return-logs/setup/{sessionId}/note` page + * + * Supports generating the data needed for the note page in the return log setup journey. It fetches the + * current session record and combines it with textarea information needed for the form. + * + * @param {string} sessionId - The UUID for return log setup session record + * + * @returns {Promise} The view data for the note page + */ +async function go(sessionId) { + const session = await SessionModel.query().findById(sessionId) + + const formattedData = NotePresenter.go(session) + + return { + activeNavBar: 'search', + ...formattedData + } +} + +module.exports = { + go +} diff --git a/app/services/return-logs/setup/submit-note.service.js b/app/services/return-logs/setup/submit-note.service.js new file mode 100644 index 0000000000..9ec2514ec1 --- /dev/null +++ b/app/services/return-logs/setup/submit-note.service.js @@ -0,0 +1,107 @@ +'use strict' + +/** + * Orchestrates validating the data for `/return-logs/setup/{sessionId}/note` page + * @module SubmitNoteService + */ + +const NotePresenter = require('../../../presenters/return-logs/setup/note.presenter.js') +const NoteValidator = require('../../../validators/return-logs/setup/note.validator.js') +const SessionModel = require('../../../models/session.model.js') + +/** + * Orchestrates validating the data for `/return-logs/setup/{sessionId}/note` page + * + * It first retrieves the session instance for the return log 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} user - The logged in user details + * @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, user, yar) { + const session = await SessionModel.query().findById(sessionId) + const validationResult = _validate(payload) + + if (!validationResult) { + const notification = _notification(session, payload.note) + + await _save(session, payload, user) + + if (notification) { + yar.flash('notification', notification) + } + + return {} + } + + const submittedSessionData = _submittedSessionData(session, payload) + + return { + activeNavBar: 'search', + error: validationResult, + ...submittedSessionData + } +} + +function _notification(session, newNote) { + const { + data: { note } + } = session + + if (!note && newNote) { + return { + text: 'Note added', + title: 'Added' + } + } + + if (note?.content !== newNote) { + return { + text: 'Note updated', + title: 'Updated' + } + } + + return null +} + +async function _save(session, payload, user) { + session.note = { + content: payload.note, + userEmail: user.username + } + + return session.$update() +} + +function _submittedSessionData(session, payload) { + session.note = payload.note ? payload.note : null + + return NotePresenter.go(session) +} + +function _validate(payload) { + const validation = NoteValidator.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-logs/setup/note.validator.js b/app/validators/return-logs/setup/note.validator.js new file mode 100644 index 0000000000..2e6ded1454 --- /dev/null +++ b/app/validators/return-logs/setup/note.validator.js @@ -0,0 +1,35 @@ +'use strict' + +/** + * Validates data submitted for the `/return-logs/{sessionId}/note` page + * @module NoteValidator + */ + +const Joi = require('joi') + +/** + * Validates data submitted for the `/return-logs/{sessionId}/note` page + * + * @param {object} payload - The payload from the request to be validated + * + * @returns {object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If + * any errors are found the `error:` property will also exist detailing what the issues were + */ +function go(payload) { + const errorMessage = 'Enter details' + const maxErrorMessage = 'Enter no more than 500 characters' + const schema = Joi.object({ + note: Joi.string().required().max(500).messages({ + 'any.required': errorMessage, + 'any.only': errorMessage, + 'string.empty': errorMessage, + 'string.max': maxErrorMessage + }) + }) + + return schema.validate(payload, { abortEarly: false }) +} + +module.exports = { + go +} diff --git a/app/views/return-logs/setup/check.njk b/app/views/return-logs/setup/check.njk index 69328909c5..9589f70385 100644 --- a/app/views/return-logs/setup/check.njk +++ b/app/views/return-logs/setup/check.njk @@ -1,10 +1,19 @@ {% extends 'layout.njk' %} {% from "govuk/components/button/macro.njk" import govukButton %} +{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %} {% from "govuk/components/radios/macro.njk" import govukRadios %} {% from "govuk/components/summary-list/macro.njk" import govukSummaryList %} {% from "govuk/components/table/macro.njk" import govukTable %} {% block content %} + {# Notification banner #} + {% if notification %} + {{ govukNotificationBanner({ + titleText: notification.title, + text: notification.text + }) }} + {% endif %} + {# Main heading #}
Return reference {{ returnReference }} diff --git a/app/views/return-logs/setup/note.njk b/app/views/return-logs/setup/note.njk new file mode 100644 index 0000000000..11c2e643e9 --- /dev/null +++ b/app/views/return-logs/setup/note.njk @@ -0,0 +1,61 @@ +{% extends 'layout.njk' %} +{% from "govuk/components/back-link/macro.njk" import govukBackLink %} +{% from "govuk/components/button/macro.njk" import govukButton %} +{% from "govuk/components/character-count/macro.njk" import govukCharacterCount %} +{% 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: '#note' + } + ] + }) }} + {% endif %} + + {# Main heading #} + {% set pageHeader %} + + Return reference {{ returnReference }} {{ pageTitle }} + + {% endset %} + +
+ + +
+ {{ govukCharacterCount({ + name: "note", + id: "note", + maxlength: 500, + value: note, + label: { + html: pageHeader, + isPageHeading: true + }, + hint: { + text: "Provide a short explanation about the editing of this return." + }, + errorMessage: { + text: error.text + } if error + }) }} + + {{ govukButton({ text: "Confirm", preventDoubleClick: true }) }} +
+
+{% endblock %} diff --git a/test/controllers/return-logs-setup.controller.test.js b/test/controllers/return-logs-setup.controller.test.js index 57fbeb5c05..69f0eecf0f 100644 --- a/test/controllers/return-logs-setup.controller.test.js +++ b/test/controllers/return-logs-setup.controller.test.js @@ -13,15 +13,18 @@ const { postRequestOptions } = require('../support/general.js') // Things we need to stub const CheckService = require('../../app/services/return-logs/setup/check.service.js') +const DeleteNoteService = require('../../app/services/return-logs/setup/delete-note.service.js') const InitiateSessionService = require('../../app/services/return-logs/setup/initiate-session.service.js') const MeterDetailsService = require('../../app/services/return-logs/setup/meter-details.service.js') const MeterProvidedService = require('../../app/services/return-logs/setup/meter-provided.service.js') +const NoteService = require('../../app/services/return-logs/setup/note.service.js') const ReceivedService = require('../../app/services/return-logs/setup/received.service.js') const ReportedService = require('../../app/services/return-logs/setup/reported.service.js') const SingleVolumeService = require('../../app/services/return-logs/setup/single-volume.service.js') const SubmissionService = require('../../app/services/return-logs/setup/submission.service.js') const SubmitMeterDetailsService = require('../../app/services/return-logs/setup/submit-meter-details.service.js') const SubmitMeterProvidedService = require('../../app/services/return-logs/setup/submit-meter-provided.service.js') +const SubmitNoteService = require('../../app/services/return-logs/setup/submit-note.service.js') const SubmitReceivedService = require('../../app/services/return-logs/setup/submit-received.service.js') const SubmitReportedService = require('../../app/services/return-logs/setup/submit-reported.service.js') const SubmitSingleVolumeService = require('../../app/services/return-logs/setup/submit-single-volume.service.js') @@ -32,6 +35,8 @@ const UnitsService = require('../../app/services/return-logs/setup/units.service // For running our service const { init } = require('../../app/server.js') +const sessionId = 'f01efb63-4d27-4be7-ab10-54cf177f1908' + describe('Return Logs Setup controller', () => { let options let server @@ -56,7 +61,7 @@ describe('Return Logs Setup controller', () => { describe('return-logs/setup', () => { describe('GET', () => { - const session = { id: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', data: {} } + const session = { id: sessionId, data: {} } beforeEach(() => { options = { @@ -85,39 +90,50 @@ describe('Return Logs Setup controller', () => { }) describe('return-logs/setup/{sessionId}/check', () => { - describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e139b961-0aa0-4e58-afcd-a95ce7d0e21d/check', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } - }) + const path = 'check' + describe('GET', () => { describe('when a request is valid', () => { beforeEach(() => { Sinon.stub(CheckService, 'go').resolves({ pageTitle: 'Check details and enter new volumes or readings', returnReference: '1234567', - sessionId: 'e139b961-0aa0-4e58-afcd-a95ce7d0e21d' + sessionId }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Check details and enter new volumes or readings') expect(response.payload).to.contain('1234567') - expect(response.payload).to.contain('e139b961-0aa0-4e58-afcd-a95ce7d0e21d') + expect(response.payload).to.contain(sessionId) }) }) }) }) + describe('/return-logs/setup/{sessionId}/delete-note', () => { + const path = 'delete-note' + + describe('GET', () => { + beforeEach(async () => { + Sinon.stub(DeleteNoteService, 'go').resolves({ + title: 'Removed', + text: 'Note removed' + }) + }) + + it('redirects on success', async () => { + const result = await server.inject(_getOptions(path)) + + expect(result.statusCode).to.equal(302) + expect(result.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/check`) + }) + }) + }) + describe('return-logs/setup/guidance', () => { describe('GET', () => { beforeEach(() => { @@ -142,30 +158,73 @@ describe('Return Logs Setup controller', () => { }) }) - describe('return-logs/setup/{sessionId}/received', () => { + describe('/return-logs/setup/{sessionId}/note', () => { + const path = 'note' + describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/received', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } + beforeEach(async () => { + Sinon.stub(NoteService, 'go').resolves({ + id: '8702b98f-ae51-475d-8fcc-e049af8b8d38', + pageTitle: 'Add a note' + }) + }) + + describe('when the request succeeds', () => { + it('returns the page successfully', async () => { + const response = await server.inject(_getOptions(path)) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Add a note') + }) + }) + }) + + describe('POST', () => { + describe('when the request succeeds', () => { + beforeEach(() => { + Sinon.stub(SubmitNoteService, 'go').resolves({}) + }) + + it('redirects to the "check" page', async () => { + const response = await server.inject(_postOptions(path, { journey: 'selectedOption' })) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/check`) + }) }) + describe('when the request succeeds', () => { + describe('and the validation fails', () => { + beforeEach(() => { + Sinon.stub(SubmitNoteService, 'go').resolves({ error: {} }) + }) + + it('returns the page successfully with the error summary banner', async () => { + const response = await server.inject(_postOptions(path, {})) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('There is a problem') + }) + }) + }) + }) + }) + + describe('return-logs/setup/{sessionId}/received', () => { + const path = 'received' + + describe('GET', () => { describe('when a request is valid', () => { beforeEach(() => { Sinon.stub(ReceivedService, 'go').resolves({ - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', + sessionId, licenceId: '3154ea03-e232-4c66-a711-a72956b7de61', pageTitle: 'When was the return received?' }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('When was the return received?') @@ -175,39 +234,31 @@ describe('Return Logs Setup controller', () => { describe('POST', () => { describe('when a request is valid', () => { - beforeEach(() => { - options = _postOptions('received', {}) - }) - describe('and the received date is entered', () => { beforeEach(() => { Sinon.stub(SubmitReceivedService, 'go').resolves({}) }) it('redirects to the "submission" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/submission' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/submission`) }) }) }) describe('when a request is invalid', () => { beforeEach(() => { - options = _postOptions('received') - Sinon.stub(SubmitReceivedService, 'go').resolves({ error: { message: 'Enter a real received date' }, pageTitle: 'When was the return received?', - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5' + sessionId }) }) it('re-renders the page with an error message', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Enter a real received date') @@ -218,29 +269,20 @@ describe('Return Logs Setup controller', () => { }) describe('return-logs/setup/{sessionId}/reported', () => { - describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/reported', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } - }) + const path = 'reported' + describe('GET', () => { describe('when a request is valid', () => { beforeEach(() => { Sinon.stub(ReportedService, 'go').resolves({ - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', + sessionId, licenceId: '3154ea03-e232-4c66-a711-a72956b7de61', pageTitle: 'How was this return reported?' }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('How was this return reported?') @@ -250,39 +292,31 @@ describe('Return Logs Setup controller', () => { describe('POST', () => { describe('when a request is valid', () => { - beforeEach(() => { - options = _postOptions('reported', {}) - }) - describe('and the reported type is entered', () => { beforeEach(() => { Sinon.stub(SubmitReportedService, 'go').resolves({}) }) it('redirects to the "units" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/units' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/units`) }) }) }) describe('when a request is invalid', () => { beforeEach(() => { - options = _postOptions('reported') - Sinon.stub(SubmitReportedService, 'go').resolves({ error: { text: 'Select how this return was reported' }, pageTitle: 'How was this return reported?', - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5' + sessionId }) }) it('re-renders the page with an error message', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Select how this return was reported') @@ -293,25 +327,16 @@ describe('Return Logs Setup controller', () => { }) describe('/return-logs/setup/{sessionId}/submission', () => { - describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/submission', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } - }) + const path = 'submission' + describe('GET', () => { describe('when the request succeeds', () => { beforeEach(() => { Sinon.stub(SubmissionService, 'go').resolves({ pageTitle: 'Abstraction return' }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Abstraction return') @@ -322,44 +347,28 @@ describe('Return Logs Setup controller', () => { describe('POST', () => { describe('when the request succeeds', () => { beforeEach(() => { - options = _postOptions('submission', { journey: 'selectedOption' }) + Sinon.stub(SubmitSubmissionService, 'go').resolves({}) }) - describe('and an option is selected', () => { - beforeEach(() => { - Sinon.stub(SubmitSubmissionService, 'go').resolves({}) - }) - - it('redirects to the "reported" page', async () => { - const response = await server.inject(options) + it('redirects to the "reported" page', async () => { + const response = await server.inject(_postOptions(path, { journey: 'selectedOption' })) - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/reported' - ) - }) + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/reported`) }) }) describe('when the request succeeds', () => { - beforeEach(() => { - options = _postOptions('submission', {}) - }) - - describe('and the validation fails as no option has been selected', () => { + describe('and the validation fails', () => { beforeEach(() => { - Sinon.stub(SubmitSubmissionService, 'go').resolves({ - pageTitle: 'Abstraction return', - error: { text: 'Select what you want to do with this return' } - }) + Sinon.stub(SubmitSubmissionService, 'go').resolves({ error: {} }) }) it('returns the page successfully with the error summary banner', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('Select what you want to do with this return') - expect(response.payload).to.contain('Abstraction return') + expect(response.payload).to.contain('There is a problem') }) }) }) @@ -367,29 +376,20 @@ describe('Return Logs Setup controller', () => { }) describe('return-logs/setup/{sessionId}/units', () => { - describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/units', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } - }) + const path = 'units' + describe('GET', () => { describe('when a request is valid', () => { beforeEach(() => { Sinon.stub(UnitsService, 'go').resolves({ - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', + sessionId, licenceId: '3154ea03-e232-4c66-a711-a72956b7de61', pageTitle: 'Which units were used?' }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Which units were used?') @@ -399,39 +399,31 @@ describe('Return Logs Setup controller', () => { describe('POST', () => { describe('when a request is valid', () => { - beforeEach(() => { - options = _postOptions('units', {}) - }) - describe('and the unit type is entered', () => { beforeEach(() => { Sinon.stub(SubmitUnitsService, 'go').resolves({}) }) it('redirects to the "meter provided" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/meter-provided' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/meter-provided`) }) }) }) describe('when a request is invalid', () => { beforeEach(() => { - options = _postOptions('units') - Sinon.stub(SubmitUnitsService, 'go').resolves({ error: { text: 'Select which units were used' }, pageTitle: 'Which units were used?', - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5' + sessionId }) }) it('re-renders the page with an error message', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Select which units were used') @@ -442,29 +434,20 @@ describe('Return Logs Setup controller', () => { }) describe('return-logs/setup/{sessionId}/meter-provided', () => { - describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/meter-provided', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } - }) + const path = 'meter-provided' + describe('GET', () => { describe('when a request is valid', () => { beforeEach(() => { Sinon.stub(MeterProvidedService, 'go').resolves({ - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', + sessionId, licenceId: '3154ea03-e232-4c66-a711-a72956b7de61', pageTitle: 'Have meter details been provided?' }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Have meter details been provided?') @@ -474,22 +457,16 @@ describe('Return Logs Setup controller', () => { describe('POST', () => { describe('when a request is valid', () => { - beforeEach(() => { - options = _postOptions('meter-provided', {}) - }) - describe('and a meter was provided', () => { beforeEach(() => { Sinon.stub(SubmitMeterProvidedService, 'go').resolves({ meterProvided: 'yes' }) }) it('redirects to the "meter provided" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/meter-details' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/meter-details`) }) }) @@ -499,29 +476,25 @@ describe('Return Logs Setup controller', () => { }) it('redirects to the "meter provided" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/single-volume' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/single-volume`) }) }) }) describe('when a request is invalid', () => { beforeEach(() => { - options = _postOptions('meter-provided') - Sinon.stub(SubmitMeterProvidedService, 'go').resolves({ error: { text: 'Select if meter details have been provided' }, pageTitle: 'Have meter details been provided?', - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5' + sessionId }) }) it('re-renders the page with an error message', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Select if meter details have been provided') @@ -532,28 +505,19 @@ describe('Return Logs Setup controller', () => { }) describe('return-logs/setup/{sessionId}/meter-details', () => { - describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/meter-details', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } - }) + const path = 'meter-details' + describe('GET', () => { describe('when a request is valid', () => { beforeEach(() => { Sinon.stub(MeterDetailsService, 'go').resolves({ - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', + sessionId, pageTitle: 'Meter details' }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Meter details') @@ -563,10 +527,6 @@ describe('Return Logs Setup controller', () => { describe('POST', () => { describe('when a request is valid', () => { - beforeEach(() => { - options = _postOptions('meter-details', {}) - }) - describe('and a meter details were provided', () => { beforeEach(() => { Sinon.stub(SubmitMeterDetailsService, 'go').resolves({ @@ -577,20 +537,16 @@ describe('Return Logs Setup controller', () => { }) it('redirects to the "meter readings" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/meter-readings' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/meter-readings`) }) }) }) describe('when a request is invalid', () => { beforeEach(() => { - options = _postOptions('meter-details') - Sinon.stub(SubmitMeterDetailsService, 'go').resolves({ error: { errorList: [{ href: '#meter-make', text: 'Enter the make of the meter' }], @@ -602,7 +558,7 @@ describe('Return Logs Setup controller', () => { }) it('re-renders the page with an error message', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Enter the make of the meter') @@ -613,28 +569,19 @@ describe('Return Logs Setup controller', () => { }) describe('return-logs/setup/{sessionId}/single-volume', () => { - describe('GET', () => { - beforeEach(() => { - options = { - method: 'GET', - url: '/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/single-volume', - auth: { - strategy: 'session', - credentials: { scope: ['billing'] } - } - } - }) + const path = 'single-volume' + describe('GET', () => { describe('when a request is valid', () => { beforeEach(() => { Sinon.stub(SingleVolumeService, 'go').resolves({ - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', + sessionId, pageTitle: 'Is it a single volume?' }) }) it('returns the page successfully', async () => { - const response = await server.inject(options) + const response = await server.inject(_getOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Is it a single volume?') @@ -644,10 +591,6 @@ describe('Return Logs Setup controller', () => { describe('POST', () => { describe('when a request is valid', () => { - beforeEach(() => { - options = _postOptions('single-volume', {}) - }) - describe('and a single volume was provided', () => { beforeEach(() => { Sinon.stub(SubmitSingleVolumeService, 'go').resolves({ @@ -657,12 +600,10 @@ describe('Return Logs Setup controller', () => { }) it('redirects to the "period used" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/period-used' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/period-used`) }) }) @@ -674,29 +615,25 @@ describe('Return Logs Setup controller', () => { }) it('redirects to the "check answers" page', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path, {})) expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/check-answers' - ) + expect(response.headers.location).to.equal(`/system/return-logs/setup/${sessionId}/check-answers`) }) }) }) describe('when a request is invalid', () => { beforeEach(() => { - options = _postOptions('single-volume') - Sinon.stub(SubmitSingleVolumeService, 'go').resolves({ error: { message: 'Select which units were used' }, pageTitle: 'Is it a single volume?', - sessionId: 'e0c77b74-7326-493d-be5e-0d1ad41594b5' + sessionId }) }) it('re-renders the page with an error message', async () => { - const response = await server.inject(options) + const response = await server.inject(_postOptions(path)) expect(response.statusCode).to.equal(200) expect(response.payload).to.contain('Select which units were used') @@ -707,6 +644,19 @@ describe('Return Logs Setup controller', () => { }) }) +function _getOptions(path) { + const url = `/return-logs/setup/${sessionId}/${path}` + + return { + method: 'GET', + url, + auth: { + strategy: 'session', + credentials: { scope: ['billing'] } + } + } +} + function _postOptions(path, payload) { - return postRequestOptions(`/return-logs/setup/e0c77b74-7326-493d-be5e-0d1ad41594b5/${path}`, payload) + return postRequestOptions(`/return-logs/setup/${sessionId}/${path}`, payload) } diff --git a/test/controllers/return-versions-setup.controller.test.js b/test/controllers/return-versions-setup.controller.test.js index 3b4c5a3e73..c6f6f7421d 100644 --- a/test/controllers/return-versions-setup.controller.test.js +++ b/test/controllers/return-versions-setup.controller.test.js @@ -38,6 +38,7 @@ const SubmitFrequencyCollectedService = require('../../app/services/return-versi const SubmitFrequencyReportedService = require('../../app/services/return-versions/setup/submit-frequency-reported.service.js') const SubmitMethodService = require('../../app/services/return-versions/setup/method/submit-method.service.js') const SubmitNoReturnsRequiredService = require('../../app/services/return-versions/setup/submit-no-returns-required.service.js') +const SubmitNoteService = require('../../app/services/return-versions/setup/submit-note.service.js') const SubmitPointsService = require('../../app/services/return-versions/setup/submit-points.service.js') const SubmitPurposeService = require('../../app/services/return-versions/setup/submit-purpose.service.js') const SubmitReasonService = require('../../app/services/return-versions/setup/submit-reason.service.js') @@ -182,6 +183,36 @@ describe('Return Versions controller', () => { }) }) }) + + describe('POST', () => { + describe('when the request succeeds', () => { + beforeEach(() => { + Sinon.stub(SubmitNoteService, 'go').resolves({}) + }) + + it('redirects to the "check" page', async () => { + const response = await server.inject(_postOptions(path, {})) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal(`/system/return-versions/setup/${sessionId}/check`) + }) + }) + + describe('when the request succeeds', () => { + describe('and the validation fails', () => { + beforeEach(() => { + Sinon.stub(SubmitNoteService, 'go').resolves({ error: {} }) + }) + + it('returns the page successfully with the error summary banner', async () => { + const response = await server.inject(_postOptions(path, {})) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('There is a problem') + }) + }) + }) + }) }) describe('/return-versions/setup/{sessionId}/agreements-exceptions', () => { diff --git a/test/presenters/return-logs/setup/note.presenter.test.js b/test/presenters/return-logs/setup/note.presenter.test.js new file mode 100644 index 0000000000..efb8965efe --- /dev/null +++ b/test/presenters/return-logs/setup/note.presenter.test.js @@ -0,0 +1,69 @@ +'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 NotePresenter = require('../../../../app/presenters/return-logs/setup/note.presenter.js') + +describe('Return Logs Setup - Note presenter', () => { + let session + + beforeEach(() => { + session = { + id: '61e07498-f309-4829-96a9-72084a54996d', + returnReference: '1234' + } + }) + + describe('when provided with a session', () => { + it('correctly presents the data without a note', () => { + const result = NotePresenter.go(session) + + expect(result).to.be.equal({ + backLink: '/system/return-logs/setup/61e07498-f309-4829-96a9-72084a54996d/check', + note: null, + pageTitle: 'Add a note', + returnReference: '1234', + sessionId: '61e07498-f309-4829-96a9-72084a54996d' + }) + }) + }) + + describe('the "backLink" property', () => { + it('returns a link back to the "check" page', () => { + const result = NotePresenter.go(session) + + expect(result.backLink).to.equal('/system/return-logs/setup/61e07498-f309-4829-96a9-72084a54996d/check') + }) + }) + + describe('the "note" property', () => { + describe('when the user has previously submitted a note', () => { + beforeEach(() => { + session.note = { + content: 'Note attached to return log', + userEmail: 'carol.shaw@atari.com' + } + }) + + it('returns the contents of the note', () => { + const result = NotePresenter.go(session) + + expect(result.note).to.equal('Note attached to return log') + }) + }) + + describe('when the user has not previously submitted a note', () => { + it('returns an empty note', () => { + const result = NotePresenter.go(session) + + expect(result.note).to.be.null() + }) + }) + }) +}) diff --git a/test/services/return-logs/setup/check.service.test.js b/test/services/return-logs/setup/check.service.test.js index 75a2479b17..a3379696b6 100644 --- a/test/services/return-logs/setup/check.service.test.js +++ b/test/services/return-logs/setup/check.service.test.js @@ -3,6 +3,7 @@ // Test framework dependencies const Lab = require('@hapi/lab') const Code = require('@hapi/code') +const Sinon = require('sinon') const { describe, it, before } = (exports.lab = Lab.script()) const { expect } = Code @@ -14,16 +15,18 @@ const SessionHelper = require('../../../support/helpers/session.helper.js') const CheckService = require('../../../../app/services/return-logs/setup/check.service.js') describe('Return Logs Setup - Check service', () => { - let sessionId + let session + let yarStub before(async () => { - const session = await SessionHelper.add({ data: { returnReference: '1234' } }) - sessionId = session.id + session = await SessionHelper.add({ data: { returnReference: '1234' } }) + + yarStub = { flash: Sinon.stub().returns([]) } }) describe('when called', () => { it('returns page data for the view', async () => { - const result = await CheckService.go(sessionId) + const result = await CheckService.go(session.id, yarStub) expect(result).to.equal({ activeNavBar: 'search', @@ -36,10 +39,19 @@ describe('Return Logs Setup - Check service', () => { ], text: 'No notes added' }, + notification: undefined, pageTitle: 'Check details and enter new volumes or readings', returnReference: '1234', - sessionId + sessionId: session.id }) }) + + it('updates the session record to indicate user has visited the "check" page', async () => { + await CheckService.go(session.id, yarStub) + + const refreshedSession = await session.$query() + + expect(refreshedSession.checkPageVisited).to.be.true() + }) }) }) diff --git a/test/services/return-logs/setup/delete-note.service.test.js b/test/services/return-logs/setup/delete-note.service.test.js new file mode 100644 index 0000000000..ed5d066e07 --- /dev/null +++ b/test/services/return-logs/setup/delete-note.service.test.js @@ -0,0 +1,53 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach } = (exports.lab = Lab.script()) +const { expect } = Code + +// Test helpers +const SessionHelper = require('../../../support/helpers/session.helper.js') + +// Thing under test +const DeleteNoteService = require('../../../../app/services/return-logs/setup/delete-note.service.js') + +describe('Return Logs Setup - Delete Note service', () => { + let session + let yarStub + + beforeEach(async () => { + session = await SessionHelper.add({ + data: { + returnReference: '1234', + note: { + content: 'I am not long for this world', + userEmail: 'carol.shaw@atari.com' + } + } + }) + + yarStub = { + flash: Sinon.stub() + } + }) + + it('deletes the note from the session', async () => { + await DeleteNoteService.go(session.id, yarStub) + + const refreshedSession = await session.$query() + + expect(refreshedSession.note).to.be.undefined() + }) + + it('sets the notification message to "Removed"', async () => { + await DeleteNoteService.go(session.id, yarStub) + + const [flashType, notification] = yarStub.flash.args[0] + + expect(flashType).to.equal('notification') + expect(notification).to.equal({ title: 'Removed', text: 'Note removed' }) + }) +}) diff --git a/test/services/return-logs/setup/note.service.test.js b/test/services/return-logs/setup/note.service.test.js new file mode 100644 index 0000000000..d632f3d148 --- /dev/null +++ b/test/services/return-logs/setup/note.service.test.js @@ -0,0 +1,44 @@ +'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 SessionHelper = require('../../../support/helpers/session.helper.js') + +// Thing under test +const NoteService = require('../../../../app/services/return-logs/setup/note.service.js') + +describe('Return Logs Setup - Note service', () => { + let sessionId + + beforeEach(async () => { + const session = await SessionHelper.add({ data: { returnReference: '1234' } }) + sessionId = session.id + }) + + describe('when called', () => { + it('fetches the current setup session record', async () => { + const result = await NoteService.go(sessionId) + + expect(result.sessionId).to.equal(sessionId) + }) + + it('returns page data for the view', async () => { + const result = await NoteService.go(sessionId) + + expect(result).to.equal({ + activeNavBar: 'search', + backLink: `/system/return-logs/setup/${sessionId}/check`, + note: null, + pageTitle: 'Add a note', + returnReference: '1234', + sessionId + }) + }) + }) +}) diff --git a/test/services/return-logs/setup/submit-note.service.test.js b/test/services/return-logs/setup/submit-note.service.test.js new file mode 100644 index 0000000000..dc96354926 --- /dev/null +++ b/test/services/return-logs/setup/submit-note.service.test.js @@ -0,0 +1,164 @@ +'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 SessionHelper = require('../../../support/helpers/session.helper.js') + +// Thing under test +const SubmitNoteService = require('../../../../app/services/return-logs/setup/submit-note.service.js') + +describe('Return Logs Setup - Submit Note service', () => { + const user = { username: 'carol.shaw@atari.com' } + + let payload + let session + let yarStub + + beforeEach(async () => { + session = await SessionHelper.add({ data: { returnReference: '1234' } }) + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('with a valid payload', () => { + describe('that is a new note', () => { + beforeEach(() => { + payload = { note: 'A new note related to return logs' } + }) + + it('saves the submitted value', async () => { + await SubmitNoteService.go(session.id, payload, user, yarStub) + + const refreshedSession = await session.$query() + + expect(refreshedSession.note).to.equal({ + content: 'A new note related to return logs', + userEmail: 'carol.shaw@atari.com' + }) + }) + + it('returns the correct details the controller needs to redirect the journey', async () => { + const result = await SubmitNoteService.go(session.id, payload, user, yarStub) + + expect(result).to.equal({}) + }) + + it('sets the notification message to "Added"', async () => { + await SubmitNoteService.go(session.id, payload, user, yarStub) + + const [flashType, notification] = yarStub.flash.args[0] + + expect(flashType).to.equal('notification') + expect(notification).to.equal({ title: 'Added', text: 'Note added' }) + }) + }) + + describe('that is an updated note', () => { + beforeEach(async () => { + await session.$query().patch({ + data: { + note: { + content: 'A old note related to return requirement', + userEmail: 'carol.shaw@atari.com' + } + } + }) + + payload = { note: 'An updated note related to return requirement' } + }) + + it('saves the submitted value', async () => { + await SubmitNoteService.go(session.id, payload, user, yarStub) + + const refreshedSession = await session.$query() + + expect(refreshedSession.note).to.equal({ + content: 'An updated note related to return requirement', + userEmail: 'carol.shaw@atari.com' + }) + }) + + it('returns the journey to redirect the page', async () => { + const result = await SubmitNoteService.go(session.id, payload, user, yarStub) + + expect(result).to.equal({}) + }) + + it('sets the notification message to "Updated"', async () => { + await SubmitNoteService.go(session.id, payload, user, yarStub) + + const [flashType, notification] = yarStub.flash.args[0] + + expect(flashType).to.equal('notification') + expect(notification).to.equal({ title: 'Updated', text: 'Note updated' }) + }) + }) + }) + + describe('with an invalid payload', () => { + beforeEach(() => { + payload = {} + }) + + it('returns page data for the view', async () => { + const result = await SubmitNoteService.go(session.id, payload, user, yarStub) + + expect(result).to.equal({ + activeNavBar: 'search', + backLink: `/system/return-logs/setup/${session.id}/check`, + error: { + text: 'Enter details' + }, + note: null, + pageTitle: 'Add a note', + returnReference: '1234', + sessionId: session.id + }) + }) + + describe('because the user has not entered anything', () => { + it('includes an error for the input element', async () => { + const result = await SubmitNoteService.go(session.id, payload, user, yarStub) + + expect(result.error).to.equal({ text: 'Enter details' }) + }) + }) + + describe('because the user has entered a note more than 500 characters', () => { + beforeEach(() => { + payload = { + note: `Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit` + } + }) + + it('includes an error for the input element', async () => { + const result = await SubmitNoteService.go(session.id, payload, user, yarStub) + + expect(result.error).to.equal({ text: 'Enter no more than 500 characters' }) + }) + }) + }) + }) +}) diff --git a/test/validators/return-logs/setup/note.validator.test.js b/test/validators/return-logs/setup/note.validator.test.js new file mode 100644 index 0000000000..d774b39431 --- /dev/null +++ b/test/validators/return-logs/setup/note.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 NoteValidator = require('../../../../app/validators/return-logs/setup/note.validator.js') + +describe('Return Logs Setup - Note validator', () => { + describe('when valid data is provided', () => { + it('confirms the data is valid', () => { + const result = NoteValidator.go({ note: 'Note added to return requirement' }) + + expect(result.value).to.exist() + expect(result.error).not.to.exist() + }) + }) + + describe('when invalid data is provided', () => { + describe('because no "note" is given', () => { + it('fails validation', () => { + const result = NoteValidator.go({ note: '' }) + + expect(result.value).to.exist() + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('Enter details') + }) + }) + + describe('because too much "note" text is given', () => { + it('fails validation', () => { + const result = NoteValidator.go({ + note: `Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit + Lorem ipsum dolor sit amet consectetur adipiscing elit` + }) + + expect(result.value).to.exist() + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('Enter no more than 500 characters') + }) + }) + }) +})