Skip to content

Commit f921d66

Browse files
committed
Update all e2e tests to use POM static .ini() methods so that we can inject a variable on global window for use in determining whether client script is running in e2e environment
1 parent 724c798 commit f921d66

56 files changed

Lines changed: 800 additions & 1006 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.vscode/settings.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"jsdom",
4747
"KHTML",
4848
"koko",
49+
"labelledby",
4950
"LIMS",
5051
"Linkify",
5152
"liradb",

‎src/components/Carousel/client.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,10 @@ class CarouselInstance {
189189
private nextBtn: HTMLButtonElement | null
190190
private viewport: HTMLElement | null
191191
private dotsContainer: HTMLElement | null
192+
private container: HTMLElement
192193

193194
constructor(container: HTMLElement, _instanceId: number) {
195+
this.container = container
194196
this.prevBtn = container.querySelector('.embla__button--prev')
195197
this.nextBtn = container.querySelector('.embla__button--next')
196198
this.viewport = container.querySelector('.embla__viewport')
@@ -226,6 +228,9 @@ class CarouselInstance {
226228
// Initialize Embla Carousel with Autoplay plugin
227229
this.emblaApi = EmblaCarousel(this.viewport, options, [this.autoplayPlugin])
228230

231+
// Expose API to container element for testing
232+
;(this.container as HTMLElement & { __emblaApi__?: EmblaCarouselType }).__emblaApi__ = this.emblaApi
233+
229234
this.setupNavigationButtons()
230235
this.setupDotsNavigation()
231236
} catch (error) {

‎src/components/Consent/Banner/client.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class ConsentBannerElement extends LitElement {
4040
private trapFocusHandler: (((_event: Event) => void) | null) = null
4141

4242
// Track View Transitions
43-
private isInitialized = false
43+
public isInitialized = false
4444
private static isModalCurrentlyVisible = false
4545

4646
/**

‎test/e2e/helpers/pageObjectModels/BasePage.ts‎

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class BasePage {
2020
public errors404: string[] = []
2121
public navigationItems = navigationItems
2222

23-
constructor(protected readonly _page: Page) {
23+
protected constructor(protected readonly _page: Page) {
2424
this.page = _page
2525

2626
// IMPORTANT: Register listener early
@@ -29,6 +29,24 @@ export class BasePage {
2929
})
3030
}
3131

32+
static async init(page: Page): Promise<BasePage> {
33+
await page.addInitScript(() => {
34+
window.isPlaywrightControlled = true
35+
})
36+
const instance = new BasePage(page)
37+
await instance.onInit()
38+
return instance
39+
}
40+
41+
/**
42+
* Hook for subclasses to perform custom initialization
43+
* Called after construction but before the instance is returned from init()
44+
* Override this in subclasses to add custom setup logic
45+
*/
46+
protected async onInit(): Promise<void> {
47+
// Base implementation does nothing - subclasses can override
48+
}
49+
3250
/**
3351
* ================================================================
3452
*
@@ -102,11 +120,18 @@ export class BasePage {
102120
} /**
103121
* Evaluate JS script in the browser
104122
*/
123+
async evaluate<R, Arg = unknown>(
124+
pageFunction: (arg: Arg) => R | Promise<R>,
125+
arg: Arg
126+
): Promise<R>
105127
async evaluate<R>(
106-
pageFunction: () => R | Promise<R>,
107-
arg?: unknown
128+
pageFunction: () => R | Promise<R>
129+
): Promise<R>
130+
async evaluate<R, Arg = unknown>(
131+
pageFunction: ((arg: Arg) => R | Promise<R>) | (() => R | Promise<R>),
132+
arg?: Arg
108133
): Promise<R> {
109-
return await this._page.evaluate(pageFunction, arg)
134+
return await this._page.evaluate(pageFunction as any, arg)
110135
}
111136

112137
/**
@@ -704,15 +729,6 @@ export class BasePage {
704729
* ================================================================
705730
*/
706731

707-
/**
708-
* Throw errors that are normally handled internally
709-
*/
710-
async disableErrorBoundary(): Promise<void> {
711-
await this._page.addInitScript(() => {
712-
window._throw = false
713-
})
714-
}
715-
716732
/**
717733
* Returns up to (currently) 200 last uncaught exceptions from this page
718734
*/

‎test/e2e/helpers/pageObjectModels/ComponentPersistencePage.ts‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,24 @@ export interface PersistenceVerificationData {
2828
export class ComponentPersistencePage extends BasePage {
2929
private consoleMessages: CapturedConsoleMessage[] = []
3030

31-
constructor(page: Page) {
31+
protected constructor(page: Page) {
3232
super(page)
33+
}
34+
35+
static override async init(page: Page): Promise<ComponentPersistencePage> {
36+
await page.addInitScript(() => {
37+
window.isPlaywrightControlled = true
38+
})
39+
const instance = new ComponentPersistencePage(page)
40+
await instance.onInit()
41+
return instance
42+
}
43+
44+
/**
45+
* Custom initialization - sets up console message capture
46+
*/
47+
protected override async onInit(): Promise<void> {
48+
await super.onInit()
3349
this.setupConsoleCapture()
3450
}
3551

‎test/e2e/helpers/pageObjectModels/NewsletterPage.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,19 @@ export class NewsletterPage extends BasePage {
1414
private readonly messageSelector = '#newsletter-message'
1515
private readonly buttonSpinnerSelector = '#button-spinner'
1616

17-
constructor(page: Page) {
17+
protected constructor(page: Page) {
1818
super(page)
1919
}
2020

21+
static override async init(page: Page): Promise<NewsletterPage> {
22+
await page.addInitScript(() => {
23+
window.isPlaywrightControlled = true
24+
})
25+
const instance = new NewsletterPage(page)
26+
await instance.onInit()
27+
return instance
28+
}
29+
2130
/**
2231
* Navigate to home page where newsletter form is located
2332
*/

‎test/e2e/helpers/pageObjectModels/PerformancePage.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,19 @@ import { expect } from '@playwright/test'
77
import { BasePage } from '@test/e2e/helpers'
88

99
export class PerformancePage extends BasePage {
10-
constructor(page: Page) {
10+
protected constructor(page: Page) {
1111
super(page)
1212
}
1313

14+
static override async init(page: Page): Promise<PerformancePage> {
15+
await page.addInitScript(() => {
16+
window.isPlaywrightControlled = true
17+
})
18+
const instance = new PerformancePage(page)
19+
await instance.onInit()
20+
return instance
21+
}
22+
1423
/**
1524
* ================================================================
1625
* Core Web Vitals Methods

‎test/e2e/helpers/pageObjectModels/PwaPage.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,19 @@ import { expect } from '@playwright/test'
77
import { BasePage } from '@test/e2e/helpers'
88

99
export class PwaPage extends BasePage {
10-
constructor(page: Page) {
10+
protected constructor(page: Page) {
1111
super(page)
1212
}
1313

14+
static override async init(page: Page): Promise<PwaPage> {
15+
await page.addInitScript(() => {
16+
window.isPlaywrightControlled = true
17+
})
18+
const instance = new PwaPage(page)
19+
await instance.onInit()
20+
return instance
21+
}
22+
1423
/**
1524
* ================================================================
1625
* Navigation Methods

‎test/e2e/specs/01-smoke/critical-paths.spec.ts‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { BasePage, test, expect } from '@test/e2e/helpers'
77

88
test.describe('Critical Paths @smoke', () => {
99
test('@ready all main navigation pages are accessible', async ({ page: playwrightPage }) => {
10-
const page = new BasePage(playwrightPage)
10+
const page = await BasePage.init(playwrightPage)
1111
for (const { url: path, title } of page.navigationItems) {
1212
await page.goto(path)
1313
await page.expectTitle(title)
@@ -21,7 +21,7 @@ test.describe('Critical Paths @smoke', () => {
2121
const isMobile = viewport ? viewport.width < 768 : false
2222
test.skip(isMobile, 'Desktop navigation test - skipping on mobile viewport')
2323

24-
const page = new BasePage(playwrightPage)
24+
const page = await BasePage.init(playwrightPage)
2525

2626
// Import setupTestPage here to avoid unused import warnings on other tests
2727
const { setupTestPage } = await import('../../helpers/cookieHelper')
@@ -40,7 +40,7 @@ test.describe('Critical Paths @smoke', () => {
4040
const isMobile = viewport ? viewport.width < 768 : false
4141
test.skip(!isMobile, 'Mobile navigation test - skipping on desktop viewport')
4242

43-
const page = new BasePage(playwrightPage)
43+
const page = await BasePage.init(playwrightPage)
4444
await page.goto('/')
4545

4646
const navItems = page.navigationItems
@@ -62,15 +62,15 @@ test.describe('Critical Paths @smoke', () => {
6262
})
6363

6464
test('@ready footer is present on all pages', async ({ page: playwrightPage }) => {
65-
const page = new BasePage(playwrightPage)
65+
const page = await BasePage.init(playwrightPage)
6666
for (const { url: path } of page.navigationItems) {
6767
await page.goto(path)
6868
await page.expectFooter()
6969
}
7070
})
7171

7272
test('@ready contact form loads and is visible', async ({ page: playwrightPage }) => {
73-
const page = new BasePage(playwrightPage)
73+
const page = await BasePage.init(playwrightPage)
7474
await page.goto('/contact')
7575
await page.expectContactForm()
7676
await page.expectContactFormNameInput()
@@ -80,7 +80,7 @@ test.describe('Critical Paths @smoke', () => {
8080
})
8181

8282
test('@ready newsletter form is present on homepage', async ({ page: playwrightPage }) => {
83-
const page = new BasePage(playwrightPage)
83+
const page = await BasePage.init(playwrightPage)
8484
// Expected: Newsletter form should be visible on homepage
8585
// Actual: Unknown - needs testing
8686

@@ -91,21 +91,21 @@ test.describe('Critical Paths @smoke', () => {
9191
})
9292

9393
test('@ready theme picker is accessible', async ({ page: playwrightPage }) => {
94-
const page = new BasePage(playwrightPage)
94+
const page = await BasePage.init(playwrightPage)
9595
await page.goto('/')
9696
await page.expectThemePickerButton()
9797
})
9898

9999
test('@ready cookie consent banner appears', async ({ page: playwrightPage, context }) => {
100-
const page = new BasePage(playwrightPage)
100+
const page = await BasePage.init(playwrightPage)
101101
// Clear consent cookies to force banner to appear
102102
await page.clearConsentCookies(context)
103103
await page.goto('/', { skipCookieDismiss: true })
104104
await page.expectCookiesContactForm()
105105
})
106106

107107
test('@ready main pages have no 404 errors', async ({ page: playwrightPage}) => {
108-
const page = new BasePage(playwrightPage)
108+
const page = await BasePage.init(playwrightPage)
109109
for (const { url: path } of page.navigationItems) {
110110
page.enable404Listener()
111111
await page.goto(path)
@@ -114,7 +114,7 @@ test.describe('Critical Paths @smoke', () => {
114114
})
115115

116116
test('@ready main pages have no errors', async ({ page: playwrightPage }) => {
117-
const page = new BasePage(playwrightPage)
117+
const page = await BasePage.init(playwrightPage)
118118
for (const { url: path } of page.navigationItems) {
119119
await page.goto(path)
120120
await page.expectNoErrors()

‎test/e2e/specs/01-smoke/dynamic-pages.spec.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { BasePage, test, expect, setupConsoleErrorChecker, logConsoleErrors } fr
77

88
test.describe('Dynamic Pages @smoke', () => {
99
test('@ready article detail page loads', async ({ page: playwrightPage }) => {
10-
const page = new BasePage(playwrightPage)
10+
const page = await BasePage.init(playwrightPage)
1111
// First, visit articles list to get an actual article link
1212
await page.goto('/articles')
1313
await page.waitForLoadState('networkidle')
@@ -32,7 +32,7 @@ test.describe('Dynamic Pages @smoke', () => {
3232
})
3333

3434
test('@ready service detail page loads', async ({ page: playwrightPage }) => {
35-
const page = new BasePage(playwrightPage)
35+
const page = await BasePage.init(playwrightPage)
3636
// Visit services list to get an actual service link
3737
await page.goto('/services')
3838
await page.waitForLoadState('networkidle')
@@ -59,7 +59,7 @@ test.describe('Dynamic Pages @smoke', () => {
5959
})
6060

6161
test('@ready case study detail page loads', async ({ page: playwrightPage }) => {
62-
const page = new BasePage(playwrightPage)
62+
const page = await BasePage.init(playwrightPage)
6363
// Visit case studies list to get an actual case study link
6464
await page.goto('/case-studies')
6565
await page.waitForLoadState('networkidle')
@@ -86,7 +86,7 @@ test.describe('Dynamic Pages @smoke', () => {
8686
})
8787

8888
test('@ready RSS feed is accessible', async ({ page: playwrightPage }) => {
89-
const page = new BasePage(playwrightPage)
89+
const page = await BasePage.init(playwrightPage)
9090
// RSS feed should be accessible and valid XML
9191
const response = await page.goto('/rss.xml')
9292
expect(response?.status()).toBe(200)
@@ -124,7 +124,7 @@ test.describe('Dynamic Pages @smoke', () => {
124124
})
125125

126126
test('@ready dynamic pages have no 404 errors', async ({ page: playwrightPage }) => {
127-
const page = new BasePage(playwrightPage)
127+
const page = await BasePage.init(playwrightPage)
128128
// Test article page
129129
await page.goto('/articles')
130130
await page.waitForLoadState('networkidle')
@@ -169,7 +169,7 @@ test.describe('Dynamic Pages @smoke', () => {
169169
})
170170

171171
test('@ready dynamic pages have no console errors', async ({ page: playwrightPage }) => {
172-
const page = new BasePage(playwrightPage)
172+
const page = await BasePage.init(playwrightPage)
173173
// First, get actual article URL
174174
await page.goto('/articles')
175175
await page.waitForLoadState('networkidle')

0 commit comments

Comments
 (0)