Skip to content

Commit

Permalink
Feature notifications setup session (#1574)
Browse files Browse the repository at this point in the history
https://eaflood.atlassian.net/browse/WATER-4716

As part of the ongoing work to migrate the legacy UI we are replacing the notification journey from the UI and rebuilding in system.

This change introduces session initialization to allow the journey to store user answers.

This new route notifications/setup is now the target for the water abstraction UI redirect
  • Loading branch information
jonathangoulding authored Dec 17, 2024
1 parent 3df2c8e commit 42b9f8c
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 6 deletions.
8 changes: 8 additions & 0 deletions app/controllers/notifications-setup.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const ReturnsPeriodService = require('../services/notifications/setup/returns-period.service.js')
const SubmitReturnsPeriodService = require('../services/notifications/setup/submit-returns-period.service.js')
const InitiateSessionService = require('../services/notifications/setup/initiate-session.service')

/**
* Controller for /notifications/setup endpoints
Expand All @@ -18,6 +19,12 @@ async function viewReturnsPeriod(_request, h) {
})
}

async function setup(_request, h) {
const session = await InitiateSessionService.go()

return h.redirect(`/system/${basePath}/${session.id}/returns-period`)
}

async function submitReturnsPeriod(request, h) {
const { payload } = request

Expand All @@ -34,5 +41,6 @@ async function submitReturnsPeriod(request, h) {

module.exports = {
viewReturnsPeriod,
setup,
submitReturnsPeriod
}
18 changes: 15 additions & 3 deletions app/routes/notifications-setup.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@

const NotificationsSetupController = require('../controllers/notifications-setup.controller.js')

const basePath = '/notifications/setup/'
const basePath = '/notifications/setup'

const routes = [
{
method: 'GET',
path: basePath + 'returns-period',
path: basePath,
options: {
handler: NotificationsSetupController.setup,
auth: {
access: {
scope: ['returns']
}
}
}
},
{
method: 'GET',
path: basePath + '/{sessionId}/returns-period',
options: {
handler: NotificationsSetupController.viewReturnsPeriod,
auth: {
Expand All @@ -19,7 +31,7 @@ const routes = [
},
{
method: 'POST',
path: basePath + 'returns-period',
path: basePath + '/{sessionId}/returns-period',
options: {
handler: NotificationsSetupController.submitReturnsPeriod,
auth: {
Expand Down
31 changes: 31 additions & 0 deletions app/services/notifications/setup/initiate-session.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict'

/**
* Initiates the session record used for setting up a new ad-hoc returns notification
* @module InitiateSessionService
*/

const SessionModel = require('../../../models/session.model.js')

/**
* Initiates the session record used for setting up a new ad-hoc returns notification
*
* During the setup journey for a new ad-hoc returns notification we temporarily store the data in a `SessionModel`
* instance. It is expected that on each page of the journey the GET will fetch the session record and use it to
* populate the view.
* When the page is submitted the session record will be updated with the next piece of data.
*
* At the end when the journey is complete the data from the session will be used to create the ad-hoc returns
* notification and the session record itself deleted.
*
* @returns {Promise<module:SessionModel>} the newly created session record
*/
async function go() {
// NOTE: data defaults to {} when a new record is created. But Objection.js throws a 'The query is empty' if we pass
// nothing into `insert()`.
return SessionModel.query().insert({ data: {} }).returning('id')
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { expect } = Code
const { postRequestOptions } = require('../support/general.js')

// Things we need to stub
const InitiateSessionService = require('../../app/services/notifications/setup/initiate-session.service.js')
const ReturnsPeriodService = require('../../app/services/notifications/setup/returns-period.service.js')
const SubmitReturnsPeriodService = require('../../app/services/notifications/setup/submit-returns-period.service.js')

Expand All @@ -19,6 +20,7 @@ const { init } = require('../../app/server.js')

describe('Notifications Setup controller', () => {
const basePath = '/notifications/setup'
const session = { id: 'e0c77b74-7326-493d-be5e-0d1ad41594b5', data: {} }

let getOptions
let postOptions
Expand All @@ -42,12 +44,40 @@ describe('Notifications Setup controller', () => {
Sinon.restore()
})

describe('notifications/setup', () => {
describe('GET', () => {
beforeEach(async () => {
getOptions = {
method: 'GET',
url: '/notifications/setup',
auth: {
strategy: 'session',
credentials: { scope: ['returns'] }
}
}
})

describe('when a request is valid', () => {
beforeEach(async () => {
Sinon.stub(InitiateSessionService, 'go').resolves(session)
})

it('redirects successfully', async () => {
const response = await server.inject(getOptions)

expect(response.statusCode).to.equal(302)
expect(response.headers.location).to.equal(`/system/notifications/setup/${session.id}/returns-period`)
})
})
})
})

describe('notifications/setup/returns-period', () => {
describe('GET', () => {
beforeEach(async () => {
getOptions = {
method: 'GET',
url: basePath + '/returns-period',
url: basePath + `/${session.id}/returns-period`,
auth: {
strategy: 'session',
credentials: { scope: ['returns'] }
Expand All @@ -56,6 +86,7 @@ describe('Notifications Setup controller', () => {
})
describe('when a request is valid', () => {
beforeEach(async () => {
Sinon.stub(InitiateSessionService, 'go').resolves(session)
Sinon.stub(ReturnsPeriodService, 'go').returns(_viewReturnsPeriod())
})

Expand All @@ -75,11 +106,12 @@ describe('Notifications Setup controller', () => {
describe('when the request succeeds', () => {
describe('and the validation fails', () => {
beforeEach(async () => {
Sinon.stub(InitiateSessionService, 'go').resolves(session)
Sinon.stub(SubmitReturnsPeriodService, 'go').returns({
..._viewReturnsPeriod(),
error: 'Something went wrong'
})
postOptions = postRequestOptions(basePath + '/returns-period', {})
postOptions = postRequestOptions(basePath + `/${session.id}/returns-period`, {})
})

it('returns the page successfully with the error summary banner', async () => {
Expand All @@ -93,7 +125,7 @@ describe('Notifications Setup controller', () => {
describe('and the validation succeeds', () => {
beforeEach(async () => {
Sinon.stub(SubmitReturnsPeriodService, 'go').returns({ redirect: 'send-notice' })
postOptions = postRequestOptions(basePath + '/returns-period', {})
postOptions = postRequestOptions(basePath + `/${session.id}/returns-period`, {})
})

it('redirects the to the next page', async () => {
Expand Down
26 changes: 26 additions & 0 deletions test/services/notifications/setup/initiate-session.service.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'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

// Test helpers
const SessionModel = require('../../../../app/models/session.model.js')

// Thing under test
const InitiateSessionService = require('../../../../app/services/notifications/setup/initiate-session.service.js')

describe('Notifications Setup - Initiate Session service', () => {
describe('when called', () => {
it('creates a new session record with an empty data property', async () => {
const result = await InitiateSessionService.go()

const matchingSession = await SessionModel.query().findById(result.id)

expect(matchingSession.data).to.equal({})
})
})
})

0 comments on commit 42b9f8c

Please sign in to comment.