Skip to content

Commit 1ef232f

Browse files
committed
test(react): Improve react router v6 E2E tests
1 parent eadcac5 commit 1ef232f

File tree

8 files changed

+150
-8
lines changed

8 files changed

+150
-8
lines changed

dev-packages/e2e-tests/test-applications/react-router-6-use-routes/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@
4747
]
4848
},
4949
"devDependencies": {
50-
"@playwright/test": "1.26.1",
50+
"@playwright/test": "^1.43.1",
51+
"@sentry-internal/event-proxy-server": "link:../../../event-proxy-server",
52+
"ts-node": "^10.9.2",
5153
"axios": "1.6.0",
5254
"serve": "14.0.1"
5355
},

dev-packages/e2e-tests/test-applications/react-router-6-use-routes/playwright.config.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import type { PlaywrightTestConfig } from '@playwright/test';
22
import { devices } from '@playwright/test';
33

4+
const reactPort = 3030;
5+
const eventProxyPort = 3031;
6+
47
/**
58
* See https://playwright.dev/docs/test-configuration.
69
*/
@@ -32,6 +35,8 @@ const config: PlaywrightTestConfig = {
3235

3336
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
3437
trace: 'on-first-retry',
38+
39+
baseURL: `http://localhost:${reactPort}`,
3540
},
3641

3742
/* Configure projects for major browsers */
@@ -58,13 +63,20 @@ const config: PlaywrightTestConfig = {
5863
],
5964

6065
/* Run your local dev server before starting the tests */
61-
webServer: {
62-
command: 'pnpm start',
63-
port: 3030,
64-
env: {
65-
PORT: '3030',
66+
67+
webServer: [
68+
{
69+
command: 'pnpm ts-node-script start-event-proxy.ts',
70+
port: eventProxyPort,
6671
},
67-
},
72+
{
73+
command: 'pnpm start',
74+
port: reactPort,
75+
env: {
76+
PORT: `${reactPort}`,
77+
},
78+
},
79+
],
6880
};
6981

7082
export default config;

dev-packages/e2e-tests/test-applications/react-router-6-use-routes/src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Sentry.init({
3535
// Always capture replays, so we can test this properly
3636
replaysSessionSampleRate: 1.0,
3737
replaysOnErrorSampleRate: 0.0,
38+
39+
tunnel: 'http://localhost:3031', // proxy server
3840
});
3941

4042
Object.defineProperty(window, 'sentryReplayId', {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { startEventProxyServer } from '@sentry-internal/event-proxy-server';
2+
3+
startEventProxyServer({
4+
port: 3031,
5+
proxyServerName: 'react-router-6-use-routes',
6+
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError, waitForTransaction } from '@sentry-internal/event-proxy-server';
3+
4+
test('Sends correct error event', async ({ page }) => {
5+
const errorEventPromise = waitForError('react-router-6-use-routes', event => {
6+
return !event.type && event.exception?.values?.[0]?.value === 'I am an error!';
7+
});
8+
9+
await page.goto('/');
10+
11+
const exceptionButton = page.locator('id=exception-button');
12+
await exceptionButton.click();
13+
14+
const errorEvent = await errorEventPromise;
15+
16+
expect(errorEvent.exception?.values).toHaveLength(1);
17+
expect(errorEvent.exception?.values?.[0]?.value).toBe('I am an error!');
18+
19+
expect(errorEvent.request).toEqual({
20+
headers: expect.any(Object),
21+
url: 'http://localhost:3030/',
22+
});
23+
24+
expect(errorEvent.transaction).toEqual('/');
25+
26+
expect(errorEvent.contexts?.trace).toEqual({
27+
trace_id: expect.any(String),
28+
span_id: expect.any(String),
29+
});
30+
});
31+
32+
test('Sets correct transactionName', async ({ page }) => {
33+
const transactionPromise = waitForTransaction('react-router-6-use-routes', async transactionEvent => {
34+
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'pageload';
35+
});
36+
37+
const errorEventPromise = waitForError('react-router-6-use-routes', event => {
38+
return !event.type && event.exception?.values?.[0]?.value === 'I am an error!';
39+
});
40+
41+
await page.goto('/');
42+
const transactionEvent = await transactionPromise;
43+
44+
// Only capture error once transaction was sent
45+
const exceptionButton = page.locator('id=exception-button');
46+
await exceptionButton.click();
47+
48+
const errorEvent = await errorEventPromise;
49+
50+
expect(errorEvent.exception?.values).toHaveLength(1);
51+
expect(errorEvent.exception?.values?.[0]?.value).toBe('I am an error!');
52+
53+
expect(errorEvent.transaction).toEqual('/');
54+
55+
expect(errorEvent.contexts?.trace).toEqual({
56+
trace_id: transactionEvent.contexts?.trace?.trace_id,
57+
span_id: expect.not.stringContaining(transactionEvent.contexts?.trace?.span_id || ''),
58+
});
59+
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForTransaction } from '@sentry-internal/event-proxy-server';
3+
4+
test('sends a pageload transaction with a parameterized URL', async ({ page }) => {
5+
const transactionPromise = waitForTransaction('react-router-6-use-routes', async transactionEvent => {
6+
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'pageload';
7+
});
8+
9+
await page.goto(`/`);
10+
11+
const rootSpan = await transactionPromise;
12+
13+
expect(rootSpan).toMatchObject({
14+
contexts: {
15+
trace: {
16+
op: 'pageload',
17+
origin: 'auto.pageload.react.reactrouter_v6',
18+
},
19+
},
20+
transaction: '/',
21+
transaction_info: {
22+
source: 'route',
23+
},
24+
});
25+
});
26+
27+
test('sends a navigation transaction with a parameterized URL', async ({ page }) => {
28+
page.on('console', msg => console.log(msg.text()));
29+
const pageloadTxnPromise = waitForTransaction('react-router-6-use-routes', async transactionEvent => {
30+
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'pageload';
31+
});
32+
33+
const navigationTxnPromise = waitForTransaction('react-router-6-use-routes', async transactionEvent => {
34+
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'navigation';
35+
});
36+
37+
await page.goto(`/`);
38+
await pageloadTxnPromise;
39+
40+
const linkElement = page.locator('id=navigation');
41+
42+
const [_, navigationTxn] = await Promise.all([linkElement.click(), navigationTxnPromise]);
43+
44+
expect(navigationTxn).toMatchObject({
45+
contexts: {
46+
trace: {
47+
op: 'navigation',
48+
origin: 'auto.navigation.react.reactrouter_v6',
49+
},
50+
},
51+
transaction: '/user/:id',
52+
transaction_info: {
53+
source: 'route',
54+
},
55+
});
56+
});

dev-packages/e2e-tests/test-applications/react-router-6-use-routes/tsconfig.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,10 @@
1616
"noEmit": true,
1717
"jsx": "react"
1818
},
19-
"include": ["src", "tests"]
19+
"include": ["src", "tests"],
20+
"ts-node": {
21+
"compilerOptions": {
22+
"module": "CommonJS"
23+
}
24+
}
2025
}

0 commit comments

Comments
 (0)