Skip to content

Commit 3ebad79

Browse files
committed
ref(react): Add source to react-router-v3
1 parent 1cfcb0d commit 3ebad79

File tree

2 files changed

+99
-22
lines changed

2 files changed

+99
-22
lines changed

packages/react/src/reactrouterv3.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Primitive, Transaction, TransactionContext } from '@sentry/types';
1+
import { Primitive, Transaction, TransactionContext, TransactionSource } from '@sentry/types';
22
import { getGlobalObject } from '@sentry/utils';
33

44
import { Location, ReactRouterInstrumentation } from './types';
@@ -44,16 +44,24 @@ export function reactRouterV3Instrumentation(
4444

4545
// Have to use global.location because history.location might not be defined.
4646
if (startTransactionOnPageLoad && global && global.location) {
47-
normalizeTransactionName(routes, global.location as unknown as Location, match, (localName: string) => {
48-
prevName = localName;
49-
activeTransaction = startTransaction({
50-
name: prevName,
51-
op: 'pageload',
52-
tags: {
53-
'routing.instrumentation': 'react-router-v3',
54-
},
55-
});
56-
});
47+
normalizeTransactionName(
48+
routes,
49+
global.location as unknown as Location,
50+
match,
51+
(localName: string, source: TransactionSource = 'url') => {
52+
prevName = localName;
53+
activeTransaction = startTransaction({
54+
name: prevName,
55+
op: 'pageload',
56+
tags: {
57+
'routing.instrumentation': 'react-router-v3',
58+
},
59+
metadata: {
60+
source,
61+
},
62+
});
63+
},
64+
);
5765
}
5866

5967
if (startTransactionOnLocationChange && history.listen) {
@@ -68,12 +76,15 @@ export function reactRouterV3Instrumentation(
6876
if (prevName) {
6977
tags.from = prevName;
7078
}
71-
normalizeTransactionName(routes, location, match, (localName: string) => {
79+
normalizeTransactionName(routes, location, match, (localName: string, source: TransactionSource = 'url') => {
7280
prevName = localName;
7381
activeTransaction = startTransaction({
7482
name: prevName,
7583
op: 'navigation',
7684
tags,
85+
metadata: {
86+
source,
87+
},
7788
});
7889
});
7990
}
@@ -89,7 +100,7 @@ function normalizeTransactionName(
89100
appRoutes: Route[],
90101
location: Location,
91102
match: Match,
92-
callback: (pathname: string) => void,
103+
callback: (pathname: string, source?: TransactionSource) => void,
93104
): void {
94105
let name = location.pathname;
95106
match(
@@ -108,7 +119,7 @@ function normalizeTransactionName(
108119
}
109120

110121
name = routePath;
111-
return callback(name);
122+
return callback(name, 'route');
112123
},
113124
);
114125
}

packages/react/test/reactrouterv3.test.tsx

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ declare module 'react-router-3' {
1515
export const createRoutes: (routes: any) => RouteType[];
1616
}
1717

18+
function createMockStartTransaction(opts: { finish?: jest.FunctionLike; setMetadata?: jest.FunctionLike } = {}) {
19+
const { finish = jest.fn(), setMetadata = jest.fn() } = opts;
20+
return jest.fn().mockReturnValue({
21+
finish,
22+
setMetadata,
23+
});
24+
}
25+
1826
describe('React Router V3', () => {
1927
const routes = (
2028
<Route path="/" component={({ children }: { children: JSX.Element }) => <div>{children}</div>}>
@@ -37,24 +45,27 @@ describe('React Router V3', () => {
3745
const instrumentation = reactRouterV3Instrumentation(history, instrumentationRoutes, match);
3846

3947
it('starts a pageload transaction when instrumentation is started', () => {
40-
const mockStartTransaction = jest.fn();
48+
const mockStartTransaction = createMockStartTransaction();
4149
instrumentation(mockStartTransaction);
4250
expect(mockStartTransaction).toHaveBeenCalledTimes(1);
4351
expect(mockStartTransaction).toHaveBeenLastCalledWith({
4452
name: '/',
4553
op: 'pageload',
4654
tags: { 'routing.instrumentation': 'react-router-v3' },
55+
metadata: {
56+
source: 'route',
57+
},
4758
});
4859
});
4960

5061
it('does not start pageload transaction if option is false', () => {
51-
const mockStartTransaction = jest.fn();
62+
const mockStartTransaction = createMockStartTransaction();
5263
instrumentation(mockStartTransaction, false);
5364
expect(mockStartTransaction).toHaveBeenCalledTimes(0);
5465
});
5566

5667
it('starts a navigation transaction', () => {
57-
const mockStartTransaction = jest.fn();
68+
const mockStartTransaction = createMockStartTransaction();
5869
instrumentation(mockStartTransaction);
5970
render(<Router history={history}>{routes}</Router>);
6071

@@ -66,6 +77,9 @@ describe('React Router V3', () => {
6677
name: '/about',
6778
op: 'navigation',
6879
tags: { from: '/', 'routing.instrumentation': 'react-router-v3' },
80+
metadata: {
81+
source: 'route',
82+
},
6983
});
7084

7185
act(() => {
@@ -76,18 +90,21 @@ describe('React Router V3', () => {
7690
name: '/features',
7791
op: 'navigation',
7892
tags: { from: '/about', 'routing.instrumentation': 'react-router-v3' },
93+
metadata: {
94+
source: 'route',
95+
},
7996
});
8097
});
8198

8299
it('does not start a transaction if option is false', () => {
83-
const mockStartTransaction = jest.fn();
100+
const mockStartTransaction = createMockStartTransaction();
84101
instrumentation(mockStartTransaction, true, false);
85102
render(<Router history={history}>{routes}</Router>);
86103
expect(mockStartTransaction).toHaveBeenCalledTimes(1);
87104
});
88105

89106
it('only starts a navigation transaction on push', () => {
90-
const mockStartTransaction = jest.fn();
107+
const mockStartTransaction = createMockStartTransaction();
91108
instrumentation(mockStartTransaction);
92109
render(<Router history={history}>{routes}</Router>);
93110

@@ -99,7 +116,7 @@ describe('React Router V3', () => {
99116

100117
it('finishes a transaction on navigation', () => {
101118
const mockFinish = jest.fn();
102-
const mockStartTransaction = jest.fn().mockReturnValue({ finish: mockFinish });
119+
const mockStartTransaction = createMockStartTransaction({ finish: mockFinish });
103120
instrumentation(mockStartTransaction);
104121
render(<Router history={history}>{routes}</Router>);
105122
expect(mockStartTransaction).toHaveBeenCalledTimes(1);
@@ -112,7 +129,7 @@ describe('React Router V3', () => {
112129
});
113130

114131
it('normalizes transaction names', () => {
115-
const mockStartTransaction = jest.fn();
132+
const mockStartTransaction = createMockStartTransaction();
116133
instrumentation(mockStartTransaction);
117134
const { container } = render(<Router history={history}>{routes}</Router>);
118135

@@ -126,11 +143,14 @@ describe('React Router V3', () => {
126143
name: '/users/:userid',
127144
op: 'navigation',
128145
tags: { from: '/', 'routing.instrumentation': 'react-router-v3' },
146+
metadata: {
147+
source: 'route',
148+
},
129149
});
130150
});
131151

132152
it('normalizes nested transaction names', () => {
133-
const mockStartTransaction = jest.fn();
153+
const mockStartTransaction = createMockStartTransaction();
134154
instrumentation(mockStartTransaction);
135155
const { container } = render(<Router history={history}>{routes}</Router>);
136156

@@ -144,6 +164,9 @@ describe('React Router V3', () => {
144164
name: '/organizations/:orgid/v1/:teamid',
145165
op: 'navigation',
146166
tags: { from: '/', 'routing.instrumentation': 'react-router-v3' },
167+
metadata: {
168+
source: 'route',
169+
},
147170
});
148171

149172
act(() => {
@@ -156,6 +179,49 @@ describe('React Router V3', () => {
156179
name: '/organizations/:orgid',
157180
op: 'navigation',
158181
tags: { from: '/organizations/:orgid/v1/:teamid', 'routing.instrumentation': 'react-router-v3' },
182+
metadata: {
183+
source: 'route',
184+
},
185+
});
186+
});
187+
188+
it('sets metadata to url if on an unknown route', () => {
189+
const mockStartTransaction = createMockStartTransaction();
190+
instrumentation(mockStartTransaction);
191+
render(<Router history={history}>{routes}</Router>);
192+
193+
act(() => {
194+
history.push('/organizations/1234/some/other/route');
195+
});
196+
197+
expect(mockStartTransaction).toHaveBeenCalledTimes(2);
198+
expect(mockStartTransaction).toHaveBeenLastCalledWith({
199+
name: '/organizations/1234/some/other/route',
200+
op: 'navigation',
201+
tags: { from: '/', 'routing.instrumentation': 'react-router-v3' },
202+
metadata: {
203+
source: 'url',
204+
},
205+
});
206+
});
207+
208+
it('sets metadata to url if no routes are provided', () => {
209+
const fakeRoutes = <div>hello</div>;
210+
const mockStartTransaction = createMockStartTransaction();
211+
const mockInstrumentation = reactRouterV3Instrumentation(history, createRoutes(fakeRoutes), match);
212+
mockInstrumentation(mockStartTransaction);
213+
// We render here with `routes` instead of `fakeRoutes` from above to validate the case
214+
// where users provided the instrumentation with a bad set of routes.
215+
render(<Router history={history}>{routes}</Router>);
216+
217+
expect(mockStartTransaction).toHaveBeenCalledTimes(1);
218+
expect(mockStartTransaction).toHaveBeenLastCalledWith({
219+
name: '/',
220+
op: 'pageload',
221+
tags: { 'routing.instrumentation': 'react-router-v3' },
222+
metadata: {
223+
source: 'url',
224+
},
159225
});
160226
});
161227
});

0 commit comments

Comments
 (0)