Skip to content

Commit b07991a

Browse files
authored
Merge pull request #869 from UKHSA-Internal/feature/CDD-3084-error-page
Feature/cdd 3084 error page
2 parents cfbdf8c + 0b80e32 commit b07991a

File tree

19 files changed

+625
-67
lines changed

19 files changed

+625
-67
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { expect, Locator, type Page } from '@playwright/test'
2+
3+
export class AuthErrorPage {
4+
readonly page: Page
5+
readonly heading: Locator
6+
readonly errorLine: Locator
7+
readonly errorText: Locator
8+
readonly subText: Locator
9+
readonly backButton: Locator
10+
readonly errorBorder: Locator
11+
readonly relatedLinksSidebar: Locator
12+
readonly relatedLinksFooter: Locator
13+
readonly announcements: Locator
14+
15+
constructor(page: Page) {
16+
this.page = page
17+
this.heading = this.page.locator('main').getByRole('heading', { level: 1 })
18+
this.errorLine = this.page.locator('.text-red').first()
19+
this.errorText = this.page.locator('.border-l-red').locator('[data-testid="rich-text"]').first()
20+
this.subText = this.page.locator('main').locator('[data-testid="rich-text"]').nth(1)
21+
this.backButton = this.page.getByRole('link', { name: /back/i })
22+
this.errorBorder = this.page.locator('.border-l-\\[9px\\].border-l-red')
23+
this.relatedLinksSidebar = this.page.locator('.govuk-grid-column-one-quarter-from-desktop')
24+
this.relatedLinksFooter = this.page.locator('main > div:last-child')
25+
this.announcements = this.page.locator('[data-testid="announcements"]')
26+
}
27+
28+
async goto(slug: string = 'authentication-error') {
29+
await this.page.goto(`/${slug}`)
30+
}
31+
32+
async isAuthErrorPage(slug: string = 'authentication-error') {
33+
await expect(this.page).toHaveURL(new RegExp(`/${slug}/?$`))
34+
}
35+
36+
async checkHeadingExists(expectedText: string) {
37+
await expect(this.heading).toBeVisible()
38+
await expect(this.heading).toHaveText(expectedText)
39+
}
40+
41+
async checkErrorLineExists(expectedText: string) {
42+
await expect(this.errorLine).toBeVisible()
43+
await expect(this.errorLine).toHaveText(expectedText)
44+
}
45+
46+
async checkErrorTextExists() {
47+
await expect(this.errorText).toBeVisible()
48+
}
49+
50+
async checkSubTextExists() {
51+
await expect(this.subText).toBeVisible()
52+
}
53+
54+
async checkBackButtonExists() {
55+
await expect(this.backButton).toBeVisible()
56+
}
57+
58+
async checkBackButtonHasCorrectHref() {
59+
await expect(this.backButton).toHaveAttribute('href', '/start')
60+
}
61+
62+
async clickBackButton() {
63+
await this.backButton.click()
64+
}
65+
66+
async checkErrorBorderStyling() {
67+
await expect(this.errorBorder).toBeVisible()
68+
await expect(this.errorBorder).toHaveClass(/border-l-\[9px\]/)
69+
await expect(this.errorBorder).toHaveClass(/border-l-red/)
70+
await expect(this.errorBorder).toHaveClass(/pl-9/)
71+
}
72+
73+
async checkRelatedLinksSidebarExists() {
74+
await expect(this.relatedLinksSidebar).toBeVisible()
75+
}
76+
77+
async checkRelatedLinksSidebarNotExists() {
78+
await expect(this.relatedLinksSidebar).not.toBeVisible()
79+
}
80+
81+
async checkRelatedLinksFooterExists() {
82+
const footerLinks = this.page.locator('[data-testid="related-links-footer"]')
83+
await expect(footerLinks).toBeVisible()
84+
}
85+
86+
async checkRelatedLinksFooterNotExists() {
87+
const footerLinks = this.page.locator('[data-testid="related-links-footer"]')
88+
await expect(footerLinks).not.toBeVisible()
89+
}
90+
91+
async checkAnnouncementsExist() {
92+
await expect(this.announcements).toBeVisible()
93+
}
94+
95+
async checkAnnouncementsCount(expectedCount: number) {
96+
const announcements = this.page.locator('[role="alert"]')
97+
await expect(announcements).toHaveCount(expectedCount)
98+
}
99+
100+
async hasMainContent() {
101+
await expect(this.page.locator('main')).toBeVisible()
102+
}
103+
104+
async checkBackButtonIcon() {
105+
const svg = this.backButton.locator('svg')
106+
await expect(svg).toBeVisible()
107+
await expect(svg).toHaveAttribute('width', '20')
108+
await expect(svg).toHaveAttribute('height', '20')
109+
}
110+
111+
async checkPageContainsText(text: string) {
112+
await expect(this.page.locator('main')).toContainText(text)
113+
}
114+
115+
async checkRelatedLinksCount(count: number) {
116+
const links = this.page.locator('[data-testid*="related-links"] a')
117+
await expect(links).toHaveCount(count)
118+
}
119+
120+
async clickRelatedLink(linkText: string) {
121+
await this.page.getByRole('link', { name: linkText }).click()
122+
}
123+
}

public/locales/en/auth.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"signOutButton": "Sign out",
33
"signInButton": "Sign in",
4+
"backButtonText": "Back",
45
"startPage": {
56
"signOutBannerTitle": "Success",
67
"signOutBannerHeading": "You've been signed out",

src/api/requests/cms/getPage.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ beforeEach(() => {
1313
jest.clearAllMocks()
1414
})
1515

16-
test('Returns a full page from thge cms by id', async () => {
16+
test('Returns a full page from the cms by id', async () => {
1717
jest.mocked(client).mockResolvedValueOnce({ data: dashboardMock, status: 200 })
1818

1919
const result = await getPage(dashboardMock.id)

src/api/requests/cms/getPage.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type PageTypeToDataMap = {
2525
[PageType.MetricsParent]: typeof WithMetricsParentData
2626
[PageType.MetricsChild]: typeof WithMetricsChildData
2727
[PageType.Acknowledgement]: typeof WithAcknowledgementData
28+
[PageType.AuthError]: typeof WithErrorData
2829
}
2930

3031
const SharedPageData = z.object({
@@ -186,6 +187,17 @@ const WithAcknowledgementData = SharedPageData.omit({
186187
seo_priority: z.coerce.number().or(fallback(0.5)).optional(),
187188
})
188189

190+
const WithErrorData = SharedPageData.extend({
191+
error_line: z.string(),
192+
error_text: z.string(),
193+
sub_text: z.string(),
194+
meta: Meta.extend({
195+
type: z.literal('error.ErrorPage'),
196+
}),
197+
related_links: RelatedLinks,
198+
related_links_layout: RelatedLinksLayout.or(fallback<RelatedLinksLayout>('Sidebar')),
199+
})
200+
189201
export const responseSchema = z.union([
190202
WithLandingData,
191203
withFeedbackData,
@@ -198,6 +210,7 @@ export const responseSchema = z.union([
198210
WithMetricsParentData,
199211
WithMetricsChildData,
200212
WithAcknowledgementData,
213+
WithErrorData,
201214
])
202215

203216
/**

src/api/requests/cms/getPages.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export enum PageType {
4141
MetricsParent = 'metrics_documentation.MetricsDocumentationParentPage',
4242
MetricsChild = 'metrics_documentation.MetricsDocumentationChildEntry',
4343
Acknowledgement = 'acknowledgement.AcknowledgementPage',
44+
AuthError = 'error.ErrorPage',
4445
}
4546

4647
const page = z.object({
@@ -107,7 +108,7 @@ export const metricsChildResponseSchema = responseSchema.extend({
107108
})
108109
),
109110
is_public: z.boolean(),
110-
page_classification: DataClassification.or(fallback(undefined))
111+
page_classification: DataClassification.or(fallback(undefined)),
111112
})
112113
),
113114
})

src/app/(auth)/auth/error/layout.tsx

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/app/(auth)/auth/error/page.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import React from 'react'
1+
import { redirect } from 'next/navigation'
22

3-
import ErrorMessage from '@/app/components/ui/ukhsa/ErrorMessage/ErrorMessage'
4-
5-
export default async function Page() {
6-
return <ErrorMessage />
3+
export default function Page() {
4+
redirect('/authentication-error')
75
}

src/app/(cms)/[[...slug]]/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ComponentType } from 'react'
44

55
import { PageType } from '@/api/requests/cms/getPages'
66
import AcknowledgementPage from '@/app/components/cms/pages/Acknowledgement'
7+
import AuthErrorPage from '@/app/components/cms/pages/AuthError'
78
import CompositePage from '@/app/components/cms/pages/Composite'
89
import FeedbackPage from '@/app/components/cms/pages/Feedback'
910
import LandingPage from '@/app/components/cms/pages/Landing'
@@ -52,6 +53,7 @@ const PageComponents: Record<PageType, ComponentType<PageComponentBaseProps>> =
5253
[PageType.WhatsNewParent]: WhatsNewParentPage,
5354
[PageType.WhatsNewChild]: WhatsNewChildPage,
5455
[PageType.Acknowledgement]: AcknowledgementPage,
56+
[PageType.AuthError]: AuthErrorPage,
5557
}
5658

5759
/**

src/app/__snapshots__/sitemap.spec.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ exports[`test sitemap function that builds a list of URLs for search engines 1`]
1111
"/access-our-data/what-is-an-api",
1212
"/accessibility-statement/",
1313
"/acknowledgement/",
14+
"/authentication-error/",
1415
"/browse",
1516
"/bulk-downloads/",
1617
"/compliance/",

0 commit comments

Comments
 (0)