From de142780f16e3032952d660ba89a4c374924fe73 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:03:14 +0000 Subject: [PATCH 01/12] Make the existing Telesales cancellation journey available to the public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://eaflood.atlassian.net/browse/IWTF-5045 • Cancellation journey is available in Websales • Cancellation journey is concealed behind a feature switch for Web sales. • Feature switch is off in production --- .../src/routes/__tests__/routes.spec.js | 53 +++++++++++++++++++ .../routes/__tests__/telesales-routes.spec.js | 51 +----------------- .../gafl-webapp-service/src/routes/routes.js | 20 +++++++ .../src/routes/telesales-routes.js | 18 ------- 4 files changed, 74 insertions(+), 68 deletions(-) diff --git a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js index 13575b560c..60031259ec 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js @@ -1,3 +1,13 @@ +import { + CANCEL_RP_IDENTIFY, + CANCEL_RP_DETAILS, + CANCEL_RP_CONFIRM, + CANCEL_RP_COMPLETE, + CANCEL_RP_AGREEMENT_NOT_FOUND, + CANCEL_RP_LICENCE_NOT_FOUND, + CANCEL_RP_ALREADY_CANCELLED +} from '../../uri.js' + const mockErrorRoutes = [Symbol('error')] jest.mock('../error-routes.js', () => mockErrorRoutes) @@ -7,6 +17,17 @@ jest.mock('../error-test-routes.js', () => mockErrorTestingRoutes) const mockTelesalesRoutes = [Symbol('telesales')] jest.mock('../telesales-routes.js', () => mockTelesalesRoutes) +jest.mock('@defra-fish/connectors-lib') +const getCancelRPURIs = () => [ + CANCEL_RP_IDENTIFY.uri, + CANCEL_RP_DETAILS.uri, + CANCEL_RP_CONFIRM.uri, + CANCEL_RP_COMPLETE.uri, + CANCEL_RP_AGREEMENT_NOT_FOUND.uri, + CANCEL_RP_LICENCE_NOT_FOUND.uri, + CANCEL_RP_ALREADY_CANCELLED.uri +] + describe('route', () => { beforeEach(() => { jest.clearAllMocks() @@ -49,3 +70,35 @@ describe('route', () => { expect(routes.default).toEqual(expect.not.arrayContaining(mockErrorTestingRoutes)) }) }) + +describe('cancellation route journey behaves as expected', () => { + beforeEach(jest.clearAllMocks) + + it('adds the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to true', () => { + process.env.SHOW_CANCELLATION_JOURNEY = 'true' + jest.isolateModules(() => { + const routesPaths = require('../routes.js').default.map(route => route.path) + expect(routesPaths).toEqual(expect.arrayContaining(getCancelRPURIs())) + }) + }) + + it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to false', () => { + process.env.SHOW_CANCELLATION_JOURNEY = 'false' + jest.isolateModules(() => { + const routes = require('../routes.js').default + const cancelRPURIs = getCancelRPURIs() + const cancelRPRoutes = routes.filter(route => cancelRPURIs.includes(route.path)) + expect(cancelRPRoutes).toHaveLength(0) + }) + }) + + it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is not present', () => { + delete process.env.SHOW_CANCELLATION_JOURNEY + jest.isolateModules(() => { + const routes = require('../routes.js').default + const cancelRPURIs = getCancelRPURIs() + const cancelRPRoutes = routes.filter(route => cancelRPURIs.includes(route.path)) + expect(cancelRPRoutes).toHaveLength(0) + }) + }) +}) diff --git a/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js index b11303db8d..b1336ff403 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js @@ -1,24 +1,7 @@ import { setupEnvironment } from '../../__mocks__/openid-client.js' -import { - CANCEL_RP_IDENTIFY, - CANCEL_RP_DETAILS, - CANCEL_RP_CONFIRM, - CANCEL_RP_COMPLETE, - CANCEL_RP_AGREEMENT_NOT_FOUND, - CANCEL_RP_LICENCE_NOT_FOUND, - CANCEL_RP_ALREADY_CANCELLED -} from '../../uri.js' jest.mock('@defra-fish/connectors-lib') -const getCancelRPURIs = () => [ - CANCEL_RP_IDENTIFY.uri, - CANCEL_RP_DETAILS.uri, - CANCEL_RP_CONFIRM.uri, - CANCEL_RP_COMPLETE.uri, - CANCEL_RP_AGREEMENT_NOT_FOUND.uri, - CANCEL_RP_LICENCE_NOT_FOUND.uri, - CANCEL_RP_ALREADY_CANCELLED.uri -] + let TestUtils = null describe('Telesales route handlers', () => { // Start application before running the test case @@ -61,35 +44,3 @@ describe('Telesales route handlers', () => { expect(data.statusCode).toBe(200) }) }) - -describe('cancellation route journey behaves as expected', () => { - beforeEach(jest.clearAllMocks) - - it('adds the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to true', () => { - process.env.SHOW_CANCELLATION_JOURNEY = 'true' - jest.isolateModules(() => { - const telesalesRoutePaths = require('../telesales-routes.js').default.map(route => route.path) - expect(telesalesRoutePaths).toEqual(expect.arrayContaining(getCancelRPURIs())) - }) - }) - - it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to false', () => { - process.env.SHOW_CANCELLATION_JOURNEY = 'false' - jest.isolateModules(() => { - const telesalesRoutes = require('../telesales-routes.js').default - const cancelRPURIs = getCancelRPURIs() - const cancelRPRoutes = telesalesRoutes.filter(route => cancelRPURIs.includes(route.path)) - expect(cancelRPRoutes).toHaveLength(0) - }) - }) - - it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is not present', () => { - delete process.env.SHOW_CANCELLATION_JOURNEY - jest.isolateModules(() => { - const telesalesRoutes = require('../telesales-routes.js').default - const cancelRPURIs = getCancelRPURIs() - const cancelRPRoutes = telesalesRoutes.filter(route => cancelRPURIs.includes(route.path)) - expect(cancelRPRoutes).toHaveLength(0) - }) - }) -}) diff --git a/packages/gafl-webapp-service/src/routes/routes.js b/packages/gafl-webapp-service/src/routes/routes.js index fe21234016..8a90ffcb77 100644 --- a/packages/gafl-webapp-service/src/routes/routes.js +++ b/packages/gafl-webapp-service/src/routes/routes.js @@ -32,6 +32,14 @@ import invalidLink from '../pages/renewals/renewal-inactive/route.js' import renewalStartDate from '../pages/renewals/renewal-start-date/route.js' import licenceNotFound from '../pages/renewals/licence-not-found/route.js' +import cancelRPIdentify from '../pages/recurring-payments/cancel/identify/route.js' +import cancelRPDetails from '../pages/recurring-payments/cancel/details/route.js' +import cancelRPConfirm from '../pages/recurring-payments/cancel/confirm/route.js' +import cancelRPComplete from '../pages/recurring-payments/cancel/complete/route.js' +import cancelRPAgreementNotFound from '../pages/recurring-payments/cancel/agreement-not-found/route.js' +import cancelRPLicenceNotFound from '../pages/recurring-payments/cancel/licence-not-found/route.js' +import cancelRPAlreadyCancelled from '../pages/recurring-payments/cancel/already-cancelled/route.js' + import staticAssets from './static-routes.js' import miscRoutes from './misc-routes.js' import telesalesRoutes from './telesales-routes.js' @@ -76,6 +84,18 @@ const routes = [ ...licenceNotFound ] +if (process.env.SHOW_CANCELLATION_JOURNEY === 'true') { + routes.push( + ...cancelRPIdentify, + ...cancelRPDetails, + ...cancelRPConfirm, + ...cancelRPComplete, + ...cancelRPAgreementNotFound, + ...cancelRPAlreadyCancelled, + ...cancelRPLicenceNotFound + ) +} + if (process.env.CHANNEL === 'telesales') { routes.push(...telesalesRoutes) } diff --git a/packages/gafl-webapp-service/src/routes/telesales-routes.js b/packages/gafl-webapp-service/src/routes/telesales-routes.js index 4d042602f9..203b48fe7b 100644 --- a/packages/gafl-webapp-service/src/routes/telesales-routes.js +++ b/packages/gafl-webapp-service/src/routes/telesales-routes.js @@ -1,13 +1,6 @@ import { OIDC_SIGNIN, OIDC_ACCOUNT_DISABLED, OIDC_ROLE_REQUIRED, CONTROLLER } from '../uri.js' import { signIn } from '../handlers/oidc-handler.js' import journeyGoal from '../pages/journey-goal/route.js' -import cancelRPIdentify from '../pages/recurring-payments/cancel/identify/route.js' -import cancelRPDetails from '../pages/recurring-payments/cancel/details/route.js' -import cancelRPConfirm from '../pages/recurring-payments/cancel/confirm/route.js' -import cancelRPComplete from '../pages/recurring-payments/cancel/complete/route.js' -import cancelRPAgreementNotFound from '../pages/recurring-payments/cancel/agreement-not-found/route.js' -import cancelRPLicenceNotFound from '../pages/recurring-payments/cancel/licence-not-found/route.js' -import cancelRPAlreadyCancelled from '../pages/recurring-payments/cancel/already-cancelled/route.js' const telesalesRoutes = [ { @@ -36,15 +29,4 @@ const telesalesRoutes = [ ...journeyGoal ] -if (process.env.SHOW_CANCELLATION_JOURNEY === 'true') { - telesalesRoutes.push( - ...cancelRPIdentify, - ...cancelRPDetails, - ...cancelRPConfirm, - ...cancelRPComplete, - ...cancelRPAgreementNotFound, - ...cancelRPAlreadyCancelled, - ...cancelRPLicenceNotFound - ) -} export default telesalesRoutes From 23301fdef88cc707dc58fbe4127b49153d5d9cb5 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:45:54 +0000 Subject: [PATCH 02/12] remove mock --- packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js index 60031259ec..3da646c348 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js @@ -17,7 +17,6 @@ jest.mock('../error-test-routes.js', () => mockErrorTestingRoutes) const mockTelesalesRoutes = [Symbol('telesales')] jest.mock('../telesales-routes.js', () => mockTelesalesRoutes) -jest.mock('@defra-fish/connectors-lib') const getCancelRPURIs = () => [ CANCEL_RP_IDENTIFY.uri, CANCEL_RP_DETAILS.uri, From f24deccebebc33d08134f3e6619ea166704157b2 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Thu, 26 Mar 2026 16:13:29 +0000 Subject: [PATCH 03/12] turn off SHOW_CANCELLATION_JOURNEY --- docker/env/gafl_webapp.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/env/gafl_webapp.env.example b/docker/env/gafl_webapp.env.example index 5b5b111df4..3c26af3a8b 100644 --- a/docker/env/gafl_webapp.env.example +++ b/docker/env/gafl_webapp.env.example @@ -36,4 +36,4 @@ ERROR_PAGE_ROUTE=false ENABLE_ANALYTICS_OPT_IN_DEBUGGING=true # Recurring payments content -SHOW_CANCELLATION_JOURNEY=true +SHOW_CANCELLATION_JOURNEY=false From 89756e200dae30f08d2a043d4d2405e84e14c409 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Tue, 21 Apr 2026 15:22:09 +0100 Subject: [PATCH 04/12] update readme --- docker/env/gafl_webapp.env.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/env/gafl_webapp.env.example b/docker/env/gafl_webapp.env.example index 3c26af3a8b..82172ee274 100644 --- a/docker/env/gafl_webapp.env.example +++ b/docker/env/gafl_webapp.env.example @@ -36,4 +36,5 @@ ERROR_PAGE_ROUTE=false ENABLE_ANALYTICS_OPT_IN_DEBUGGING=true # Recurring payments content -SHOW_CANCELLATION_JOURNEY=false +## DEV & TEST envs set to true; TRAIN, PRE, PROD set to false +SHOW_CANCELLATION_JOURNEY=true From 5a5095323cf3531f071ff7dd7c43dc68e02f74ec Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Thu, 23 Apr 2026 14:01:20 +0100 Subject: [PATCH 05/12] add new env var name Co-authored-by: Copilot --- docker/env/gafl_webapp.env.example | 6 +- packages/gafl-webapp-service/README.md | 61 ++++++++++--------- .../__tests__/journey-definition.spec.js | 20 ++++++ .../src/routes/__tests__/routes.spec.js | 15 +++-- .../routes/__tests__/telesales-routes.spec.js | 51 +++++++++++++++- .../gafl-webapp-service/src/routes/routes.js | 2 +- .../src/routes/telesales-routes.js | 18 ++++++ 7 files changed, 132 insertions(+), 41 deletions(-) diff --git a/docker/env/gafl_webapp.env.example b/docker/env/gafl_webapp.env.example index 82172ee274..089e5b9087 100644 --- a/docker/env/gafl_webapp.env.example +++ b/docker/env/gafl_webapp.env.example @@ -36,5 +36,9 @@ ERROR_PAGE_ROUTE=false ENABLE_ANALYTICS_OPT_IN_DEBUGGING=true # Recurring payments content -## DEV & TEST envs set to true; TRAIN, PRE, PROD set to false +## Admin Switch SHOW_CANCELLATION_JOURNEY=true + +## Public Switch +// DEV & TEST envs set to true; TRAIN, PRE, PROD set to false +SHOW_CANCELLATION_JOURNEY_PUBLIC=true diff --git a/packages/gafl-webapp-service/README.md b/packages/gafl-webapp-service/README.md index dc2c3f292b..7b1bce0553 100644 --- a/packages/gafl-webapp-service/README.md +++ b/packages/gafl-webapp-service/README.md @@ -8,36 +8,37 @@ To run from this directory: ## Environment variables -| name | description | required | default | valid | -| --------------------------------- | ---------------------------------------------------------------- | :------: | --------------------------------------------------------- | ----------------------------- | -| NODE_ENV | Node environment | no | | development, test, production | -| HAPI_KEEP_ALIVE_TIMEOUT_MS | Configure the keep-alive timeout on the server listener | no | 1 minute | | -| PORT | The http port the listens on | no | 3000 | | -| REDIS_HOST | Hostname of the redis instance used for session caching | yes | | | -| REDIS_PORT | Port number of the redis instance used for session caching | no | 6379 | | -| REDIS_PASSWORD | Password used to authenticate with the configured redis instance | no | | | -| CHANNEL | The sales channel | no | websales | websales, telesales | -| SESSION_COOKIE_NAME | Name of the session cookie | no | sid | | -| CSRF_TOKEN_COOKIE_NAME | Name of the CSRF token cookie | no | rlsctkn | | -| SESSION_COOKIE_PASSWORD | Encryption key for the session cookie (at least 32 characters) | yes | | | -| SESSION_TTL_MS | Time to live for the session cookie and cache | no | 10800000 | | -| ADDRESS_LOOKUP_URL | OS Places API endpoint URL | no | https://api.os.uk/search/places/v1/postcode | | -| ADDRESS_LOOKUP_KEY | The API key required by OS places | no | | | -| ADDRESS_LOOKUP_TIMEOUT_MS | The timeout in milliseconds for the lookup | no | 10000 | | -| SALES_API_URL | The address of the sales api | no | http://0.0.0.0:4000 | | -| SALES_API_TIMEOUT_MS | The timeout in milliseconds requests to the api | no | 10000 | | -| GOV_PAY_API_URL | The GOV.UK Pay API base url | no | Yes | | -| GOV_PAY_APIKEY | GOV pay access identifier | no | Yes | | -| GOV_PAY_REQUEST_TIMEOUT_MS | Timeout in milliseconds for API requests | no | Yes | | -| FEEDBACK_URI | Location of feedback survey | no | # | | -| ANALYTICS_PRIMARY_PROPERTY | Analytics ID for tracking inc ecommerce | no | | | -| ANALYTICS_PROPERTY_API | Analytics property API key for linking Analytics.google property | no | | | -| SERVICE_PAGE | GOV.UK service page | no | https://www.gov.uk/fishing-licences/buy-a-fishing-licence | | -| AIRBRAKE_HOST | URL of airbrake host | no | | | -| AIRBRAKE_PROJECT_KEY | Project key for airbrake logging | no | | | -| ENABLE_ANALYTICS_OPT_IN_DEBUGGING | Set log if analytics been checked in non-production | no | | | -| ERROR_PAGE_ROUTE | Display error pages to support welsh language | no | | | -| SHOW_CANCELLATION_JOURNEY | Display option to show recurring payments cancellation journey | no | | | +| name | description | required | default | valid | +| :-------------------------------: | :----------------------------------------------------------------------: | :------: | :-------------------------------------------------------: | :---------------------------: | +| NODE_ENV | Node environment | no | | development, test, production | +| HAPI_KEEP_ALIVE_TIMEOUT_MS | Configure the keep-alive timeout on the server listener | no | 1 minute | | +| PORT | The http port the listens on | no | 3000 | | +| REDIS_HOST | Hostname of the redis instance used for session caching | yes | | | +| REDIS_PORT | Port number of the redis instance used for session caching | no | 6379 | | +| REDIS_PASSWORD | Password used to authenticate with the configured redis instance | no | | | +| CHANNEL | The sales channel | no | websales | websales, telesales | +| SESSION_COOKIE_NAME | Name of the session cookie | no | sid | | +| CSRF_TOKEN_COOKIE_NAME | Name of the CSRF token cookie | no | rlsctkn | | +| SESSION_COOKIE_PASSWORD | Encryption key for the session cookie (at least 32 characters) | yes | | | +| SESSION_TTL_MS | Time to live for the session cookie and cache | no | 10800000 | | +| ADDRESS_LOOKUP_URL | OS Places API endpoint URL | no | https://api.os.uk/search/places/v1/postcode | | +| ADDRESS_LOOKUP_KEY | The API key required by OS places | no | | | +| ADDRESS_LOOKUP_TIMEOUT_MS | The timeout in milliseconds for the lookup | no | 10000 | | +| SALES_API_URL | The address of the sales api | no | http://0.0.0.0:4000 | | +| SALES_API_TIMEOUT_MS | The timeout in milliseconds requests to the api | no | 10000 | | +| GOV_PAY_API_URL | The GOV.UK Pay API base url | no | Yes | | +| GOV_PAY_APIKEY | GOV pay access identifier | no | Yes | | +| GOV_PAY_REQUEST_TIMEOUT_MS | Timeout in milliseconds for API requests | no | Yes | | +| FEEDBACK_URI | Location of feedback survey | no | # | | +| ANALYTICS_PRIMARY_PROPERTY | Analytics ID for tracking inc ecommerce | no | | | +| ANALYTICS_PROPERTY_API | Analytics property API key for linking Analytics.google property | no | | | +| SERVICE_PAGE | GOV.UK service page | no | https://www.gov.uk/fishing-licences/buy-a-fishing-licence | | +| AIRBRAKE_HOST | URL of airbrake host | no | | | +| AIRBRAKE_PROJECT_KEY | Project key for airbrake logging | no | | | +| ENABLE_ANALYTICS_OPT_IN_DEBUGGING | Set log if analytics been checked in non-production | no | | | +| ERROR_PAGE_ROUTE | Display error pages to support welsh language | no | | | +| SHOW_CANCELLATION_JOURNEY | Display option to show recurring payments cancellation journey to admin | no | | telesales | +| SHOW_CANCELLATION_JOURNEY_PUBLIC | Display option to show recurring payments cancellation journey to public | no | | websales | ## OS Places address lookup diff --git a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js index cc1f5a6a90..da6b67ee93 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js @@ -70,4 +70,24 @@ describe('journey-definition', () => { ) }) }) + + it('does not route websales users to journey goal even when SHOW_CANCELLATION_JOURNEY_PUBLIC is true', () => { + jest.isolateModules(() => { + process.env.CHANNEL = 'websales' + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'true' + + const journeyDefinition = require('../journey-definition.js').default + const startPage = journeyDefinition.find(page => page.current.page === 'start') + expect(startPage).toEqual( + expect.objectContaining({ + current: { page: 'start' }, + next: { + [CommonResults.OK]: { + page: LICENCE_FOR + } + } + }) + ) + }) + }) }) diff --git a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js index 3da646c348..f5a5080992 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js @@ -70,19 +70,18 @@ describe('route', () => { }) }) -describe('cancellation route journey behaves as expected', () => { +describe('cancellation route journey in websales behaves as expected', () => { beforeEach(jest.clearAllMocks) - - it('adds the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to true', () => { - process.env.SHOW_CANCELLATION_JOURNEY = 'true' + it('adds the cancellation route journey if SHOW_CANCELLATION_JOURNEY_PUBLIC is set to true', () => { + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'true' jest.isolateModules(() => { const routesPaths = require('../routes.js').default.map(route => route.path) expect(routesPaths).toEqual(expect.arrayContaining(getCancelRPURIs())) }) }) - it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to false', () => { - process.env.SHOW_CANCELLATION_JOURNEY = 'false' + it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY_PUBLIC is set to false', () => { + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'false' jest.isolateModules(() => { const routes = require('../routes.js').default const cancelRPURIs = getCancelRPURIs() @@ -91,8 +90,8 @@ describe('cancellation route journey behaves as expected', () => { }) }) - it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is not present', () => { - delete process.env.SHOW_CANCELLATION_JOURNEY + it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY_PUBLIC is not present', () => { + delete process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC jest.isolateModules(() => { const routes = require('../routes.js').default const cancelRPURIs = getCancelRPURIs() diff --git a/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js index b1336ff403..b11303db8d 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/telesales-routes.spec.js @@ -1,7 +1,24 @@ import { setupEnvironment } from '../../__mocks__/openid-client.js' +import { + CANCEL_RP_IDENTIFY, + CANCEL_RP_DETAILS, + CANCEL_RP_CONFIRM, + CANCEL_RP_COMPLETE, + CANCEL_RP_AGREEMENT_NOT_FOUND, + CANCEL_RP_LICENCE_NOT_FOUND, + CANCEL_RP_ALREADY_CANCELLED +} from '../../uri.js' jest.mock('@defra-fish/connectors-lib') - +const getCancelRPURIs = () => [ + CANCEL_RP_IDENTIFY.uri, + CANCEL_RP_DETAILS.uri, + CANCEL_RP_CONFIRM.uri, + CANCEL_RP_COMPLETE.uri, + CANCEL_RP_AGREEMENT_NOT_FOUND.uri, + CANCEL_RP_LICENCE_NOT_FOUND.uri, + CANCEL_RP_ALREADY_CANCELLED.uri +] let TestUtils = null describe('Telesales route handlers', () => { // Start application before running the test case @@ -44,3 +61,35 @@ describe('Telesales route handlers', () => { expect(data.statusCode).toBe(200) }) }) + +describe('cancellation route journey behaves as expected', () => { + beforeEach(jest.clearAllMocks) + + it('adds the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to true', () => { + process.env.SHOW_CANCELLATION_JOURNEY = 'true' + jest.isolateModules(() => { + const telesalesRoutePaths = require('../telesales-routes.js').default.map(route => route.path) + expect(telesalesRoutePaths).toEqual(expect.arrayContaining(getCancelRPURIs())) + }) + }) + + it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is set to false', () => { + process.env.SHOW_CANCELLATION_JOURNEY = 'false' + jest.isolateModules(() => { + const telesalesRoutes = require('../telesales-routes.js').default + const cancelRPURIs = getCancelRPURIs() + const cancelRPRoutes = telesalesRoutes.filter(route => cancelRPURIs.includes(route.path)) + expect(cancelRPRoutes).toHaveLength(0) + }) + }) + + it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY is not present', () => { + delete process.env.SHOW_CANCELLATION_JOURNEY + jest.isolateModules(() => { + const telesalesRoutes = require('../telesales-routes.js').default + const cancelRPURIs = getCancelRPURIs() + const cancelRPRoutes = telesalesRoutes.filter(route => cancelRPURIs.includes(route.path)) + expect(cancelRPRoutes).toHaveLength(0) + }) + }) +}) diff --git a/packages/gafl-webapp-service/src/routes/routes.js b/packages/gafl-webapp-service/src/routes/routes.js index 8a90ffcb77..401dc25e86 100644 --- a/packages/gafl-webapp-service/src/routes/routes.js +++ b/packages/gafl-webapp-service/src/routes/routes.js @@ -84,7 +84,7 @@ const routes = [ ...licenceNotFound ] -if (process.env.SHOW_CANCELLATION_JOURNEY === 'true') { +if (process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC === 'true') { routes.push( ...cancelRPIdentify, ...cancelRPDetails, diff --git a/packages/gafl-webapp-service/src/routes/telesales-routes.js b/packages/gafl-webapp-service/src/routes/telesales-routes.js index 203b48fe7b..4d042602f9 100644 --- a/packages/gafl-webapp-service/src/routes/telesales-routes.js +++ b/packages/gafl-webapp-service/src/routes/telesales-routes.js @@ -1,6 +1,13 @@ import { OIDC_SIGNIN, OIDC_ACCOUNT_DISABLED, OIDC_ROLE_REQUIRED, CONTROLLER } from '../uri.js' import { signIn } from '../handlers/oidc-handler.js' import journeyGoal from '../pages/journey-goal/route.js' +import cancelRPIdentify from '../pages/recurring-payments/cancel/identify/route.js' +import cancelRPDetails from '../pages/recurring-payments/cancel/details/route.js' +import cancelRPConfirm from '../pages/recurring-payments/cancel/confirm/route.js' +import cancelRPComplete from '../pages/recurring-payments/cancel/complete/route.js' +import cancelRPAgreementNotFound from '../pages/recurring-payments/cancel/agreement-not-found/route.js' +import cancelRPLicenceNotFound from '../pages/recurring-payments/cancel/licence-not-found/route.js' +import cancelRPAlreadyCancelled from '../pages/recurring-payments/cancel/already-cancelled/route.js' const telesalesRoutes = [ { @@ -29,4 +36,15 @@ const telesalesRoutes = [ ...journeyGoal ] +if (process.env.SHOW_CANCELLATION_JOURNEY === 'true') { + telesalesRoutes.push( + ...cancelRPIdentify, + ...cancelRPDetails, + ...cancelRPConfirm, + ...cancelRPComplete, + ...cancelRPAgreementNotFound, + ...cancelRPAlreadyCancelled, + ...cancelRPLicenceNotFound + ) +} export default telesalesRoutes From 96a4d0866f88a7b367a8d22ffd4eac29b7c7d032 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:47:30 +0100 Subject: [PATCH 06/12] remove expect chunk --- .../src/routes/__tests__/journey-definition.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js index da6b67ee93..5c4cfc1362 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js @@ -80,7 +80,6 @@ describe('journey-definition', () => { const startPage = journeyDefinition.find(page => page.current.page === 'start') expect(startPage).toEqual( expect.objectContaining({ - current: { page: 'start' }, next: { [CommonResults.OK]: { page: LICENCE_FOR From 0b5ac77d3e92a71842f1133e4c61a39f04e5dd12 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Mon, 27 Apr 2026 16:05:21 +0100 Subject: [PATCH 07/12] Update gafl_webapp.env.example --- docker/env/gafl_webapp.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/env/gafl_webapp.env.example b/docker/env/gafl_webapp.env.example index b3336fe013..a958f32ab0 100644 --- a/docker/env/gafl_webapp.env.example +++ b/docker/env/gafl_webapp.env.example @@ -42,5 +42,5 @@ ENABLE_ANALYTICS_OPT_IN_DEBUGGING=true SHOW_CANCELLATION_JOURNEY=true ## Public Switch -// DEV & TEST envs set to true; TRAIN, PRE, PROD set to false +### DEV & TEST envs set to true; TRAIN, PRE, PROD set to false SHOW_CANCELLATION_JOURNEY_PUBLIC=true From 54e28b2ffe927cb5e8d0e7e7893dff3b49a1a6ce Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Mon, 27 Apr 2026 17:07:11 +0100 Subject: [PATCH 08/12] add rcp cancelltion to session manager --- .../__tests__/session-manager.spec.js | 14 +++++++++----- .../src/session-cache/session-manager.js | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js b/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js index 5ee2f5faa1..74bc52fb90 100644 --- a/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js +++ b/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js @@ -29,7 +29,7 @@ describe('isStaticResource', () => { }) describe('includesRegex', () => { - const regexArray = [/^\/buy\/renew\/identify$/, /^\/renew\/.*$/, /^\/renew-my-licence\/.*$/] + const regexArray = [/^\/buy\/renew\/identify$/, /^\/renew\/.*$/, /^\/renew-my-licence\/.*$/, /^\/buy\/cancel-recurring-payment\/identify$/] it.each([ '/buy/renew/identify', '/renew/ABC123', @@ -39,14 +39,18 @@ describe('includesRegex', () => { '/renew-my-licence/ABC123', '/renew-my-licence/123123', '/renew-my-licence/ABCDEF', - '/renew-my-licence/anytext' + '/renew-my-licence/anytext', + '/buy/cancel-recurring-payment/identify' ])('returns true if one of the regexes is matched %s', async path => { expect(includesRegex(path, regexArray)).toBeTruthy() }) - it.each(['/buy/renew', '/buy', '/rene', '/buy/order-complete'])('returns false if one of the regexes is not matched %s', async path => { - expect(includesRegex(path, regexArray)).toBeFalsy() - }) + it.each(['/buy/renew', '/buy', '/rene', '/buy/order-complete', '/buy/cancel-recurring-payment/details'])( + 'returns false if one of the regexes is not matched %s', + async path => { + expect(includesRegex(path, regexArray)).toBeFalsy() + } + ) }) describe('Use session cookie', () => { diff --git a/packages/gafl-webapp-service/src/session-cache/session-manager.js b/packages/gafl-webapp-service/src/session-cache/session-manager.js index ecf05f9d2f..4582629ceb 100644 --- a/packages/gafl-webapp-service/src/session-cache/session-manager.js +++ b/packages/gafl-webapp-service/src/session-cache/session-manager.js @@ -39,11 +39,12 @@ const agreedHandlerProtectionExemptSet = [ NEW_PRICES.uri ] -// regex for /renew/{referenceNumber?}, /buy/renew/identify, /renew-my-licence/{referenceNumber?}, and static guidance pages +// regex for /renew/{referenceNumber?}, /buy/renew/identify, /renew-my-licence/{referenceNumber?}, /buy/cancel-recurring-payment/identify, and static guidance pages const startProtectionExemptSet = [ /^\/renew\/.*$/, /^\/buy\/renew\/identify$/, /^\/renew-my-licence\/.*$/, + /^\/buy\/cancel-recurring-payment\/identify$/, /^\/guidance\/cookies$/, /^\/guidance\/accessibility-statement$/, /^\/guidance\/privacy-policy$/, From 786075723a204143c1ff051cf3c4a0ff6ae74610 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Mon, 27 Apr 2026 17:12:10 +0100 Subject: [PATCH 09/12] prettier fixe --- .../src/session-cache/__tests__/session-manager.spec.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js b/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js index 74bc52fb90..ef8fcf5ca1 100644 --- a/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js +++ b/packages/gafl-webapp-service/src/session-cache/__tests__/session-manager.spec.js @@ -29,7 +29,12 @@ describe('isStaticResource', () => { }) describe('includesRegex', () => { - const regexArray = [/^\/buy\/renew\/identify$/, /^\/renew\/.*$/, /^\/renew-my-licence\/.*$/, /^\/buy\/cancel-recurring-payment\/identify$/] + const regexArray = [ + /^\/buy\/renew\/identify$/, + /^\/renew\/.*$/, + /^\/renew-my-licence\/.*$/, + /^\/buy\/cancel-recurring-payment\/identify$/ + ] it.each([ '/buy/renew/identify', '/renew/ABC123', From e7bc64fd2f93d6e91a2f499fba06f9f8f058138b Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Mon, 27 Apr 2026 18:08:21 +0100 Subject: [PATCH 10/12] testing testing --- .../src/routes/__tests__/journey-definition.spec.js | 2 +- .../gafl-webapp-service/src/routes/__tests__/routes.spec.js | 4 ++-- packages/gafl-webapp-service/src/routes/routes.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js index 5c4cfc1362..42ea18143a 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js @@ -74,7 +74,7 @@ describe('journey-definition', () => { it('does not route websales users to journey goal even when SHOW_CANCELLATION_JOURNEY_PUBLIC is true', () => { jest.isolateModules(() => { process.env.CHANNEL = 'websales' - process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'true' + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'TRUE' const journeyDefinition = require('../journey-definition.js').default const startPage = journeyDefinition.find(page => page.current.page === 'start') diff --git a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js index f5a5080992..f0a8fd828a 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js @@ -73,7 +73,7 @@ describe('route', () => { describe('cancellation route journey in websales behaves as expected', () => { beforeEach(jest.clearAllMocks) it('adds the cancellation route journey if SHOW_CANCELLATION_JOURNEY_PUBLIC is set to true', () => { - process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'true' + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'TRUE' jest.isolateModules(() => { const routesPaths = require('../routes.js').default.map(route => route.path) expect(routesPaths).toEqual(expect.arrayContaining(getCancelRPURIs())) @@ -81,7 +81,7 @@ describe('cancellation route journey in websales behaves as expected', () => { }) it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY_PUBLIC is set to false', () => { - process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'false' + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'FALSE' jest.isolateModules(() => { const routes = require('../routes.js').default const cancelRPURIs = getCancelRPURIs() diff --git a/packages/gafl-webapp-service/src/routes/routes.js b/packages/gafl-webapp-service/src/routes/routes.js index 401dc25e86..a6f9add86e 100644 --- a/packages/gafl-webapp-service/src/routes/routes.js +++ b/packages/gafl-webapp-service/src/routes/routes.js @@ -84,7 +84,7 @@ const routes = [ ...licenceNotFound ] -if (process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC === 'true') { +if (process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC === 'TRUE') { routes.push( ...cancelRPIdentify, ...cancelRPDetails, From 31dd6aba0f7b26cebaa69227c79eb961e94d73ed Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Tue, 28 Apr 2026 09:38:16 +0100 Subject: [PATCH 11/12] revert caps --- .../src/routes/__tests__/journey-definition.spec.js | 2 +- .../gafl-webapp-service/src/routes/__tests__/routes.spec.js | 4 ++-- packages/gafl-webapp-service/src/routes/routes.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js index 42ea18143a..5c4cfc1362 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/journey-definition.spec.js @@ -74,7 +74,7 @@ describe('journey-definition', () => { it('does not route websales users to journey goal even when SHOW_CANCELLATION_JOURNEY_PUBLIC is true', () => { jest.isolateModules(() => { process.env.CHANNEL = 'websales' - process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'TRUE' + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'true' const journeyDefinition = require('../journey-definition.js').default const startPage = journeyDefinition.find(page => page.current.page === 'start') diff --git a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js index f0a8fd828a..f5a5080992 100644 --- a/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js +++ b/packages/gafl-webapp-service/src/routes/__tests__/routes.spec.js @@ -73,7 +73,7 @@ describe('route', () => { describe('cancellation route journey in websales behaves as expected', () => { beforeEach(jest.clearAllMocks) it('adds the cancellation route journey if SHOW_CANCELLATION_JOURNEY_PUBLIC is set to true', () => { - process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'TRUE' + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'true' jest.isolateModules(() => { const routesPaths = require('../routes.js').default.map(route => route.path) expect(routesPaths).toEqual(expect.arrayContaining(getCancelRPURIs())) @@ -81,7 +81,7 @@ describe('cancellation route journey in websales behaves as expected', () => { }) it('omits the cancellation route journey if SHOW_CANCELLATION_JOURNEY_PUBLIC is set to false', () => { - process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'FALSE' + process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC = 'false' jest.isolateModules(() => { const routes = require('../routes.js').default const cancelRPURIs = getCancelRPURIs() diff --git a/packages/gafl-webapp-service/src/routes/routes.js b/packages/gafl-webapp-service/src/routes/routes.js index a6f9add86e..401dc25e86 100644 --- a/packages/gafl-webapp-service/src/routes/routes.js +++ b/packages/gafl-webapp-service/src/routes/routes.js @@ -84,7 +84,7 @@ const routes = [ ...licenceNotFound ] -if (process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC === 'TRUE') { +if (process.env.SHOW_CANCELLATION_JOURNEY_PUBLIC === 'true') { routes.push( ...cancelRPIdentify, ...cancelRPDetails, From 0d006ed7cf57bc69f629516ddfd228ffc39f5f77 Mon Sep 17 00:00:00 2001 From: laila aleissa <138867360+lailien3@users.noreply.github.com> Date: Tue, 28 Apr 2026 11:40:44 +0100 Subject: [PATCH 12/12] Update gafl_webapp.env.example --- docker/env/gafl_webapp.env.example | 1 - 1 file changed, 1 deletion(-) diff --git a/docker/env/gafl_webapp.env.example b/docker/env/gafl_webapp.env.example index a958f32ab0..9679afafd9 100644 --- a/docker/env/gafl_webapp.env.example +++ b/docker/env/gafl_webapp.env.example @@ -42,5 +42,4 @@ ENABLE_ANALYTICS_OPT_IN_DEBUGGING=true SHOW_CANCELLATION_JOURNEY=true ## Public Switch -### DEV & TEST envs set to true; TRAIN, PRE, PROD set to false SHOW_CANCELLATION_JOURNEY_PUBLIC=true