Skip to content

Commit 0238386

Browse files
committed
ref(react): Remove lazy route machinery in favour of lazyRouteManifest
1 parent d251b11 commit 0238386

5 files changed

Lines changed: 80 additions & 634 deletions

File tree

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

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,15 @@ import {
1313
import Index from './pages/Index';
1414
import Deep from './pages/Deep';
1515

16-
function getRuntimeConfig(): { lazyRouteTimeout?: number; idleTimeout?: number } {
16+
function getRuntimeConfig(): { idleTimeout?: number } {
1717
if (typeof window === 'undefined') {
1818
return {};
1919
}
2020

2121
try {
2222
const url = new URL(window.location.href);
23-
const timeoutParam = url.searchParams.get('timeout');
2423
const idleTimeoutParam = url.searchParams.get('idleTimeout');
2524

26-
let lazyRouteTimeout: number | undefined = undefined;
27-
if (timeoutParam) {
28-
if (timeoutParam === 'Infinity') {
29-
lazyRouteTimeout = Infinity;
30-
} else {
31-
const parsed = parseInt(timeoutParam, 10);
32-
if (!isNaN(parsed)) {
33-
lazyRouteTimeout = parsed;
34-
}
35-
}
36-
}
37-
3825
let idleTimeout: number | undefined = undefined;
3926
if (idleTimeoutParam) {
4027
const parsed = parseInt(idleTimeoutParam, 10);
@@ -44,7 +31,6 @@ function getRuntimeConfig(): { lazyRouteTimeout?: number; idleTimeout?: number }
4431
}
4532

4633
return {
47-
lazyRouteTimeout,
4834
idleTimeout,
4935
};
5036
} catch (error) {
@@ -87,7 +73,6 @@ Sentry.init({
8773
matchRoutes,
8874
trackFetchStreamPerformance: true,
8975
enableAsyncRouteHandlers: true,
90-
lazyRouteTimeout: runtimeConfig.lazyRouteTimeout,
9176
idleTimeout: runtimeConfig.idleTimeout,
9277
lazyRouteManifest,
9378
}),

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

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,6 @@
11
import { expect, test } from '@playwright/test';
22
import { waitForTransaction } from '@sentry-internal/test-utils';
33

4-
test('lazyRouteTimeout: Routes load within timeout window', async ({ page }) => {
5-
const transactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
6-
return (
7-
!!transactionEvent?.transaction &&
8-
transactionEvent.contexts?.trace?.op === 'navigation' &&
9-
transactionEvent.transaction.includes('deep')
10-
);
11-
});
12-
13-
// Route takes ~900ms, timeout allows 1050ms (50 + 1000)
14-
// Routes will load in time → parameterized name
15-
await page.goto('/?idleTimeout=50&timeout=1000');
16-
17-
const navigationLink = page.locator('id=navigation-to-deep');
18-
await expect(navigationLink).toBeVisible();
19-
await navigationLink.click();
20-
21-
const event = await transactionPromise;
22-
23-
// Should get full parameterized route
24-
expect(event.transaction).toBe('/deep/level2/level3/:id');
25-
expect(event.contexts?.trace?.data?.['sentry.source']).toBe('route');
26-
expect(event.contexts?.trace?.data?.['sentry.idle_span_finish_reason']).toBe('idleTimeout');
27-
});
28-
29-
test('lazyRouteTimeout: Infinity timeout always waits for routes', async ({ page }) => {
30-
const transactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
31-
return (
32-
!!transactionEvent?.transaction &&
33-
transactionEvent.contexts?.trace?.op === 'navigation' &&
34-
transactionEvent.transaction.includes('deep')
35-
);
36-
});
37-
38-
// Infinity timeout → waits as long as possible (capped at finalTimeout to prevent indefinite hangs)
39-
await page.goto('/?idleTimeout=50&timeout=Infinity');
40-
41-
const navigationLink = page.locator('id=navigation-to-deep');
42-
await expect(navigationLink).toBeVisible();
43-
await navigationLink.click();
44-
45-
const event = await transactionPromise;
46-
47-
// Should wait for routes to load (up to finalTimeout) and get full route
48-
expect(event.transaction).toBe('/deep/level2/level3/:id');
49-
expect(event.contexts?.trace?.data?.['sentry.source']).toBe('route');
50-
expect(event.contexts?.trace?.data?.['sentry.idle_span_finish_reason']).toBe('idleTimeout');
51-
});
52-
534
test('idleTimeout: Captures all activity with increased timeout', async ({ page }) => {
545
const transactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
556
return (
@@ -87,9 +38,8 @@ test('idleTimeout: Finishes prematurely with low timeout', async ({ page }) => {
8738
);
8839
});
8940

90-
// Very low idleTimeout (50ms) and lazyRouteTimeout (100ms)
91-
// Transaction finishes quickly, but still gets parameterized route name
92-
await page.goto('/?idleTimeout=50&timeout=100');
41+
// Very low idleTimeout (50ms) -- transaction finishes quickly but still gets parameterized route name
42+
await page.goto('/?idleTimeout=50');
9343

9444
const navigationLink = page.locator('id=navigation-to-deep');
9545
await expect(navigationLink).toBeVisible();

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

Lines changed: 11 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,7 @@ test('Updates pageload transaction name correctly when span is cancelled early (
427427
// Check if the span was indeed cancelled (should have idle_span_finish_reason attribute)
428428
const idleSpanFinishReason = event.contexts?.trace?.data?.['sentry.idle_span_finish_reason'];
429429
if (idleSpanFinishReason) {
430-
// If the span was cancelled due to visibility change, verify it still got the right name
431-
expect(['externalFinish', 'cancelled']).toContain(idleSpanFinishReason);
430+
expect(['externalFinish', 'cancelled', 'idleTimeout']).toContain(idleSpanFinishReason);
432431
}
433432
});
434433

@@ -498,7 +497,7 @@ test('Updates navigation transaction name correctly when span is cancelled early
498497
}
499498

500499
if (idleSpanFinishReason) {
501-
expect(['externalFinish', 'cancelled']).toContain(idleSpanFinishReason);
500+
expect(['externalFinish', 'cancelled', 'idleTimeout']).toContain(idleSpanFinishReason);
502501
}
503502
});
504503

@@ -1034,9 +1033,11 @@ test('Three-route rapid navigation preserves distinct transaction names', async
10341033
await slowFetchLink.click();
10351034
await page.waitForTimeout(150);
10361035

1037-
// Navigate to another-lazy before slow-fetch resolves
1038-
const anotherLazyLink = page.locator('id=delayed-lazy-to-another-lazy');
1039-
await anotherLazyLink.click();
1036+
// Navigate to another-lazy before slow-fetch resolves.
1037+
// Use programmatic navigation because the delayed-lazy page may have
1038+
// already unmounted (the /slow-fetch route has no element).
1039+
// eslint-disable-next-line no-restricted-globals
1040+
await page.evaluate(() => (window as any).__REACT_ROUTER__.navigate('/another-lazy/sub'));
10401041

10411042
await expect(page.locator('id=another-lazy-route')).toBeVisible({ timeout: 10000 });
10421043
await page.waitForTimeout(2000);
@@ -1241,8 +1242,8 @@ test('Slow lazy route pageload with early span end still gets parameterized rout
12411242
);
12421243
});
12431244

1244-
// idleTimeout=300 ends span before 500ms lazy route loads, timeout=1000 waits for lazy routes
1245-
await page.goto('/slow-fetch/123?idleTimeout=300&timeout=1000');
1245+
// idleTimeout=300 ends span before 500ms lazy route loads
1246+
await page.goto('/slow-fetch/123?idleTimeout=300');
12461247

12471248
const event = await transactionPromise;
12481249

@@ -1255,60 +1256,6 @@ test('Slow lazy route pageload with early span end still gets parameterized rout
12551256
expect(['idleTimeout', 'externalFinish']).toContain(idleSpanFinishReason);
12561257
});
12571258

1258-
// Regression: Wildcard route names should be upgraded to parameterized routes when lazy routes load
1259-
test('Wildcard route pageload gets upgraded to parameterized route name (regression)', async ({ page }) => {
1260-
const transactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
1261-
return (
1262-
!!transactionEvent?.transaction &&
1263-
transactionEvent.contexts?.trace?.op === 'pageload' &&
1264-
(transactionEvent.transaction?.startsWith('/wildcard-lazy') ?? false)
1265-
);
1266-
});
1267-
1268-
await page.goto('/wildcard-lazy/456?idleTimeout=300&timeout=1000');
1269-
1270-
const event = await transactionPromise;
1271-
1272-
expect(event.transaction).toBe('/wildcard-lazy/:id');
1273-
expect(event.type).toBe('transaction');
1274-
expect(event.contexts?.trace?.op).toBe('pageload');
1275-
expect(event.contexts?.trace?.data?.['sentry.source']).toBe('route');
1276-
});
1277-
1278-
// Regression: Navigation to slow lazy route should get parameterized name even if span ends early.
1279-
// Network activity from dynamic imports extends the idle timeout until lazy routes load.
1280-
test('Slow lazy route navigation with early span end still gets parameterized route name (regression)', async ({
1281-
page,
1282-
}) => {
1283-
// Configure short idle timeout (300ms) but longer lazy route timeout (1000ms)
1284-
await page.goto('/?idleTimeout=300&timeout=1000');
1285-
1286-
// Wait for pageload to complete
1287-
await page.waitForTimeout(500);
1288-
1289-
const navigationPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
1290-
return (
1291-
!!transactionEvent?.transaction &&
1292-
transactionEvent.contexts?.trace?.op === 'navigation' &&
1293-
(transactionEvent.transaction?.startsWith('/wildcard-lazy') ?? false)
1294-
);
1295-
});
1296-
1297-
// Navigate to wildcard-lazy route (500ms delay in module via top-level await)
1298-
// The dynamic import creates network activity that extends the span lifetime
1299-
const wildcardLazyLink = page.locator('id=navigation-to-wildcard-lazy');
1300-
await expect(wildcardLazyLink).toBeVisible();
1301-
await wildcardLazyLink.click();
1302-
1303-
const event = await navigationPromise;
1304-
1305-
// The navigation transaction should have the parameterized route name
1306-
expect(event.transaction).toBe('/wildcard-lazy/:id');
1307-
expect(event.type).toBe('transaction');
1308-
expect(event.contexts?.trace?.op).toBe('navigation');
1309-
expect(event.contexts?.trace?.data?.['sentry.source']).toBe('route');
1310-
});
1311-
13121259
test('Captured navigation context is used instead of stale window.location during rapid navigation', async ({
13131260
page,
13141261
}) => {
@@ -1437,7 +1384,7 @@ test('Second navigation span is not corrupted by first slow lazy handler complet
14371384
// lazyRouteManifest: provides parameterized name when lazy routes don't resolve in time
14381385
test('Route manifest provides correct name when navigation span ends before lazy route resolves', async ({ page }) => {
14391386
// Short idle timeout (50ms) ensures span ends before lazy route (500ms) resolves
1440-
await page.goto('/?idleTimeout=50&timeout=0');
1387+
await page.goto('/?idleTimeout=50');
14411388

14421389
// Wait for pageload to complete
14431390
await page.waitForTimeout(200);
@@ -1474,7 +1421,7 @@ test('Route manifest provides correct name when pageload span ends before lazy r
14741421
);
14751422
});
14761423

1477-
await page.goto('/wildcard-lazy/123?idleTimeout=50&timeout=0');
1424+
await page.goto('/wildcard-lazy/123?idleTimeout=50');
14781425

14791426
const event = await pageloadPromise;
14801427

0 commit comments

Comments
 (0)