From 04add0ce9717703df995adc3d76682c8efa2dc72 Mon Sep 17 00:00:00 2001 From: sid Date: Mon, 12 May 2025 20:07:59 -0700 Subject: [PATCH 1/2] test(react): Handle nested parameterized routes in reactrouterv3 transaction normalization --- packages/react/src/reactrouterv3.ts | 14 +++++++++++--- packages/react/test/reactrouterv3.test.tsx | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/react/src/reactrouterv3.ts b/packages/react/src/reactrouterv3.ts index 73058307353f..6a21a080783f 100644 --- a/packages/react/src/reactrouterv3.ts +++ b/packages/react/src/reactrouterv3.ts @@ -150,9 +150,17 @@ function getRouteStringFromRoutes(routes: Route[]): string { } } - return routesWithPaths + const pathParts = routesWithPaths .slice(index) .filter(({ path }) => !!path) - .map(({ path }) => path) - .join(''); + .map(({ path }) => path); + + // Join all parts with '/', then replace multiple slashes with a single one. + let fullPath = pathParts.join('/'); + fullPath = fullPath.replace(/\/+/g, '/'); + + // Edge case: If the path started with multiple slashes and routes, + // like `//foo`, it might become `/foo`. This is generally acceptable. + + return fullPath; } diff --git a/packages/react/test/reactrouterv3.test.tsx b/packages/react/test/reactrouterv3.test.tsx index 841cbf018647..18fc34527c3f 100644 --- a/packages/react/test/reactrouterv3.test.tsx +++ b/packages/react/test/reactrouterv3.test.tsx @@ -64,6 +64,11 @@ describe('browserTracingReactRouterV3', () => {
OrgId
} />
Team
} />
+ + +
Team Details
} /> +
+
); const history = createMemoryHistory(); @@ -192,6 +197,22 @@ describe('browserTracingReactRouterV3', () => { [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation', }, }); + expect(getCurrentScope().getScopeData().transactionName).toEqual('/users/:userid'); + + act(() => { + history.push('/teams/456/details'); + }); + + expect(mockStartBrowserTracingNavigationSpan).toHaveBeenCalledTimes(2); + expect(mockStartBrowserTracingNavigationSpan).toHaveBeenLastCalledWith(expect.any(BrowserClient), { + name: '/teams/:teamId/details', + attributes: { + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react.reactrouter_v3', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation', + }, + }); + expect(getCurrentScope().getScopeData().transactionName).toEqual('/teams/:teamId/details'); }); it("updates the scope's `transactionName` on a navigation", () => { From c1144e2734510ca6e38406499781b93c5718ea71 Mon Sep 17 00:00:00 2001 From: sid Date: Tue, 13 May 2025 11:15:10 -0700 Subject: [PATCH 2/2] Combine filter and map with reduce --- packages/react/src/reactrouterv3.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/react/src/reactrouterv3.ts b/packages/react/src/reactrouterv3.ts index 6a21a080783f..f49948a2a74b 100644 --- a/packages/react/src/reactrouterv3.ts +++ b/packages/react/src/reactrouterv3.ts @@ -150,17 +150,8 @@ function getRouteStringFromRoutes(routes: Route[]): string { } } - const pathParts = routesWithPaths - .slice(index) - .filter(({ path }) => !!path) - .map(({ path }) => path); - - // Join all parts with '/', then replace multiple slashes with a single one. - let fullPath = pathParts.join('/'); - fullPath = fullPath.replace(/\/+/g, '/'); - - // Edge case: If the path started with multiple slashes and routes, - // like `//foo`, it might become `/foo`. This is generally acceptable. - - return fullPath; + return routesWithPaths.slice(index).reduce((acc, { path }) => { + const pathSegment = acc === '/' || acc === '' ? path : `/${path}`; + return `${acc}${pathSegment}`; + }, ''); }