From 7194ba98b0ee710e583ce0123b248fd0953bf0d5 Mon Sep 17 00:00:00 2001 From: Madhura Date: Mon, 30 Mar 2026 16:56:24 +0100 Subject: [PATCH 1/6] Add basic logic for populating subject --- src/app/components/pages/NotFound.tsx | 20 ++++++++++++++++++-- src/test/pages/NotFound.test.tsx | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/test/pages/NotFound.test.tsx diff --git a/src/app/components/pages/NotFound.tsx b/src/app/components/pages/NotFound.tsx index 44b6232f12..d02a728711 100644 --- a/src/app/components/pages/NotFound.tsx +++ b/src/app/components/pages/NotFound.tsx @@ -5,14 +5,30 @@ import { TitleAndBreadcrumb } from "../elements/TitleAndBreadcrumb"; export const NotFound = () => { const { pathname, state } = useLocation<{ overridePathname?: string }>(); + console.log(state); + const missingPageId = (state && state.overridePathname) || pathname; + const contactSubject = encodeURIComponent(`Page not found "${missingPageId}"`); return (

- {"We're sorry, page not found: "} - {(state && state.overridePathname) || pathname} + {"Sorry, we couldn't find the page you were looking for: "} + {missingPageId} +
+
+ {"If you entered a web address, check it was correct."} +
+
+ {"If you pasted the web address, check you copied the entire address."} +
+
+ {"If the web address is correct or you selected a link or button, please"}{" "} + + contact us + {" "} + {"to let us know."}

diff --git a/src/test/pages/NotFound.test.tsx b/src/test/pages/NotFound.test.tsx new file mode 100644 index 0000000000..086bc81a3f --- /dev/null +++ b/src/test/pages/NotFound.test.tsx @@ -0,0 +1,15 @@ +import { screen } from "@testing-library/react"; +import { renderTestEnvironment } from "../utils"; +import { NotFound } from "../../app/components/pages/NotFound"; + +describe("NotFound page", () => { + it("adds a prefilled subject when linking to contact us", () => { + renderTestEnvironment({ + PageComponent: NotFound, + initialRouteEntries: ["/missing-page"], + }); + + const contactLink = screen.getByRole("link", { name: /contact us/i }); + expect(contactLink).toHaveAttribute("href", '/contact?subject=Page%20not%20found%20%22%2Fmissing-page%22'); + }); +}); From d2fa58b90bbc5699a7f28b1205dd2a11dca3a3c3 Mon Sep 17 00:00:00 2001 From: Madhura Date: Wed, 1 Apr 2026 15:30:54 +0100 Subject: [PATCH 2/6] Add logic for populating message field same as on other page --- src/app/components/pages/Contact.tsx | 8 ++++++++ src/app/components/pages/NotFound.tsx | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/app/components/pages/Contact.tsx b/src/app/components/pages/Contact.tsx index 0ea91c6c3b..cdd190f3a2 100644 --- a/src/app/components/pages/Contact.tsx +++ b/src/app/components/pages/Contact.tsx @@ -64,12 +64,20 @@ const determineUrlQueryPresets = (user?: Immutable | null) => { } }; + const setPageNotFoundPresets = () => { + presetSubject = `Page not found "${urlQuery.page ?? ""}"`; + presetUrl = `Page link: ${urlQuery.url}`; + presetPlaceholder = "Please describe how you reached this page and what you expected to see."; + }; + if (urlQuery?.preset == "teacherRequest" && user?.loggedIn && !isTeacherOrAbove(user)) { setTeacherRequestPresets(user); } else if (urlQuery?.preset == "accountDeletion" && user?.loggedIn) { setAccountDeletionPresets(user); } else if (urlQuery?.preset == "contentProblem") { setContentProblemPresets(); + } else if (urlQuery?.preset == "pageNotFound") { + setPageNotFoundPresets(); } return [ diff --git a/src/app/components/pages/NotFound.tsx b/src/app/components/pages/NotFound.tsx index d02a728711..86310e5539 100644 --- a/src/app/components/pages/NotFound.tsx +++ b/src/app/components/pages/NotFound.tsx @@ -5,13 +5,14 @@ import { TitleAndBreadcrumb } from "../elements/TitleAndBreadcrumb"; export const NotFound = () => { const { pathname, state } = useLocation<{ overridePathname?: string }>(); - console.log(state); const missingPageId = (state && state.overridePathname) || pathname; - const contactSubject = encodeURIComponent(`Page not found "${missingPageId}"`); + const contactUrl = + `/contact?preset=pageNotFound&page=${encodeURIComponent(missingPageId)}` + + `&url=${encodeURIComponent(window.location.href)}`; return (
- +

{"Sorry, we couldn't find the page you were looking for: "} @@ -25,7 +26,7 @@ export const NotFound = () => {

{"If the web address is correct or you selected a link or button, please"}{" "} - + contact us {" "} {"to let us know."} From 08d9cbb520935b7a1c72d67b9a01c38aee132472 Mon Sep 17 00:00:00 2001 From: Madhura Date: Thu, 2 Apr 2026 13:09:45 +0100 Subject: [PATCH 3/6] Add tests --- src/test/pages/Contact.test.tsx | 20 ++++++++++++++++++++ src/test/pages/NotFound.test.tsx | 7 +++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/test/pages/Contact.test.tsx b/src/test/pages/Contact.test.tsx index 990c100010..a0de67c428 100644 --- a/src/test/pages/Contact.test.tsx +++ b/src/test/pages/Contact.test.tsx @@ -213,6 +213,26 @@ describe("Contact form presets", () => { ); }); + it("shows page-not-found subject when pageNotFound preset is provided", async () => { + renderContactUs(); + setLocation("?preset=pageNotFound&page=%2Fmissing-page"); + const { firstName, subject } = formFields; + await waitFor(() => expect(firstName()).not.toHaveValue("")); + expect(subject()).toHaveValue('Page not found "/missing-page"'); + }); + + it("includes the page URL in the message if submitting a form with pageNotFound preset", async () => { + renderContactUs(); + setLocation("?preset=pageNotFound&page=%2Fmissing-page&url=https://example.com/missing-page"); + const { firstName, message } = formFields; + await waitFor(() => expect(firstName()).not.toHaveValue("")); + await userEvent.type(message(), "Test message"); + await clickButton("Submit"); + expect(contactFormSubmitSpy).toHaveBeenCalledWith( + expect.objectContaining({ message: expect.stringContaining("https://example.com/missing-page") }), + ); + }); + const testFields = ["subject", "message"]; it.each(testFields)("includes a custom %s if provided in the URL", async (field) => { diff --git a/src/test/pages/NotFound.test.tsx b/src/test/pages/NotFound.test.tsx index 086bc81a3f..05fc12c26f 100644 --- a/src/test/pages/NotFound.test.tsx +++ b/src/test/pages/NotFound.test.tsx @@ -3,13 +3,16 @@ import { renderTestEnvironment } from "../utils"; import { NotFound } from "../../app/components/pages/NotFound"; describe("NotFound page", () => { - it("adds a prefilled subject when linking to contact us", () => { + it("links to contact form using pageNotFound preset and page id", () => { renderTestEnvironment({ PageComponent: NotFound, initialRouteEntries: ["/missing-page"], }); const contactLink = screen.getByRole("link", { name: /contact us/i }); - expect(contactLink).toHaveAttribute("href", '/contact?subject=Page%20not%20found%20%22%2Fmissing-page%22'); + expect(contactLink).toHaveAttribute( + "href", + expect.stringContaining("/contact?preset=pageNotFound&page=%2Fmissing-page&url="), + ); }); }); From 95b3f9d4cf06e0437125ee009cc6f0108f7d5e8a Mon Sep 17 00:00:00 2001 From: Madhura Date: Wed, 8 Apr 2026 11:30:05 +0100 Subject: [PATCH 4/6] Fix the sonarqube issue --- src/app/components/pages/NotFound.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/pages/NotFound.tsx b/src/app/components/pages/NotFound.tsx index 86310e5539..194e9808af 100644 --- a/src/app/components/pages/NotFound.tsx +++ b/src/app/components/pages/NotFound.tsx @@ -5,7 +5,7 @@ import { TitleAndBreadcrumb } from "../elements/TitleAndBreadcrumb"; export const NotFound = () => { const { pathname, state } = useLocation<{ overridePathname?: string }>(); - const missingPageId = (state && state.overridePathname) || pathname; + const missingPageId = state?.overridePathname || pathname; const contactUrl = `/contact?preset=pageNotFound&page=${encodeURIComponent(missingPageId)}` + `&url=${encodeURIComponent(window.location.href)}`; From 677de7cad77c001cd400b5b644c38cc82e4613b3 Mon Sep 17 00:00:00 2001 From: Madhura Date: Wed, 8 Apr 2026 11:47:06 +0100 Subject: [PATCH 5/6] Implement sonarqube suggestion to replace window with globalThis --- src/app/components/pages/NotFound.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/pages/NotFound.tsx b/src/app/components/pages/NotFound.tsx index 194e9808af..1ac2470a04 100644 --- a/src/app/components/pages/NotFound.tsx +++ b/src/app/components/pages/NotFound.tsx @@ -8,7 +8,7 @@ export const NotFound = () => { const missingPageId = state?.overridePathname || pathname; const contactUrl = `/contact?preset=pageNotFound&page=${encodeURIComponent(missingPageId)}` + - `&url=${encodeURIComponent(window.location.href)}`; + `&url=${encodeURIComponent(globalThis.location.href)}`; return (
From dac653c8275c3071e86114e696ffe9e7b2dfe055 Mon Sep 17 00:00:00 2001 From: Madhura Date: Wed, 8 Apr 2026 12:20:46 +0100 Subject: [PATCH 6/6] Add small font --- src/app/components/pages/NotFound.tsx | 28 +++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/app/components/pages/NotFound.tsx b/src/app/components/pages/NotFound.tsx index 1ac2470a04..e7e42b09e4 100644 --- a/src/app/components/pages/NotFound.tsx +++ b/src/app/components/pages/NotFound.tsx @@ -15,21 +15,19 @@ export const NotFound = () => {

- {"Sorry, we couldn't find the page you were looking for: "} - {missingPageId} -
-
- {"If you entered a web address, check it was correct."} -
-
- {"If you pasted the web address, check you copied the entire address."} -
-
- {"If the web address is correct or you selected a link or button, please"}{" "} - - contact us - {" "} - {"to let us know."} +

+ {"Sorry, we couldn't find the page you were looking for: "} + {missingPageId} +

+

{"If you entered a web address, check it was correct."}

+

{"If you pasted the web address, check you copied the entire address."}

+

+ {"If the web address is correct or you selected a link or button, please"}{" "} + + contact us + {" "} + {"to let us know."} +