Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ const router = sentryCreateBrowserRouter(
lazyChildren: () => import('./pages/InnerLazyRoutes').then(module => module.someMoreNestedRoutes),
},
},
{
path: '/another-lazy',
handle: {
lazyChildren: () => import('./pages/AnotherLazyRoutes').then(module => module.anotherNestedRoutes),
},
},
{
path: '/static',
element: <>Hello World</>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { Link } from 'react-router-dom';

export const anotherNestedRoutes = [
{
path: 'sub',
children: [
{
index: true,
element: (
<div id="another-lazy-route">
Another Lazy Route
<Link to="/lazy/inner/999/888/777" id="navigate-to-inner">
Navigate to Inner Lazy Route
</Link>
</div>
),
},
{
path: ':id',
children: [
{
index: true,
element: <div id="another-lazy-route-with-id">Another Lazy Route with ID</div>,
},
{
path: ':subId',
element: (
<div id="another-lazy-route-deep">
Another Deep Lazy Route
<Link to="/lazy/inner/111/222/333" id="navigate-to-inner-from-deep">
Navigate to Inner from Deep
</Link>
</div>
),
},
],
},
],
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ const Index = () => {
<Link to="/lazy/inner/123/456/789" id="navigation">
navigate
</Link>
<br />
<Link to="/another-lazy/sub" id="navigation-to-another">
Navigate to Another Lazy Route
</Link>
<br />
<Link to="/another-lazy/sub/555/666" id="navigation-to-another-deep">
Navigate to Another Deep Lazy Route
</Link>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { Link } from 'react-router-dom';

export const someMoreNestedRoutes = [
{
Expand All @@ -24,9 +25,15 @@ export const someMoreNestedRoutes = [
},
{
path: ':someAnotherId',
element: <div id="innermost-lazy-route">
Rendered
</div>,
element: (
<div id="innermost-lazy-route">
Rendered
<br />
<Link to="/another-lazy/sub/888/999" id="navigate-to-another-from-inner">
Navigate to Another Lazy Route
</Link>
</div>
),
},
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,111 @@ test('Creates a navigation transaction inside a lazy route', async ({ page }) =>
expect(event.type).toBe('transaction');
expect(event.contexts?.trace?.op).toBe('navigation');
});

test('Creates navigation transactions between two different lazy routes', async ({ page }) => {
// First, navigate to the "another-lazy" route
const firstTransactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
return (
!!transactionEvent?.transaction &&
transactionEvent.contexts?.trace?.op === 'navigation' &&
transactionEvent.transaction === '/another-lazy/sub/:id/:subId'
);
});

await page.goto('/');

// Navigate to another lazy route first
const navigationToAnotherDeep = page.locator('id=navigation-to-another-deep');
await expect(navigationToAnotherDeep).toBeVisible();
await navigationToAnotherDeep.click();

const firstEvent = await firstTransactionPromise;

// Check if the first lazy route content is rendered
const anotherLazyContent = page.locator('id=another-lazy-route-deep');
await expect(anotherLazyContent).toBeVisible();

// Validate the first transaction event
expect(firstEvent.transaction).toBe('/another-lazy/sub/:id/:subId');
expect(firstEvent.type).toBe('transaction');
expect(firstEvent.contexts?.trace?.op).toBe('navigation');

// Now navigate from the first lazy route to the second lazy route
const secondTransactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
return (
!!transactionEvent?.transaction &&
transactionEvent.contexts?.trace?.op === 'navigation' &&
transactionEvent.transaction === '/lazy/inner/:id/:anotherId/:someAnotherId'
);
});

// Click the navigation link from within the first lazy route to the second lazy route
const navigationToInnerFromDeep = page.locator('id=navigate-to-inner-from-deep');
await expect(navigationToInnerFromDeep).toBeVisible();
await navigationToInnerFromDeep.click();

const secondEvent = await secondTransactionPromise;

// Check if the second lazy route content is rendered
const innerLazyContent = page.locator('id=innermost-lazy-route');
await expect(innerLazyContent).toBeVisible();

// Validate the second transaction event
expect(secondEvent.transaction).toBe('/lazy/inner/:id/:anotherId/:someAnotherId');
expect(secondEvent.type).toBe('transaction');
expect(secondEvent.contexts?.trace?.op).toBe('navigation');
});

test('Creates navigation transactions from inner lazy route to another lazy route', async ({ page }) => {
// First, navigate to the inner lazy route
const firstTransactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
return (
!!transactionEvent?.transaction &&
transactionEvent.contexts?.trace?.op === 'navigation' &&
transactionEvent.transaction === '/lazy/inner/:id/:anotherId/:someAnotherId'
);
});

await page.goto('/');

// Navigate to inner lazy route first
const navigationToInner = page.locator('id=navigation');
await expect(navigationToInner).toBeVisible();
await navigationToInner.click();

const firstEvent = await firstTransactionPromise;

// Check if the inner lazy route content is rendered
const innerLazyContent = page.locator('id=innermost-lazy-route');
await expect(innerLazyContent).toBeVisible();

// Validate the first transaction event
expect(firstEvent.transaction).toBe('/lazy/inner/:id/:anotherId/:someAnotherId');
expect(firstEvent.type).toBe('transaction');
expect(firstEvent.contexts?.trace?.op).toBe('navigation');

// Now navigate from the inner lazy route to another lazy route
const secondTransactionPromise = waitForTransaction('react-router-7-lazy-routes', async transactionEvent => {
return (
!!transactionEvent?.transaction &&
transactionEvent.contexts?.trace?.op === 'navigation' &&
transactionEvent.transaction === '/another-lazy/sub/:id/:subId'
);
});

// Click the navigation link from within the inner lazy route to another lazy route
const navigationToAnotherFromInner = page.locator('id=navigate-to-another-from-inner');
await expect(navigationToAnotherFromInner).toBeVisible();
await navigationToAnotherFromInner.click();

const secondEvent = await secondTransactionPromise;

// Check if the another lazy route content is rendered
const anotherLazyContent = page.locator('id=another-lazy-route-deep');
await expect(anotherLazyContent).toBeVisible();

// Validate the second transaction event
expect(secondEvent.transaction).toBe('/another-lazy/sub/:id/:subId');
expect(secondEvent.type).toBe('transaction');
expect(secondEvent.contexts?.trace?.op).toBe('navigation');
});
32 changes: 32 additions & 0 deletions packages/react/src/reactrouter-compat-utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Main exports from instrumentation
export type { ReactRouterOptions } from './instrumentation';
export {
createReactRouterV6CompatibleTracingIntegration,
createV6CompatibleWithSentryReactRouterRouting,
createV6CompatibleWrapCreateBrowserRouter,
createV6CompatibleWrapCreateMemoryRouter,
createV6CompatibleWrapUseRoutes,
handleNavigation,
handleExistingNavigationSpan,
createNewNavigationSpan,
addResolvedRoutesToParent,
processResolvedRoutes,
updateNavigationSpan,
} from './instrumentation';

// Utility exports
export {
resolveRouteNameAndSource,
getNormalizedName,
initializeRouterUtils,
isLikelyLazyRouteContext,
locationIsInsideDescendantRoute,
prefixWithSlash,
rebuildRoutePathFromAllRoutes,
pathEndsWithWildcard,
pathIsWildcardAndHasChildren,
getNumberOfUrlSegments,
} from './utils';

// Lazy route exports
export { createAsyncHandlerProxy, handleAsyncHandlerResult, checkRouteForAsyncHandler } from './lazy-routes';
Loading
Loading