Skip to content

Commit 0febe4f

Browse files
committed
fix(react): Add support for React Router sub-routes from handle
1 parent 1d59d8a commit 0febe4f

File tree

19 files changed

+483
-0
lines changed

19 files changed

+483
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForTransaction } from '@sentry-internal/test-utils';
3+
4+
test('should capture pageload transaction for lazy route', async ({ page }) => {
5+
const transactionPromise = waitForTransaction('react-router-6', async transactionEvent => {
6+
return (
7+
!!transactionEvent?.transaction &&
8+
transactionEvent.contexts?.trace?.op === 'pageload' &&
9+
transactionEvent.transaction === '/lazy/inner-lazy/inner'
10+
);
11+
});
12+
13+
// Navigate to a lazy-loaded route - try just /lazy first
14+
await page.goto('/lazy');
15+
16+
// Debug: Check what's actually rendered on the page
17+
const pageContent = await page.content();
18+
console.log('Page content for /lazy:', pageContent);
19+
20+
// Check if any content is rendered - use a more general selector
21+
await page.waitForLoadState('networkidle');
22+
const bodyContent = await page.locator('body').innerHTML();
23+
console.log('Body content:', bodyContent);
24+
25+
// Try to navigate to the full nested path
26+
await page.goto('/lazy/inner-lazy/inner');
27+
await page.waitForLoadState('networkidle');
28+
29+
const nestedPageContent = await page.content();
30+
console.log('Nested page content:', nestedPageContent);
31+
32+
const event = await transactionPromise;
33+
34+
expect(event.transaction).toBe('/lazy/inner-lazy');
35+
expect(event.type).toBe('transaction');
36+
expect(event.contexts?.trace?.op).toBe('pageload');
37+
});

dev-packages/e2e-tests/test-applications/react-router-7-cross-usage/src/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ const ViewsRoutes = () =>
7777
},
7878
]);
7979

80+
const LazyRoutes = () =>
81+
sentryUseRoutes([
82+
{
83+
path: 'inner-lazy',
84+
handle: {
85+
lazyChildren: async () =>
86+
import('./pages/InnerLazyRoutes').then(
87+
(module) => module.someMoreNestedRoutes,
88+
),
89+
},
90+
}
91+
]);
92+
8093
const ProjectsRoutes = () => (
8194
<SentryRoutes>
8295
<Route path="projects" element={<Outlet />}>
@@ -85,6 +98,7 @@ const ProjectsRoutes = () => (
8598
<Route path=":projectId/*" element={<ViewsRoutes />} />
8699
</Route>
87100
</Route>
101+
<Route path="/lazy/*" element={<LazyRoutes />} />
88102
</SentryRoutes>
89103
);
90104

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
3+
export const someMoreNestedRoutes = [
4+
{
5+
path: 'level-1',
6+
children: [
7+
{
8+
index: true,
9+
element: <>Level 1</>,
10+
},
11+
{
12+
path: ':id',
13+
children: [
14+
{
15+
index: true,
16+
element: <>Level 1 ID</>,
17+
},
18+
{
19+
path: ':anotherId',
20+
children: [
21+
{
22+
index: true,
23+
element: <>Level 1 ID Another ID</>,
24+
},
25+
{
26+
path: ':someAnotherId',
27+
element: <div id="innermost-lazy-route">
28+
Level 1 ID Another ID Some Another ID
29+
</div>,
30+
},
31+
],
32+
},
33+
],
34+
},
35+
],
36+
},
37+
];

dev-packages/e2e-tests/test-applications/react-router-7-cross-usage/tests/transactions.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,26 @@ test('sends a navigation transaction with a parameterized URL - alternative rout
136136
},
137137
});
138138
});
139+
140+
test('sends a pageload transaction for lazy route', async ({ page }) => {
141+
const transactionPromise = waitForTransaction('react-router-7-cross-usage', async transactionEvent => {
142+
console.debug('Lazy route transaction event', transactionEvent);
143+
return (
144+
!!transactionEvent?.transaction &&
145+
transactionEvent.contexts?.trace?.op === 'pageload' &&
146+
transactionEvent.transaction === '/lazy/inner-lazy/inner-inner-lazy'
147+
);
148+
});
149+
150+
// Try to navigate to the full nested path
151+
await page.goto('/lazy/level-1/123/456/789');
152+
153+
console.debug('Navigated to lazy route');
154+
console.debug('ROOT', await page.innerHTML('#root'));
155+
156+
const event = await transactionPromise;
157+
158+
expect(event.transaction).toBe('/lazy/inner-lazy/inner-inner-lazy');
159+
expect(event.type).toBe('transaction');
160+
expect(event.contexts?.trace?.op).toBe('pageload');
161+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
25+
/test-results/
26+
/playwright-report/
27+
/playwright/.cache/
28+
29+
!*.d.ts
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "react-router-7-cross-usage",
3+
"version": "0.1.0",
4+
"private": true,
5+
"dependencies": {
6+
"@sentry/react": "latest || *",
7+
"@types/react": "18.0.0",
8+
"@types/react-dom": "18.0.0",
9+
"express": "4.20.0",
10+
"react": "18.2.0",
11+
"react-dom": "18.2.0",
12+
"react-router-dom": "7.6.0",
13+
"react-scripts": "5.0.1",
14+
"typescript": "~5.0.0"
15+
},
16+
"scripts": {
17+
"build": "react-scripts build",
18+
"start": "serve -s build",
19+
"test": "playwright test",
20+
"clean": "npx rimraf node_modules pnpm-lock.yaml",
21+
"test:build": "pnpm install && npx playwright install && pnpm build",
22+
"test:build-ts3.8": "pnpm install && pnpm add [email protected] && npx playwright install && pnpm build",
23+
"test:build-canary": "pnpm install && pnpm add react@canary react-dom@canary && npx playwright install && pnpm build",
24+
"test:assert": "pnpm test"
25+
},
26+
"eslintConfig": {
27+
"extends": [
28+
"react-app",
29+
"react-app/jest"
30+
]
31+
},
32+
"browserslist": {
33+
"production": [
34+
">0.2%",
35+
"not dead",
36+
"not op_mini all"
37+
],
38+
"development": [
39+
"last 1 chrome version",
40+
"last 1 firefox version",
41+
"last 1 safari version"
42+
]
43+
},
44+
"devDependencies": {
45+
"@playwright/test": "~1.53.2",
46+
"@sentry-internal/test-utils": "link:../../../test-utils",
47+
"serve": "14.0.1",
48+
"npm-run-all2": "^6.2.0"
49+
},
50+
"volta": {
51+
"extends": "../../package.json"
52+
}
53+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
2+
3+
const config = getPlaywrightConfig({
4+
startCommand: `pnpm start`,
5+
});
6+
7+
export default config;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<meta name="theme-color" content="#000000" />
7+
<meta name="description" content="Web site created using create-react-app" />
8+
<title>React App</title>
9+
</head>
10+
<body>
11+
<noscript>You need to enable JavaScript to run this app.</noscript>
12+
<div id="root"></div>
13+
<!--
14+
This HTML file is a template.
15+
If you open it directly in the browser, you will see an empty page.
16+
17+
You can add webfonts, meta tags, or analytics to this file.
18+
The build step will place the bundled scripts into the <body> tag.
19+
20+
To begin the development, run `npm start` or `yarn start`.
21+
To create a production bundle, use `npm run build` or `yarn build`.
22+
-->
23+
</body>
24+
</html>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
interface Window {
2+
recordedTransactions?: string[];
3+
capturedExceptionId?: string;
4+
sentryReplayId?: string;
5+
}

0 commit comments

Comments
 (0)