From eeca06bb09bccd376119da7c4c677f1762814b96 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Wed, 15 Apr 2026 11:25:09 +0200 Subject: [PATCH 1/4] Added plugin navigation utils --- test/apps/nuxt-app/yarn.lock | 12 +++---- .../plugins/angularPlugin.scenario.ts | 27 +++++++------- .../scenario/plugins/basePluginRouterTests.ts | 36 ++++++++----------- test/e2e/scenario/plugins/navigationUtils.ts | 11 ++++++ .../scenario/plugins/nextjsPlugin.scenario.ts | 6 ++-- 5 files changed, 50 insertions(+), 42 deletions(-) create mode 100644 test/e2e/scenario/plugins/navigationUtils.ts diff --git a/test/apps/nuxt-app/yarn.lock b/test/apps/nuxt-app/yarn.lock index 952b2e8234..e92a12e00a 100644 --- a/test/apps/nuxt-app/yarn.lock +++ b/test/apps/nuxt-app/yarn.lock @@ -347,17 +347,17 @@ __metadata: "@datadog/browser-core@file:../../../packages/core/package.tgz::locator=nuxt-app%40workspace%3A.": version: 6.32.0 - resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=8ea3e2&locator=nuxt-app%40workspace%3A." - checksum: 10c0/54e9b17cccc1084e14f99bdf1152526e02adf97cb90b574cfcd9e41411b614c0c9cbc164d9b37d62fd0dfb8efdcf5908d3e4c72768b6dddbadf10dda744c07cd + resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=2bcbab&locator=nuxt-app%40workspace%3A." + checksum: 10c0/d184c9c1b22336ceebe73f9e7b74c1d8fc955610171d9d765e2032baf4ce3fc1b63bea4950a0bd99a73e212d75e064b9161dad6df9cefdaf8fdbe54d4ad29ecd languageName: node linkType: hard "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz::locator=nuxt-app%40workspace%3A.": version: 6.32.0 - resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=72de04&locator=nuxt-app%40workspace%3A." + resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=fc4028&locator=nuxt-app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.32.0" - checksum: 10c0/6a8d8a5117fb91d357552f8b543e44a1a92ab14fe779de6f259f1e7dd65eeb57a6182188c568da234e091840a393055bcb934f3a6392d2fbc5941411d4465387 + checksum: 10c0/cdc4db22ca0603989eac8afb3be17b66a59a767ced6792d0ae3987a778d8ee6ba9745e26fc4625c55c3d0f774b176d56a1bf0ad3f3d21f8f160d3c322fcb6dbe languageName: node linkType: hard @@ -388,7 +388,7 @@ __metadata: "@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=nuxt-app%40workspace%3A.": version: 6.32.0 - resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=4e6058&locator=nuxt-app%40workspace%3A." + resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=cc0d55&locator=nuxt-app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.32.0" "@datadog/browser-rum-core": "npm:6.32.0" @@ -397,7 +397,7 @@ __metadata: peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: 10c0/d4467b27a7030f691b21dddf7d0064907415b22d5bbb2ce519a6206d2c56bd9b6585d771cfbc4ace3076285cdcc5a26458c473f0bb007cd475d63798db0ce7f8 + checksum: 10c0/4967f32460c6bcc4e6d7050e849bdca349bbf410b8233bfd0a7643348687ff5eb3f750dad45858f228dfee91a01f1b07c3a7762275407a4b838611095da20b66 languageName: node linkType: hard diff --git a/test/e2e/scenario/plugins/angularPlugin.scenario.ts b/test/e2e/scenario/plugins/angularPlugin.scenario.ts index 89bc229b69..92b9f9a5ef 100644 --- a/test/e2e/scenario/plugins/angularPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/angularPlugin.scenario.ts @@ -2,6 +2,7 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' import { runBasePluginRouterTests } from './basePluginRouterTests' +import { clickAndWaitForURL } from './navigationUtils' const angularAppName = 'angular-app' const angularBasePluginConfig = { @@ -38,26 +39,28 @@ test.describe('plugin: angular', () => { .withRum() .withApp(angularAppName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await page.click('text=Go to Nested Route') + await clickAndWaitForURL(page, 'text=Go to Nested Route', '**/parent/nested') await flushEvents() - const viewEvents = intakeRegistry.rumViewEvents - expect(viewEvents.length).toBeGreaterThan(0) - const lastView = viewEvents[viewEvents.length - 1] - expect(lastView.view.name).toBe('/parent/nested') - expect(lastView.view.url).toContain('/parent/nested') + + const nestedView = intakeRegistry.rumViewEvents.find( + (event) => event.view.name === '/parent/nested' && event.view.url?.includes('/parent/nested') + ) + expect(nestedView).toBeDefined() + expect(nestedView?.view.url).toContain('/parent/nested') }) createTest('should define a view name with the actual path for wildcard routes') .withRum() .withApp(angularAppName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await page.click('text=Go to Wildcard Route') + await clickAndWaitForURL(page, 'text=Go to Wildcard Route', '**/unknown/page') await flushEvents() - const viewEvents = intakeRegistry.rumViewEvents - expect(viewEvents.length).toBeGreaterThan(0) - const lastView = viewEvents[viewEvents.length - 1] - expect(lastView.view.name).toBe('/unknown/page') - expect(lastView.view.url).toContain('/unknown/page') + + const wildcardView = intakeRegistry.rumViewEvents.find( + (event) => event.view.name === '/unknown/page' && event.view.url?.includes('/unknown/page') + ) + expect(wildcardView).toBeDefined() + expect(wildcardView?.view.url).toContain('/unknown/page') }) createTest('should report errors caught by provideDatadogErrorHandler') diff --git a/test/e2e/scenario/plugins/basePluginRouterTests.ts b/test/e2e/scenario/plugins/basePluginRouterTests.ts index d644203f7e..42c663add5 100644 --- a/test/e2e/scenario/plugins/basePluginRouterTests.ts +++ b/test/e2e/scenario/plugins/basePluginRouterTests.ts @@ -1,5 +1,6 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' +import { clickAndWaitForURL, goHome } from './navigationUtils' type TestBuilder = ReturnType @@ -28,9 +29,10 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { const viewEvents = intakeRegistry.rumViewEvents expect(viewEvents.length).toBeGreaterThan(0) - const firstView = viewEvents[0] - expect(firstView.view.name).toBe(homeViewName) - expect(firstView.view.loading_type).toBe('initial_load') + const initialHomeView = viewEvents.find( + (e) => e.view.name === homeViewName && e.view.loading_type === 'initial_load' + ) + expect(initialHomeView).toBeDefined() }) loadApp(createTest('should normalize dynamic routes and preserve real URLs and referrers').withRum()).run( @@ -38,16 +40,13 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { const baseOrigin = new URL(baseUrl).origin // Home → Guides → Home → User → Home - await page.click('text=Go to Guides 123') - await page.waitForURL('**/guides/123') + await clickAndWaitForURL(page, 'text=Go to Guides 123', '**/guides/123') - await page.click('text=Back to Home') - await page.waitForURL(homeUrlPattern) + await goHome(page, homeUrlPattern) - await page.click('text=Go to User 42') - await page.waitForURL('**/user/42?admin=true') + await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') - await page.click('text=Back to Home') + await goHome(page, homeUrlPattern) await flushEvents() @@ -73,10 +72,9 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp(createTest('should track SPA navigation with loading_time').withRum()).run( async ({ page, flushEvents, intakeRegistry }) => { await page.waitForLoadState('networkidle') - await page.click('text=Go to User 42') - await page.waitForURL('**/user/42?admin=true') + await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') - await page.click('text=Back to Home') + await goHome(page, homeUrlPattern) await flushEvents() @@ -93,11 +91,9 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp(createTest('should not create a new view when query params change').withRum()).run( async ({ page, flushEvents, intakeRegistry }) => { - await page.click('text=Go to User 42') - await page.waitForURL('**/user/42?admin=true') + await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') - await page.click('text=Change query params') - await page.waitForURL('**/user/42?admin=false') + await clickAndWaitForURL(page, 'text=Change query params', '**/user/42?admin=false') await flushEvents() @@ -112,11 +108,9 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp( createTest('should track navigations between different concrete URLs of the same dynamic route').withRum() ).run(async ({ page, flushEvents, intakeRegistry }) => { - await page.click('text=Go to User 42') - await page.waitForURL('**/user/42?admin=true') + await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') - await page.click('text=Go to User 999') - await page.waitForURL('**/user/999?admin=true') + await clickAndWaitForURL(page, 'text=Go to User 999', '**/user/999?admin=true') await flushEvents() diff --git a/test/e2e/scenario/plugins/navigationUtils.ts b/test/e2e/scenario/plugins/navigationUtils.ts new file mode 100644 index 0000000000..b36349c854 --- /dev/null +++ b/test/e2e/scenario/plugins/navigationUtils.ts @@ -0,0 +1,11 @@ +import type { Page } from '@playwright/test' + +export type UrlPattern = string | RegExp + +export async function clickAndWaitForURL(page: Page, selector: string, urlPattern: UrlPattern) { + await Promise.all([page.waitForURL(urlPattern), page.click(selector)]) +} + +export async function goHome(page: Page, homeUrlPattern: UrlPattern) { + await clickAndWaitForURL(page, 'text=Back to Home', homeUrlPattern) +} diff --git a/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts b/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts index 9dcd70e1b3..177fb035fe 100644 --- a/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts @@ -2,6 +2,7 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' import { runBasePluginRouterTests } from './basePluginRouterTests' +import { clickAndWaitForURL, goHome } from './navigationUtils' const nextjsVariants = [ { @@ -55,12 +56,11 @@ test.describe('plugin: nextjs', () => { await page.waitForSelector('[data-testid="sidebar"]') expect(await page.textContent('[data-testid="sidebar"]')).toContain('Sidebar: Home') - await page.click('text=Go to User 42') - await page.waitForURL('**/user/42?admin=true') + await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') expect(await page.textContent('[data-testid="sidebar"]')).toContain('Sidebar: User 42') - await page.click('text=Back to Home') + await goHome(page, '**/') await flushEvents() From 32a8688508d6352d980b3140a4be393a7eb636c6 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Wed, 15 Apr 2026 14:59:42 +0200 Subject: [PATCH 2/4] Wait for home view --- test/e2e/scenario/plugins/navigationUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/scenario/plugins/navigationUtils.ts b/test/e2e/scenario/plugins/navigationUtils.ts index b36349c854..7dbdaa75a2 100644 --- a/test/e2e/scenario/plugins/navigationUtils.ts +++ b/test/e2e/scenario/plugins/navigationUtils.ts @@ -8,4 +8,5 @@ export async function clickAndWaitForURL(page: Page, selector: string, urlPatter export async function goHome(page: Page, homeUrlPattern: UrlPattern) { await clickAndWaitForURL(page, 'text=Back to Home', homeUrlPattern) + await page.waitForSelector('text=Go to User 42') } From 8d89df89a025ece4cdf0bf4127a5c40614f3ae1d Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Mon, 20 Apr 2026 15:12:47 +0200 Subject: [PATCH 3/4] Add data-ci for test, modularize further base router --- test/apps/angular-app/main.ts | 24 ++-- .../apps/nextjs/app/guides/[...slug]/page.tsx | 4 +- test/apps/nextjs/app/page.tsx | 20 +++- test/apps/nextjs/app/user/[id]/page.tsx | 16 ++- .../pages/pages-router/guides/[...slug].tsx | 4 +- test/apps/nextjs/pages/pages-router/index.tsx | 12 +- .../nextjs/pages/pages-router/user/[id].tsx | 16 ++- test/apps/nuxt-app/pages/guides/[...slug].vue | 2 +- test/apps/nuxt-app/pages/index.vue | 6 +- test/apps/nuxt-app/pages/user/[id].vue | 10 +- test/apps/react-router-v6-app/app.tsx | 44 ++++++-- .../vue-router-app/src/pages/GuidesPage.vue | 2 +- .../vue-router-app/src/pages/HomePage.vue | 6 +- .../vue-router-app/src/pages/UserPage.vue | 10 +- .../browserExtensions.scenario.ts | 2 +- .../plugins/angularPlugin.scenario.ts | 11 +- .../scenario/plugins/basePluginErrorTests.ts | 17 ++- .../scenario/plugins/basePluginRouterTests.ts | 103 ++++++++++++++++-- test/e2e/scenario/plugins/navigationUtils.ts | 38 ++++++- .../scenario/plugins/nextjsPlugin.scenario.ts | 37 +++++-- .../scenario/plugins/nuxtPlugin.scenario.ts | 11 +- .../scenario/plugins/reactPlugin.scenario.ts | 29 +++-- .../scenario/plugins/vuePlugin.scenario.ts | 17 ++- 23 files changed, 329 insertions(+), 112 deletions(-) diff --git a/test/apps/angular-app/main.ts b/test/apps/angular-app/main.ts index 0779c2423d..21a57e7bde 100644 --- a/test/apps/angular-app/main.ts +++ b/test/apps/angular-app/main.ts @@ -27,11 +27,11 @@ if (window.RUM_CONTEXT) { imports: [RouterLink], template: `

Initial Route

- Go to User 42
- Go to Guides 123
- Go to Error Test
- Go to Nested Route
- Go to Wildcard Route
+ Go to User 42
+ Go to Guides 123
+ Go to Error Test
+ Go to Nested Route
+ Go to Wildcard Route
`, @@ -54,10 +54,14 @@ class InitialRouteComponent { imports: [RouterLink], template: `

User Page

- Back to Home
- Go to Section
- Change query params
- Go to User 999 + Back to Home
+ Go to Section
+ Change query params
+ Go to User 999 `, }) class UserRouteComponent { @@ -70,7 +74,7 @@ class UserRouteComponent { imports: [RouterLink], template: `

Guides

- Back to Home + Back to Home `, }) class GuidesRouteComponent {} diff --git a/test/apps/nextjs/app/guides/[...slug]/page.tsx b/test/apps/nextjs/app/guides/[...slug]/page.tsx index 0b9003d978..6e4f2931fa 100644 --- a/test/apps/nextjs/app/guides/[...slug]/page.tsx +++ b/test/apps/nextjs/app/guides/[...slug]/page.tsx @@ -5,7 +5,9 @@ export default async function GuidesPage({ params }: { params: Promise<{ slug: s return (
- Back to Home + + Back to Home +

Guides: {slug.join('/')}

) diff --git a/test/apps/nextjs/app/page.tsx b/test/apps/nextjs/app/page.tsx index 9d80fd5b82..42e978560f 100644 --- a/test/apps/nextjs/app/page.tsx +++ b/test/apps/nextjs/app/page.tsx @@ -6,19 +6,29 @@ export default function HomePage() {

Home

  • - Go to User 42 + + Go to User 42 +
  • - Go to Guides 123 + + Go to Guides 123 +
  • - Go to Error Test + + Go to Error Test +
  • - Go to Server Error + + Go to Server Error +
  • - Go to Global Error + + Go to Global Error +
diff --git a/test/apps/nextjs/app/user/[id]/page.tsx b/test/apps/nextjs/app/user/[id]/page.tsx index d3832f7cf0..6f1dc8eaba 100644 --- a/test/apps/nextjs/app/user/[id]/page.tsx +++ b/test/apps/nextjs/app/user/[id]/page.tsx @@ -5,16 +5,24 @@ export default async function UserPage({ params }: { params: Promise<{ id: strin return (
- ← Back to Home + + ← Back to Home +

User {id}

- Go to User 999 + + Go to User 999 +
- Change query params + + Change query params +
- Go to Section + + Go to Section +
) diff --git a/test/apps/nextjs/pages/pages-router/guides/[...slug].tsx b/test/apps/nextjs/pages/pages-router/guides/[...slug].tsx index e54ea7d828..f406a1cc26 100644 --- a/test/apps/nextjs/pages/pages-router/guides/[...slug].tsx +++ b/test/apps/nextjs/pages/pages-router/guides/[...slug].tsx @@ -8,7 +8,9 @@ export default function GuidesPage() { return (
- ← Back to Home + + ← Back to Home +

Guides: {slugParts.join('/')}

) diff --git a/test/apps/nextjs/pages/pages-router/index.tsx b/test/apps/nextjs/pages/pages-router/index.tsx index 2d31b81838..b64c2730b5 100644 --- a/test/apps/nextjs/pages/pages-router/index.tsx +++ b/test/apps/nextjs/pages/pages-router/index.tsx @@ -6,13 +6,19 @@ export default function HomePage() {

Home

  • - Go to User 42 + + Go to User 42 +
  • - Go to Guides 123 + + Go to Guides 123 +
  • - Go to Error Test + + Go to Error Test +
diff --git a/test/apps/nextjs/pages/pages-router/user/[id].tsx b/test/apps/nextjs/pages/pages-router/user/[id].tsx index 929a5104d2..e276e76042 100644 --- a/test/apps/nextjs/pages/pages-router/user/[id].tsx +++ b/test/apps/nextjs/pages/pages-router/user/[id].tsx @@ -7,16 +7,24 @@ export default function UserPage() { return (
- ← Back to Home + + ← Back to Home +

User {id}

- Go to User 999 + + Go to User 999 +
- Change query params + + Change query params +
- Go to Section + + Go to Section +
) diff --git a/test/apps/nuxt-app/pages/guides/[...slug].vue b/test/apps/nuxt-app/pages/guides/[...slug].vue index 9e5817691b..57dbfb70dd 100644 --- a/test/apps/nuxt-app/pages/guides/[...slug].vue +++ b/test/apps/nuxt-app/pages/guides/[...slug].vue @@ -1,6 +1,6 @@ diff --git a/test/apps/nuxt-app/pages/index.vue b/test/apps/nuxt-app/pages/index.vue index 4669277f20..47ea1f3007 100644 --- a/test/apps/nuxt-app/pages/index.vue +++ b/test/apps/nuxt-app/pages/index.vue @@ -1,8 +1,8 @@ diff --git a/test/apps/nuxt-app/pages/user/[id].vue b/test/apps/nuxt-app/pages/user/[id].vue index 22c76dd2f8..39c2088ea4 100644 --- a/test/apps/nuxt-app/pages/user/[id].vue +++ b/test/apps/nuxt-app/pages/user/[id].vue @@ -5,9 +5,11 @@ const route = useRoute() diff --git a/test/apps/react-router-v6-app/app.tsx b/test/apps/react-router-v6-app/app.tsx index e0f9aea8f1..3da3afd722 100644 --- a/test/apps/react-router-v6-app/app.tsx +++ b/test/apps/react-router-v6-app/app.tsx @@ -25,15 +25,25 @@ function HomePage() { return (

Home

- Go to User 42 + + Go to User 42 +
- Go to Guides 123 + + Go to Guides 123 +
- Go to Wildcard + + Go to Wildcard +
- Go to Error Test + + Go to Error Test +
- Go to Tracked + + Go to Tracked +
) } @@ -43,13 +53,21 @@ function UserPage() { return (

User {id}

- Back to Home + + Back to Home +
- Go to Section + + Go to Section +
- Change query params + + Change query params +
- Go to User 999 + + Go to User 999 +
) } @@ -58,7 +76,9 @@ function GuidesPage() { return (

Guides

- Back to Home + + Back to Home +
) } @@ -68,7 +88,9 @@ function WildcardPage() { return (

Wildcard: {splatPath}

- Back to Home + + Back to Home +
) } diff --git a/test/apps/vue-router-app/src/pages/GuidesPage.vue b/test/apps/vue-router-app/src/pages/GuidesPage.vue index 175e982d4f..545da0153e 100644 --- a/test/apps/vue-router-app/src/pages/GuidesPage.vue +++ b/test/apps/vue-router-app/src/pages/GuidesPage.vue @@ -1,6 +1,6 @@ diff --git a/test/apps/vue-router-app/src/pages/HomePage.vue b/test/apps/vue-router-app/src/pages/HomePage.vue index 6fae5a7ea1..3c4f64a664 100644 --- a/test/apps/vue-router-app/src/pages/HomePage.vue +++ b/test/apps/vue-router-app/src/pages/HomePage.vue @@ -1,8 +1,8 @@ diff --git a/test/apps/vue-router-app/src/pages/UserPage.vue b/test/apps/vue-router-app/src/pages/UserPage.vue index 3dcd166c10..b342791dc3 100644 --- a/test/apps/vue-router-app/src/pages/UserPage.vue +++ b/test/apps/vue-router-app/src/pages/UserPage.vue @@ -5,9 +5,11 @@ const route = useRoute() diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index 0bb5b571cd..f894f4f89f 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -92,7 +92,7 @@ test.describe('browser extensions', () => { */ createTest('should not warn - edge case simulating NextJs with an extension that override `appendChild`') .withExtension(createExtension(path.join(BASE_PATH, 'appendChild-extension'))) - .withRum() + .withRum({ sessionReplaySampleRate: 0 }) .withLogs() .withSetup((options, servers) => { const { rumScriptUrl, logsScriptUrl } = createCrossOriginScriptUrls(servers, options) diff --git a/test/e2e/scenario/plugins/angularPlugin.scenario.ts b/test/e2e/scenario/plugins/angularPlugin.scenario.ts index 92b9f9a5ef..1fbad247a6 100644 --- a/test/e2e/scenario/plugins/angularPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/angularPlugin.scenario.ts @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' -import { runBasePluginRouterTests } from './basePluginRouterTests' +import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' import { clickAndWaitForURL } from './navigationUtils' const angularAppName = 'angular-app' @@ -14,12 +14,13 @@ const angularBasePluginConfig = { runBasePluginRouterTests([ { ...angularBasePluginConfig, - router: { + router: createBasePluginRouterConfig({ homeViewName: '/', homeUrlPattern: '**/', userRouteName: '/user/:id', guidesRouteName: '/guides/:slug', - }, + viewPrefix: '', + }), }, ]) @@ -39,7 +40,7 @@ test.describe('plugin: angular', () => { .withRum() .withApp(angularAppName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL(page, 'text=Go to Nested Route', '**/parent/nested') + await clickAndWaitForURL(page, '[data-testid="go-to-nested-route"]', '**/parent/nested') await flushEvents() const nestedView = intakeRegistry.rumViewEvents.find( @@ -53,7 +54,7 @@ test.describe('plugin: angular', () => { .withRum() .withApp(angularAppName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL(page, 'text=Go to Wildcard Route', '**/unknown/page') + await clickAndWaitForURL(page, '[data-testid="go-to-wildcard"]', '**/unknown/page') await flushEvents() const wildcardView = intakeRegistry.rumViewEvents.find( diff --git a/test/e2e/scenario/plugins/basePluginErrorTests.ts b/test/e2e/scenario/plugins/basePluginErrorTests.ts index 3f709c6b41..644b1c8233 100644 --- a/test/e2e/scenario/plugins/basePluginErrorTests.ts +++ b/test/e2e/scenario/plugins/basePluginErrorTests.ts @@ -1,5 +1,6 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' +import { clickAndWait, clickAndWaitForURL } from './navigationUtils' type TestBuilder = ReturnType @@ -8,6 +9,7 @@ interface ErrorConfig { expectedFramework: string expectsBrowserConsoleErrors?: boolean expectsComponentStack?: boolean + errorHandledSelector?: string } interface ErrorPluginTestConfig { @@ -23,11 +25,16 @@ export function runBasePluginErrorTests(configs: ErrorPluginTestConfig[]) { test.describe('errors', () => { loadApp(createTest('should report client-side error').withRum()).run( async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await page.click('text=Go to Error Test') - await page.waitForURL(`**${viewPrefix}/error-test`) - - await page.click('[data-testid="trigger-error"]') - await page.waitForSelector('[data-testid="error-handled"]') + await clickAndWaitForURL( + page, + '[data-testid="go-to-error-test"]', + `**${viewPrefix}/error-test`, + '[data-testid="trigger-error"]' + ) + + await clickAndWait(page, '[data-testid="trigger-error"]', { + readySelector: error.errorHandledSelector ?? '[data-testid="error-handled"]', + }) await flushEvents() diff --git a/test/e2e/scenario/plugins/basePluginRouterTests.ts b/test/e2e/scenario/plugins/basePluginRouterTests.ts index 42c663add5..07032e31a6 100644 --- a/test/e2e/scenario/plugins/basePluginRouterTests.ts +++ b/test/e2e/scenario/plugins/basePluginRouterTests.ts @@ -1,14 +1,26 @@ +import type { Page } from '@playwright/test' import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' +import type { NavigationTarget, UrlPattern } from './navigationUtils' import { clickAndWaitForURL, goHome } from './navigationUtils' type TestBuilder = ReturnType +interface RouteNavigation extends NavigationTarget { + urlPattern: UrlPattern +} + interface RouterConfig { homeViewName: string - homeUrlPattern: string | RegExp + homeNavigation: RouteNavigation userRouteName: string guidesRouteName: string + navigation: { + guides: RouteNavigation + user: RouteNavigation + queryChange: RouteNavigation + otherUser: RouteNavigation + } } interface RouterPluginTestConfig { @@ -18,9 +30,76 @@ interface RouterPluginTestConfig { router: RouterConfig } +interface RouteFixtures { + guideSlug: string + userId: string + otherUserId: string +} + +interface CreateBasePluginRouterConfigParams { + homeViewName: string + homeUrlPattern: UrlPattern + userRouteName: string + guidesRouteName: string + viewPrefix: string + fixtures?: Partial +} + +const DEFAULT_ROUTE_FIXTURES: RouteFixtures = { + guideSlug: '123', + userId: '42', + otherUserId: '999', +} + +export function createBasePluginRouterConfig({ + homeViewName, + homeUrlPattern, + userRouteName, + guidesRouteName, + viewPrefix, + fixtures, +}: CreateBasePluginRouterConfigParams): RouterConfig { + const { guideSlug, userId, otherUserId } = { ...DEFAULT_ROUTE_FIXTURES, ...fixtures } + + return { + homeViewName, + homeNavigation: { + clickSelector: '[data-testid="back-to-home"]', + urlPattern: homeUrlPattern, + readySelector: '[data-testid="go-to-user"]', + }, + userRouteName, + guidesRouteName, + navigation: { + guides: { + clickSelector: '[data-testid="go-to-guides"]', + urlPattern: `**${viewPrefix}/guides/${guideSlug}`, + readySelector: '[data-testid="back-to-home"]', + }, + user: { + clickSelector: '[data-testid="go-to-user"]', + urlPattern: `**${viewPrefix}/user/${userId}?admin=true`, + readySelector: '[data-testid="back-to-home"]', + }, + queryChange: { + clickSelector: '[data-testid="change-query-params"]', + urlPattern: `**${viewPrefix}/user/${userId}?admin=false`, + }, + otherUser: { + clickSelector: '[data-testid="go-to-other-user"]', + urlPattern: `**${viewPrefix}/user/${otherUserId}?admin=true`, + }, + }, + } +} + +async function clickAndWaitForNavigation(page: Page, navigation: RouteNavigation) { + await clickAndWaitForURL(page, navigation.clickSelector, navigation.urlPattern, navigation.readySelector) +} + export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { for (const { name, loadApp, viewPrefix, router } of configs) { - const { homeViewName, homeUrlPattern, userRouteName, guidesRouteName } = router + const { homeViewName, homeNavigation, userRouteName, guidesRouteName, navigation } = router test.describe(`base plugin: ${name}`, () => { test.describe('router', () => { @@ -40,13 +119,13 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { const baseOrigin = new URL(baseUrl).origin // Home → Guides → Home → User → Home - await clickAndWaitForURL(page, 'text=Go to Guides 123', '**/guides/123') + await clickAndWaitForNavigation(page, navigation.guides) - await goHome(page, homeUrlPattern) + await goHome(page, homeNavigation) - await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') + await clickAndWaitForNavigation(page, navigation.user) - await goHome(page, homeUrlPattern) + await goHome(page, homeNavigation) await flushEvents() @@ -72,9 +151,9 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp(createTest('should track SPA navigation with loading_time').withRum()).run( async ({ page, flushEvents, intakeRegistry }) => { await page.waitForLoadState('networkidle') - await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') + await clickAndWaitForNavigation(page, navigation.user) - await goHome(page, homeUrlPattern) + await goHome(page, homeNavigation) await flushEvents() @@ -91,9 +170,9 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp(createTest('should not create a new view when query params change').withRum()).run( async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') + await clickAndWaitForNavigation(page, navigation.user) - await clickAndWaitForURL(page, 'text=Change query params', '**/user/42?admin=false') + await clickAndWaitForNavigation(page, navigation.queryChange) await flushEvents() @@ -108,9 +187,9 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp( createTest('should track navigations between different concrete URLs of the same dynamic route').withRum() ).run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') + await clickAndWaitForNavigation(page, navigation.user) - await clickAndWaitForURL(page, 'text=Go to User 999', '**/user/999?admin=true') + await clickAndWaitForNavigation(page, navigation.otherUser) await flushEvents() diff --git a/test/e2e/scenario/plugins/navigationUtils.ts b/test/e2e/scenario/plugins/navigationUtils.ts index 7dbdaa75a2..80b56c3dba 100644 --- a/test/e2e/scenario/plugins/navigationUtils.ts +++ b/test/e2e/scenario/plugins/navigationUtils.ts @@ -2,11 +2,39 @@ import type { Page } from '@playwright/test' export type UrlPattern = string | RegExp -export async function clickAndWaitForURL(page: Page, selector: string, urlPattern: UrlPattern) { - await Promise.all([page.waitForURL(urlPattern), page.click(selector)]) +interface ClickAndWaitOptions { + urlPattern?: UrlPattern + readySelector?: string } -export async function goHome(page: Page, homeUrlPattern: UrlPattern) { - await clickAndWaitForURL(page, 'text=Back to Home', homeUrlPattern) - await page.waitForSelector('text=Go to User 42') +export interface NavigationTarget extends ClickAndWaitOptions { + clickSelector: string +} + +export async function clickAndWait( + page: Page, + selector: string, + { urlPattern, readySelector }: ClickAndWaitOptions = {} +) { + if (urlPattern !== undefined) { + await Promise.all([page.waitForURL(urlPattern), page.click(selector)]) + } else { + await page.click(selector) + } + + if (readySelector) { + await page.waitForSelector(readySelector) + } +} + +export async function navigate(page: Page, navigation: NavigationTarget) { + await clickAndWait(page, navigation.clickSelector, navigation) +} + +export async function clickAndWaitForURL(page: Page, selector: string, urlPattern: UrlPattern, readySelector?: string) { + await clickAndWait(page, selector, { urlPattern, readySelector }) +} + +export async function goHome(page: Page, homeNavigation: NavigationTarget) { + await navigate(page, homeNavigation) } diff --git a/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts b/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts index 177fb035fe..fa251e025b 100644 --- a/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' -import { runBasePluginRouterTests } from './basePluginRouterTests' +import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' import { clickAndWaitForURL, goHome } from './navigationUtils' const nextjsVariants = [ @@ -26,12 +26,13 @@ runBasePluginRouterTests( name, loadApp: (b: ReturnType) => b.withNextjsApp(routerType), viewPrefix, - router: { + router: createBasePluginRouterConfig({ homeViewName: viewPrefix || '/', homeUrlPattern, userRouteName: '/user/[id]', guidesRouteName: '/guides/[...slug]', - }, + viewPrefix, + }), })) ) @@ -44,6 +45,7 @@ runBasePluginErrorTests( clientErrorMessage, expectedFramework: 'nextjs', expectsBrowserConsoleErrors: true, + errorHandledSelector: '[data-testid="error-handled"][data-error-reported]', }, })) ) @@ -56,11 +58,20 @@ test.describe('plugin: nextjs', () => { await page.waitForSelector('[data-testid="sidebar"]') expect(await page.textContent('[data-testid="sidebar"]')).toContain('Sidebar: Home') - await clickAndWaitForURL(page, 'text=Go to User 42', '**/user/42?admin=true') + await clickAndWaitForURL( + page, + '[data-testid="go-to-user"]', + '**/user/42?admin=true', + '[data-testid="change-query-params"]' + ) expect(await page.textContent('[data-testid="sidebar"]')).toContain('Sidebar: User 42') - await goHome(page, '**/') + await goHome(page, { + clickSelector: '[data-testid="back-to-home"]', + urlPattern: '**/', + readySelector: '[data-testid="go-to-user"]', + }) await flushEvents() @@ -79,8 +90,12 @@ test.describe('plugin: nextjs', () => { .withRum() .withNextjsApp('app') .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await page.click('text=Go to Server Error') - await page.waitForSelector('[data-testid="error-handled"]') + await clickAndWaitForURL( + page, + '[data-testid="go-to-server-error"]', + '**/error-test/server-error?throw=true', + '[data-testid="error-handled"][data-error-reported]' + ) await flushEvents() @@ -101,8 +116,12 @@ test.describe('plugin: nextjs', () => { .withRum() .withNextjsApp('app') .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await page.click('text=Go to Global Error') - await page.waitForSelector('[data-testid="global-error-boundary"]') + await clickAndWaitForURL( + page, + '[data-testid="go-to-global-error"]', + '**/global-error-test?throw=true', + '[data-testid="global-error-boundary"]' + ) await flushEvents() diff --git a/test/e2e/scenario/plugins/nuxtPlugin.scenario.ts b/test/e2e/scenario/plugins/nuxtPlugin.scenario.ts index 2fd026a900..30201b65c6 100644 --- a/test/e2e/scenario/plugins/nuxtPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/nuxtPlugin.scenario.ts @@ -1,6 +1,6 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' -import { runBasePluginRouterTests } from './basePluginRouterTests' +import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' const nuxtBasePluginConfig = { name: 'nuxt', @@ -11,12 +11,13 @@ const nuxtBasePluginConfig = { runBasePluginRouterTests([ { ...nuxtBasePluginConfig, - router: { + router: createBasePluginRouterConfig({ homeViewName: '/', homeUrlPattern: '**/', userRouteName: '/user/[id]', guidesRouteName: '/guides/[...slug]', - }, + viewPrefix: '', + }), }, ]) @@ -25,10 +26,10 @@ test.describe('plugin: nuxt router', () => { .withRum() .withNuxtApp() .run(async ({ page, flushEvents, intakeRegistry }) => { - await page.click('text=Go to User 42') + await page.click('[data-testid="go-to-user"]') await page.waitForURL('**/user/42?admin=true') - await page.click('text=Go to Section') + await page.click('[data-testid="go-to-section"]') await page.waitForURL('**/user/42#section') await flushEvents() diff --git a/test/e2e/scenario/plugins/reactPlugin.scenario.ts b/test/e2e/scenario/plugins/reactPlugin.scenario.ts index fcafe3aeea..790c44bc8d 100644 --- a/test/e2e/scenario/plugins/reactPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/reactPlugin.scenario.ts @@ -1,7 +1,8 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' -import { runBasePluginRouterTests } from './basePluginRouterTests' +import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' +import { clickAndWait, clickAndWaitForURL } from './navigationUtils' const reactApps = [ { appName: 'react-router-v6-app', description: 'React Router v6' }, @@ -19,12 +20,13 @@ runBasePluginRouterTests( name, loadApp, viewPrefix, - router: { + router: createBasePluginRouterConfig({ homeViewName: '/', homeUrlPattern: '**/', userRouteName: '/user/:id', guidesRouteName: '/guides/:slug', - }, + viewPrefix, + }), })) ) @@ -49,7 +51,7 @@ test.describe('plugin: react', () => { .withRum() .withApp(appName) .run(async ({ flushEvents, intakeRegistry, page }) => { - await page.click('text=Go to Tracked') + await page.click('[data-testid="go-to-tracked"]') await flushEvents() const vitalEvents = intakeRegistry.rumVitalEvents[0] @@ -61,8 +63,12 @@ test.describe('plugin: react', () => { .withRum() .withApp(appName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await page.click('text=Go to Wildcard') - await page.waitForURL('**/wildcard/foo/bar') + await clickAndWaitForURL( + page, + '[data-testid="go-to-wildcard"]', + '**/wildcard/foo/bar', + '[data-testid="back-to-home"]' + ) await flushEvents() @@ -75,10 +81,13 @@ test.describe('plugin: react', () => { .withRum() .withApp(appName) .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await page.click('text=Go to Error Test') - await page.waitForURL('**/error-test') - await page.click('[data-testid="trigger-error"]') - await page.waitForSelector('[data-testid="error-handled"]') + await clickAndWaitForURL( + page, + '[data-testid="go-to-error-test"]', + '**/error-test', + '[data-testid="trigger-error"]' + ) + await clickAndWait(page, '[data-testid="trigger-error"]', { readySelector: '[data-testid="error-handled"]' }) await flushEvents() diff --git a/test/e2e/scenario/plugins/vuePlugin.scenario.ts b/test/e2e/scenario/plugins/vuePlugin.scenario.ts index b2ce0aec7e..11e1e66388 100644 --- a/test/e2e/scenario/plugins/vuePlugin.scenario.ts +++ b/test/e2e/scenario/plugins/vuePlugin.scenario.ts @@ -1,7 +1,8 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' -import { runBasePluginRouterTests } from './basePluginRouterTests' +import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' +import { clickAndWait, clickAndWaitForURL } from './navigationUtils' const vueBasePluginConfig = { name: 'vue', @@ -12,12 +13,13 @@ const vueBasePluginConfig = { runBasePluginRouterTests([ { ...vueBasePluginConfig, - router: { + router: createBasePluginRouterConfig({ homeViewName: '/', homeUrlPattern: '**/', userRouteName: '/user/:id', guidesRouteName: '/guides/:catchAll(.*)*', - }, + viewPrefix: '', + }), }, ]) @@ -37,8 +39,13 @@ test.describe('plugin: vue', () => { .withRum() .withVueApp() .run(async ({ page, flushEvents, intakeRegistry }) => { - await page.click('text=Go to Error Test') - await page.click('[data-testid="trigger-error"]') + await clickAndWaitForURL( + page, + '[data-testid="go-to-error-test"]', + '**/error-test', + '[data-testid="trigger-error"]' + ) + await clickAndWait(page, '[data-testid="trigger-error"]', { readySelector: '[data-testid="error-handled"]' }) await flushEvents() From cfb899d7c84cea103a073a0011959f6c321d39a4 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Tue, 21 Apr 2026 16:31:38 +0200 Subject: [PATCH 4/4] Remove utils file, and unnecesary replay value. --- .../browserExtensions.scenario.ts | 2 +- .../plugins/angularPlugin.scenario.ts | 5 +- .../scenario/plugins/basePluginErrorTests.ts | 19 +++----- .../scenario/plugins/basePluginRouterTests.ts | 46 +++++++++++-------- test/e2e/scenario/plugins/navigationUtils.ts | 40 ---------------- .../scenario/plugins/nextjsPlugin.scenario.ts | 32 ++++--------- .../scenario/plugins/reactPlugin.scenario.ts | 20 +++----- .../scenario/plugins/vuePlugin.scenario.ts | 12 ++--- 8 files changed, 53 insertions(+), 123 deletions(-) delete mode 100644 test/e2e/scenario/plugins/navigationUtils.ts diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index f894f4f89f..0bb5b571cd 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -92,7 +92,7 @@ test.describe('browser extensions', () => { */ createTest('should not warn - edge case simulating NextJs with an extension that override `appendChild`') .withExtension(createExtension(path.join(BASE_PATH, 'appendChild-extension'))) - .withRum({ sessionReplaySampleRate: 0 }) + .withRum() .withLogs() .withSetup((options, servers) => { const { rumScriptUrl, logsScriptUrl } = createCrossOriginScriptUrls(servers, options) diff --git a/test/e2e/scenario/plugins/angularPlugin.scenario.ts b/test/e2e/scenario/plugins/angularPlugin.scenario.ts index 1fbad247a6..342be88469 100644 --- a/test/e2e/scenario/plugins/angularPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/angularPlugin.scenario.ts @@ -2,7 +2,6 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' -import { clickAndWaitForURL } from './navigationUtils' const angularAppName = 'angular-app' const angularBasePluginConfig = { @@ -40,7 +39,7 @@ test.describe('plugin: angular', () => { .withRum() .withApp(angularAppName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL(page, '[data-testid="go-to-nested-route"]', '**/parent/nested') + await page.click('[data-testid="go-to-nested-route"]') await flushEvents() const nestedView = intakeRegistry.rumViewEvents.find( @@ -54,7 +53,7 @@ test.describe('plugin: angular', () => { .withRum() .withApp(angularAppName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL(page, '[data-testid="go-to-wildcard"]', '**/unknown/page') + await page.click('[data-testid="go-to-wildcard"]') await flushEvents() const wildcardView = intakeRegistry.rumViewEvents.find( diff --git a/test/e2e/scenario/plugins/basePluginErrorTests.ts b/test/e2e/scenario/plugins/basePluginErrorTests.ts index 644b1c8233..926f327b1e 100644 --- a/test/e2e/scenario/plugins/basePluginErrorTests.ts +++ b/test/e2e/scenario/plugins/basePluginErrorTests.ts @@ -1,6 +1,5 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' -import { clickAndWait, clickAndWaitForURL } from './navigationUtils' type TestBuilder = ReturnType @@ -15,26 +14,20 @@ interface ErrorConfig { interface ErrorPluginTestConfig { name: string loadApp: (builder: TestBuilder) => TestBuilder - viewPrefix: string error: ErrorConfig } export function runBasePluginErrorTests(configs: ErrorPluginTestConfig[]) { - for (const { name, loadApp, viewPrefix, error } of configs) { + for (const { name, loadApp, error } of configs) { test.describe(`base plugin: ${name}`, () => { test.describe('errors', () => { loadApp(createTest('should report client-side error').withRum()).run( async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await clickAndWaitForURL( - page, - '[data-testid="go-to-error-test"]', - `**${viewPrefix}/error-test`, - '[data-testid="trigger-error"]' - ) - - await clickAndWait(page, '[data-testid="trigger-error"]', { - readySelector: error.errorHandledSelector ?? '[data-testid="error-handled"]', - }) + await page.click('[data-testid="go-to-error-test"]') + await page.waitForSelector('[data-testid="trigger-error"]') + + await page.click('[data-testid="trigger-error"]') + await page.waitForSelector(error.errorHandledSelector ?? '[data-testid="error-handled"]') await flushEvents() diff --git a/test/e2e/scenario/plugins/basePluginRouterTests.ts b/test/e2e/scenario/plugins/basePluginRouterTests.ts index 07032e31a6..6ac15b44d5 100644 --- a/test/e2e/scenario/plugins/basePluginRouterTests.ts +++ b/test/e2e/scenario/plugins/basePluginRouterTests.ts @@ -1,11 +1,14 @@ -import type { Page } from '@playwright/test' import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' -import type { NavigationTarget, UrlPattern } from './navigationUtils' -import { clickAndWaitForURL, goHome } from './navigationUtils' + +type UrlPattern = string | RegExp type TestBuilder = ReturnType +interface NavigationTarget { + clickSelector: string +} + interface RouteNavigation extends NavigationTarget { urlPattern: UrlPattern } @@ -66,7 +69,6 @@ export function createBasePluginRouterConfig({ homeNavigation: { clickSelector: '[data-testid="back-to-home"]', urlPattern: homeUrlPattern, - readySelector: '[data-testid="go-to-user"]', }, userRouteName, guidesRouteName, @@ -74,12 +76,10 @@ export function createBasePluginRouterConfig({ guides: { clickSelector: '[data-testid="go-to-guides"]', urlPattern: `**${viewPrefix}/guides/${guideSlug}`, - readySelector: '[data-testid="back-to-home"]', }, user: { clickSelector: '[data-testid="go-to-user"]', urlPattern: `**${viewPrefix}/user/${userId}?admin=true`, - readySelector: '[data-testid="back-to-home"]', }, queryChange: { clickSelector: '[data-testid="change-query-params"]', @@ -93,10 +93,6 @@ export function createBasePluginRouterConfig({ } } -async function clickAndWaitForNavigation(page: Page, navigation: RouteNavigation) { - await clickAndWaitForURL(page, navigation.clickSelector, navigation.urlPattern, navigation.readySelector) -} - export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { for (const { name, loadApp, viewPrefix, router } of configs) { const { homeViewName, homeNavigation, userRouteName, guidesRouteName, navigation } = router @@ -119,13 +115,17 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { const baseOrigin = new URL(baseUrl).origin // Home → Guides → Home → User → Home - await clickAndWaitForNavigation(page, navigation.guides) + await page.click(navigation.guides.clickSelector) + await page.waitForURL(navigation.guides.urlPattern) - await goHome(page, homeNavigation) + await page.click(homeNavigation.clickSelector) + await page.waitForURL(homeNavigation.urlPattern) - await clickAndWaitForNavigation(page, navigation.user) + await page.click(navigation.user.clickSelector) + await page.waitForURL(navigation.user.urlPattern) - await goHome(page, homeNavigation) + await page.click(homeNavigation.clickSelector) + await page.waitForURL(homeNavigation.urlPattern) await flushEvents() @@ -151,9 +151,11 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp(createTest('should track SPA navigation with loading_time').withRum()).run( async ({ page, flushEvents, intakeRegistry }) => { await page.waitForLoadState('networkidle') - await clickAndWaitForNavigation(page, navigation.user) + await page.click(navigation.user.clickSelector) + await page.waitForURL(navigation.user.urlPattern) - await goHome(page, homeNavigation) + await page.click(homeNavigation.clickSelector) + await page.waitForURL(homeNavigation.urlPattern) await flushEvents() @@ -170,9 +172,11 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp(createTest('should not create a new view when query params change').withRum()).run( async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForNavigation(page, navigation.user) + await page.click(navigation.user.clickSelector) + await page.waitForURL(navigation.user.urlPattern) - await clickAndWaitForNavigation(page, navigation.queryChange) + await page.click(navigation.queryChange.clickSelector) + await page.waitForURL(navigation.queryChange.urlPattern) await flushEvents() @@ -187,9 +191,11 @@ export function runBasePluginRouterTests(configs: RouterPluginTestConfig[]) { loadApp( createTest('should track navigations between different concrete URLs of the same dynamic route').withRum() ).run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForNavigation(page, navigation.user) + await page.click(navigation.user.clickSelector) + await page.waitForURL(navigation.user.urlPattern) - await clickAndWaitForNavigation(page, navigation.otherUser) + await page.click(navigation.otherUser.clickSelector) + await page.waitForURL(navigation.otherUser.urlPattern) await flushEvents() diff --git a/test/e2e/scenario/plugins/navigationUtils.ts b/test/e2e/scenario/plugins/navigationUtils.ts deleted file mode 100644 index 80b56c3dba..0000000000 --- a/test/e2e/scenario/plugins/navigationUtils.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { Page } from '@playwright/test' - -export type UrlPattern = string | RegExp - -interface ClickAndWaitOptions { - urlPattern?: UrlPattern - readySelector?: string -} - -export interface NavigationTarget extends ClickAndWaitOptions { - clickSelector: string -} - -export async function clickAndWait( - page: Page, - selector: string, - { urlPattern, readySelector }: ClickAndWaitOptions = {} -) { - if (urlPattern !== undefined) { - await Promise.all([page.waitForURL(urlPattern), page.click(selector)]) - } else { - await page.click(selector) - } - - if (readySelector) { - await page.waitForSelector(readySelector) - } -} - -export async function navigate(page: Page, navigation: NavigationTarget) { - await clickAndWait(page, navigation.clickSelector, navigation) -} - -export async function clickAndWaitForURL(page: Page, selector: string, urlPattern: UrlPattern, readySelector?: string) { - await clickAndWait(page, selector, { urlPattern, readySelector }) -} - -export async function goHome(page: Page, homeNavigation: NavigationTarget) { - await navigate(page, homeNavigation) -} diff --git a/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts b/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts index fa251e025b..3debeb7e61 100644 --- a/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/nextjsPlugin.scenario.ts @@ -2,7 +2,6 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' -import { clickAndWaitForURL, goHome } from './navigationUtils' const nextjsVariants = [ { @@ -58,20 +57,13 @@ test.describe('plugin: nextjs', () => { await page.waitForSelector('[data-testid="sidebar"]') expect(await page.textContent('[data-testid="sidebar"]')).toContain('Sidebar: Home') - await clickAndWaitForURL( - page, - '[data-testid="go-to-user"]', - '**/user/42?admin=true', - '[data-testid="change-query-params"]' - ) + await page.click('[data-testid="go-to-user"]') + await page.waitForSelector('[data-testid="change-query-params"]') expect(await page.textContent('[data-testid="sidebar"]')).toContain('Sidebar: User 42') - await goHome(page, { - clickSelector: '[data-testid="back-to-home"]', - urlPattern: '**/', - readySelector: '[data-testid="go-to-user"]', - }) + await page.click('[data-testid="back-to-home"]') + await page.waitForSelector('[data-testid="go-to-user"]') await flushEvents() @@ -90,12 +82,8 @@ test.describe('plugin: nextjs', () => { .withRum() .withNextjsApp('app') .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await clickAndWaitForURL( - page, - '[data-testid="go-to-server-error"]', - '**/error-test/server-error?throw=true', - '[data-testid="error-handled"][data-error-reported]' - ) + await page.click('[data-testid="go-to-server-error"]') + await page.waitForSelector('[data-testid="error-handled"][data-error-reported]') await flushEvents() @@ -116,12 +104,8 @@ test.describe('plugin: nextjs', () => { .withRum() .withNextjsApp('app') .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await clickAndWaitForURL( - page, - '[data-testid="go-to-global-error"]', - '**/global-error-test?throw=true', - '[data-testid="global-error-boundary"]' - ) + await page.click('[data-testid="go-to-global-error"]') + await page.waitForSelector('[data-testid="global-error-boundary"]') await flushEvents() diff --git a/test/e2e/scenario/plugins/reactPlugin.scenario.ts b/test/e2e/scenario/plugins/reactPlugin.scenario.ts index 790c44bc8d..53fed3eb15 100644 --- a/test/e2e/scenario/plugins/reactPlugin.scenario.ts +++ b/test/e2e/scenario/plugins/reactPlugin.scenario.ts @@ -2,7 +2,6 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' -import { clickAndWait, clickAndWaitForURL } from './navigationUtils' const reactApps = [ { appName: 'react-router-v6-app', description: 'React Router v6' }, @@ -63,12 +62,8 @@ test.describe('plugin: react', () => { .withRum() .withApp(appName) .run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL( - page, - '[data-testid="go-to-wildcard"]', - '**/wildcard/foo/bar', - '[data-testid="back-to-home"]' - ) + await page.click('[data-testid="go-to-wildcard"]') + await page.waitForSelector('[data-testid="back-to-home"]') await flushEvents() @@ -81,13 +76,10 @@ test.describe('plugin: react', () => { .withRum() .withApp(appName) .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await clickAndWaitForURL( - page, - '[data-testid="go-to-error-test"]', - '**/error-test', - '[data-testid="trigger-error"]' - ) - await clickAndWait(page, '[data-testid="trigger-error"]', { readySelector: '[data-testid="error-handled"]' }) + await page.click('[data-testid="go-to-error-test"]') + await page.waitForSelector('[data-testid="trigger-error"]') + await page.click('[data-testid="trigger-error"]') + await page.waitForSelector('[data-testid="error-handled"]') await flushEvents() diff --git a/test/e2e/scenario/plugins/vuePlugin.scenario.ts b/test/e2e/scenario/plugins/vuePlugin.scenario.ts index 11e1e66388..73b9f73b5a 100644 --- a/test/e2e/scenario/plugins/vuePlugin.scenario.ts +++ b/test/e2e/scenario/plugins/vuePlugin.scenario.ts @@ -2,7 +2,6 @@ import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' import { runBasePluginErrorTests } from './basePluginErrorTests' import { createBasePluginRouterConfig, runBasePluginRouterTests } from './basePluginRouterTests' -import { clickAndWait, clickAndWaitForURL } from './navigationUtils' const vueBasePluginConfig = { name: 'vue', @@ -39,13 +38,10 @@ test.describe('plugin: vue', () => { .withRum() .withVueApp() .run(async ({ page, flushEvents, intakeRegistry }) => { - await clickAndWaitForURL( - page, - '[data-testid="go-to-error-test"]', - '**/error-test', - '[data-testid="trigger-error"]' - ) - await clickAndWait(page, '[data-testid="trigger-error"]', { readySelector: '[data-testid="error-handled"]' }) + await page.click('[data-testid="go-to-error-test"]') + await page.waitForSelector('[data-testid="trigger-error"]') + await page.click('[data-testid="trigger-error"]') + await page.waitForSelector('[data-testid="error-handled"]') await flushEvents()