From 7965be99c7432c0ee8bbeddf9dd5c238b6156366 Mon Sep 17 00:00:00 2001 From: GTVJ Date: Wed, 15 Nov 2023 18:17:09 +0000 Subject: [PATCH] CN-754: Fix issue with Contact Form back links --- .../contact-us/contact-us-controller.ts | 51 +++++++- .../contact-us/index-public-contact-us.njk | 1 - .../tests/contact-us-controller.test.ts | 111 ++++++++++++++++++ ...-us-further-information-controller.test.ts | 7 +- 4 files changed, 164 insertions(+), 6 deletions(-) diff --git a/src/components/contact-us/contact-us-controller.ts b/src/components/contact-us/contact-us-controller.ts index f8c783af15..5f8b759a10 100644 --- a/src/components/contact-us/contact-us-controller.ts +++ b/src/components/contact-us/contact-us-controller.ts @@ -15,6 +15,7 @@ import { logger } from "../../utils/logger"; import { getClientNameThatDirectsAllContactFormSubmissionsToSmartAgent, getServiceDomain, + getSupportLinkUrl, } from "../../config"; import { contactUsServiceSmartAgent } from "./contact-us-service-smart-agent"; @@ -114,9 +115,12 @@ export function contactUsGet(req: Request, res: Response): void { } } + const supportLinkURL = getSupportLinkUrl(); + const options = { referer: referer, fromURL: fromURL, + hrefBack: prepareBackLink(req, supportLinkURL, serviceDomain), ...(getAppSessionId(req.query.appSessionId as string) && { appSessionId: getAppSessionId(req.query.appSessionId as string), }), @@ -125,6 +129,45 @@ export function contactUsGet(req: Request, res: Response): void { return res.render("contact-us/index-public-contact-us.njk", options); } +export function prepareBackLink( + req: Request, + supportLinkURL: string, + serviceDomain: string +) { + let hrefBack: string; + + if (req.path.endsWith(PATH_NAMES.CONTACT_US)) { + hrefBack = supportLinkURL; + } else if (req.path.endsWith(PATH_NAMES.CONTACT_US_FURTHER_INFORMATION)) { + hrefBack = PATH_NAMES.CONTACT_US; + } else if (req.path.endsWith(PATH_NAMES.CONTACT_US_QUESTIONS)) { + if (req.query.fromURL && req.query.theme === ZENDESK_THEMES.ID_CHECK_APP) { + hrefBack = supportLinkURL; + } else { + hrefBack = PATH_NAMES.CONTACT_US_FURTHER_INFORMATION; + } + } else { + hrefBack = PATH_NAMES.CONTACT_US; + } + + const queryParams = new URLSearchParams(); + + if (validateReferer(req.query.fromURL as string, serviceDomain)) { + queryParams.append("fromURL", req.query.fromURL as string); + } + + if ( + req.query.theme && + Object.values(ZENDESK_THEMES).includes(req.query.theme as string) + ) { + queryParams.append("theme", req.query.theme as string); + } + + return queryParams.toString().length > 0 + ? hrefBack + "?" + queryParams.toString() + : hrefBack; +} + export function contactUsGetFromTriagePage(req: Request, res: Response): void { const queryParams = new URLSearchParams({ ...(validateAppId(req.query.appSessionId as string) && { @@ -261,13 +304,13 @@ export function contactUsFormPost(req: Request, res: Response): void { } export function furtherInformationGet(req: Request, res: Response): void { + const supportLinkURL = getSupportLinkUrl(); + const backLinkHref = prepareBackLink(req, supportLinkURL, serviceDomain); + if (!req.query.theme) { return res.redirect(PATH_NAMES.CONTACT_US); } - const backLinkHref = - validateReferer(req.get("referer"), serviceDomain) || PATH_NAMES.CONTACT_US; - if (isAppJourney(req.query.appSessionId as string)) { return res.render("contact-us/further-information/index.njk", { theme: req.query.theme, @@ -328,6 +371,8 @@ export function setContactFormSubmissionUrlBasedOnClientName( } export function contactUsQuestionsGet(req: Request, res: Response): void { + const supportLinkURL = getSupportLinkUrl(); + const formSubmissionUrl = setContactFormSubmissionUrlBasedOnClientName( req?.session?.client?.name, getClientNameThatDirectsAllContactFormSubmissionsToSmartAgent() diff --git a/src/components/contact-us/index-public-contact-us.njk b/src/components/contact-us/index-public-contact-us.njk index 54ebcc2d95..b7c7887c12 100644 --- a/src/components/contact-us/index-public-contact-us.njk +++ b/src/components/contact-us/index-public-contact-us.njk @@ -6,7 +6,6 @@ {% from "govuk/components/warning-text/macro.njk" import govukWarningText %} {% set showBack = true %} -{% set hrefBack = referer %} {% set pageTitleName = 'pages.contactUsPublic.title' | translateEnOnly %} {% block content %} diff --git a/src/components/contact-us/tests/contact-us-controller.test.ts b/src/components/contact-us/tests/contact-us-controller.test.ts index a1d54b590d..6a03637f77 100644 --- a/src/components/contact-us/tests/contact-us-controller.test.ts +++ b/src/components/contact-us/tests/contact-us-controller.test.ts @@ -16,6 +16,7 @@ import { contactUsGetFromTriagePage, setContactFormSubmissionUrlBasedOnClientName, validateReferer, + prepareBackLink, } from "../contact-us-controller"; import { PATH_NAMES, @@ -24,6 +25,7 @@ import { CONTACT_US_REFERER_ALLOWLIST, } from "../../../app.constants"; import { RequestGet, ResponseRedirect } from "../../../types"; +import { getServiceDomain, getSupportLinkUrl } from "../../../config"; describe("contact us controller", () => { let sandbox: sinon.SinonSandbox; @@ -35,6 +37,7 @@ describe("contact us controller", () => { sandbox = sinon.createSandbox(); req = { + path: PATH_NAMES.CONTACT_US, body: {}, query: {}, headers: {}, @@ -399,3 +402,111 @@ describe("appErrorCode and appSessionId query parameters", () => { }); }); }); + +describe("prepareBackLink", () => { + let sandbox: sinon.SinonSandbox; + let req: Partial; + let res: Partial; + let supportLinkURL: string; + let serviceDomain: string; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + + serviceDomain = getServiceDomain(); + + req = { + url: "", + path: "", + body: {}, + query: {}, + headers: {}, + get: sandbox.fake() as unknown as RequestGet, + }; + res = { + render: sandbox.fake(), + redirect: sandbox.fake() as unknown as ResponseRedirect, + locals: {}, + }; + + supportLinkURL = getSupportLinkUrl(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it("should return the supportLinkURL when the req.path ends with the CONTACT_US path", () => { + req.path = PATH_NAMES.CONTACT_US; + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(supportLinkURL); + }); + + it("should return the CONTACT_US path when the req.path ends with the CONTACT_US_FURTHER_INFORMATION path", () => { + req.path = PATH_NAMES.CONTACT_US_FURTHER_INFORMATION; + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(PATH_NAMES.CONTACT_US); + }); + + it("should return the CONTACT_US_FURTHER_INFORMATION path when the req.path ends with the CONTACT_US_QUESTIONS path", () => { + req.path = PATH_NAMES.CONTACT_US_QUESTIONS; + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(PATH_NAMES.CONTACT_US_FURTHER_INFORMATION); + }); + + it("should return the supportLinkURL with a fromURL parameter when one is included in the req.url", () => { + req.query.fromURL = `https://${getServiceDomain()}${PATH_NAMES.CONTACT_US}`; + const fromURL = + "?fromURL=" + + encodeURIComponent( + `https://${getServiceDomain()}${PATH_NAMES.CONTACT_US}` + ); + + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(supportLinkURL + fromURL); + }); + + it("should omit the fromURL from the backlink where the one included in req.url is not valid", () => { + req.url = `https://${getServiceDomain()}${ + PATH_NAMES.CONTACT_US + }?fromURL=${encodeURIComponent("https://www.example.com")}`; + + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(supportLinkURL); + }); + + it("should include the `theme` where the theme is valid", () => { + req.query.theme = ZENDESK_THEMES.ACCOUNT_CREATION; + req.url = `https://${getServiceDomain()}${PATH_NAMES.CONTACT_US}?theme=${ + ZENDESK_THEMES.ACCOUNT_CREATION + }`; + + const theme = `?theme=${ZENDESK_THEMES.ACCOUNT_CREATION}`; + + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(supportLinkURL + theme); + }); + + describe("dynamic back links on CONTACT_US_FURTHER_INFORMATION", () => { + it("should return the CONTACT_US path when the", () => { + req.path = PATH_NAMES.CONTACT_US_FURTHER_INFORMATION; + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(PATH_NAMES.CONTACT_US); + }); + it("should return the `supportLinkURL` if there is a fromURL and the theme is ID_CHECK_APP", () => { + req.path = PATH_NAMES.CONTACT_US_FURTHER_INFORMATION; + req.query.fromURL = PATH_NAMES.DOC_CHECKING_APP; + req.query.theme = ZENDESK_THEMES.ID_CHECK_APP; + expect( + prepareBackLink(req as Request, supportLinkURL, serviceDomain) + ).to.equal(`${supportLinkURL}?theme=${ZENDESK_THEMES.ID_CHECK_APP}`); + }); + }); +}); diff --git a/src/components/contact-us/tests/contact-us-further-information-controller.test.ts b/src/components/contact-us/tests/contact-us-further-information-controller.test.ts index 25b362842c..bc301b2223 100644 --- a/src/components/contact-us/tests/contact-us-further-information-controller.test.ts +++ b/src/components/contact-us/tests/contact-us-further-information-controller.test.ts @@ -35,6 +35,7 @@ describe("contact us further information controller", () => { it("should render signing in further information if a problem signing in to your account radio option was chosen", () => { req.query.theme = ZENDESK_THEMES.SIGNING_IN; req.query.referer = REFERER; + req.path = PATH_NAMES.CONTACT_US_FURTHER_INFORMATION; furtherInformationGet(req as Request, res as Response); expect(res.render).to.have.calledWith( @@ -42,12 +43,13 @@ describe("contact us further information controller", () => { { theme: "signing_in", referer: REFERER, - hrefBack: PATH_NAMES.CONTACT_US, + hrefBack: `${PATH_NAMES.CONTACT_US}?theme=${ZENDESK_THEMES.SIGNING_IN}`, } ); }); it("should render account creation further information if a creating an account radio option was chosen", () => { + req.path = PATH_NAMES.CONTACT_US_FURTHER_INFORMATION; req.query.theme = ZENDESK_THEMES.ACCOUNT_CREATION; req.query.referer = REFERER; furtherInformationGet(req as Request, res as Response); @@ -57,12 +59,13 @@ describe("contact us further information controller", () => { { theme: "account_creation", referer: REFERER, - hrefBack: PATH_NAMES.CONTACT_US, + hrefBack: `${PATH_NAMES.CONTACT_US}?theme=${ZENDESK_THEMES.ACCOUNT_CREATION}`, } ); }); it("should redirect to contact-us when no theme is present in request", () => { + req.path = PATH_NAMES.CONTACT_US_FURTHER_INFORMATION; furtherInformationGet(req as Request, res as Response); expect(res.redirect).to.have.calledWith("/contact-us");