Skip to content

Commit 80ef73e

Browse files
committed
Add E2E tests
1 parent 2e77431 commit 80ef73e

File tree

4 files changed

+142
-0
lines changed

4 files changed

+142
-0
lines changed

dev-packages/e2e-tests/test-applications/react-router-7-lazy-routes/src/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ const router = sentryCreateBrowserRouter(
5555
lazyChildren: () => import('./pages/AnotherLazyRoutes').then(module => module.anotherNestedRoutes),
5656
},
5757
},
58+
{
59+
path: '/long-running',
60+
handle: {
61+
lazyChildren: () => import('./pages/LongRunningLazyRoutes').then(module => module.longRunningNestedRoutes),
62+
},
63+
},
5864
{
5965
path: '/static',
6066
element: <>Hello World</>,

dev-packages/e2e-tests/test-applications/react-router-7-lazy-routes/src/pages/Index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const Index = () => {
1515
<Link to="/another-lazy/sub/555/666" id="navigation-to-another-deep">
1616
Navigate to Another Deep Lazy Route
1717
</Link>
18+
<br />
19+
<Link to="/long-running/slow/12345" id="navigation-to-long-running">
20+
Navigate to Long Running Lazy Route
21+
</Link>
1822
</>
1923
);
2024
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { Link, useParams } from 'react-router-dom';
3+
4+
// Component that simulates a long-running component load
5+
// This is used to test the POP guard during long-running pageloads
6+
const SlowLoadingComponent = () => {
7+
const { id } = useParams<{ id: string }>();
8+
const [data, setData] = useState<string | null>(null);
9+
const [isLoading, setIsLoading] = useState(true);
10+
11+
useEffect(() => {
12+
// Simulate a component that takes time to initialize
13+
// This extends the pageload duration to create a window where POP events might occur
14+
setTimeout(() => {
15+
setData(`Data loaded for ID: ${id}`);
16+
setIsLoading(false);
17+
}, 1000);
18+
}, [id]);
19+
20+
if (isLoading) {
21+
return <div id="loading-indicator">Loading...</div>;
22+
}
23+
24+
return (
25+
<div id="slow-loading-content">
26+
<div>{data}</div>
27+
<Link to="/" id="navigate-home">
28+
Go Home
29+
</Link>
30+
</div>
31+
);
32+
};
33+
34+
export const longRunningNestedRoutes = [
35+
{
36+
path: 'slow',
37+
children: [
38+
{
39+
path: ':id',
40+
element: <SlowLoadingComponent />,
41+
loader: async () => {
42+
// Simulate slow data fetching in the loader
43+
await new Promise(resolve => setTimeout(resolve, 2000));
44+
return null;
45+
},
46+
},
47+
],
48+
},
49+
];

dev-packages/e2e-tests/test-applications/react-router-7-lazy-routes/tests/transactions.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,86 @@ test('Does not send any duplicate navigation transaction names browsing between
294294
'/lazy/inner/:id/:anotherId',
295295
]);
296296
});
297+
298+
test('Does not create premature navigation transaction during long-running lazy route pageload', async ({ page }) => {
299+
const navigationPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
300+
return (
301+
!!transactionEvent?.transaction &&
302+
transactionEvent.contexts?.trace?.op === 'navigation' &&
303+
transactionEvent.transaction.includes('long-running')
304+
);
305+
});
306+
307+
const pageloadPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
308+
return (
309+
!!transactionEvent?.transaction &&
310+
transactionEvent.contexts?.trace?.op === 'pageload' &&
311+
transactionEvent.transaction === '/long-running/slow/:id'
312+
);
313+
});
314+
315+
await page.goto('/long-running/slow/12345');
316+
317+
const pageloadEvent = await pageloadPromise;
318+
319+
expect(pageloadEvent.transaction).toBe('/long-running/slow/:id');
320+
expect(pageloadEvent.contexts?.trace?.op).toBe('pageload');
321+
322+
const slowLoadingContent = page.locator('id=slow-loading-content');
323+
await expect(slowLoadingContent).toBeVisible({ timeout: 5000 });
324+
325+
const result = await Promise.race([
326+
navigationPromise.then(() => 'navigation'),
327+
new Promise<'timeout'>(resolve => setTimeout(() => resolve('timeout'), 2000)),
328+
]);
329+
330+
// Should timeout, meaning no unwanted navigation transaction was created
331+
expect(result).toBe('timeout');
332+
});
333+
334+
test('Allows legitimate POP navigation (back/forward) after pageload completes', async ({ page }) => {
335+
await page.goto('/');
336+
337+
const navigationToLongRunning = page.locator('id=navigation-to-long-running');
338+
await expect(navigationToLongRunning).toBeVisible();
339+
340+
const firstNavigationPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
341+
return (
342+
!!transactionEvent?.transaction &&
343+
transactionEvent.contexts?.trace?.op === 'navigation' &&
344+
transactionEvent.transaction === '/long-running/slow/:id'
345+
);
346+
});
347+
348+
await navigationToLongRunning.click();
349+
350+
const slowLoadingContent = page.locator('id=slow-loading-content');
351+
await expect(slowLoadingContent).toBeVisible({ timeout: 5000 });
352+
353+
const firstNavigationEvent = await firstNavigationPromise;
354+
355+
expect(firstNavigationEvent.transaction).toBe('/long-running/slow/:id');
356+
expect(firstNavigationEvent.contexts?.trace?.op).toBe('navigation');
357+
358+
// Now navigate back using browser back button (POP event)
359+
// This should create a navigation transaction since pageload is complete
360+
const backNavigationPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
361+
return (
362+
!!transactionEvent?.transaction &&
363+
transactionEvent.contexts?.trace?.op === 'navigation' &&
364+
transactionEvent.transaction === '/'
365+
);
366+
});
367+
368+
await page.goBack();
369+
370+
// Verify we're back at home
371+
const homeLink = page.locator('id=navigation');
372+
await expect(homeLink).toBeVisible();
373+
374+
const backNavigationEvent = await backNavigationPromise;
375+
376+
// Validate that the back navigation (POP) was properly tracked
377+
expect(backNavigationEvent.transaction).toBe('/');
378+
expect(backNavigationEvent.contexts?.trace?.op).toBe('navigation');
379+
});

0 commit comments

Comments
 (0)