Skip to content

Commit cb8e92e

Browse files
committed
feat(browser): Detect redirects when emitting navigation spans
1 parent 76b7f3a commit cb8e92e

File tree

19 files changed

+439
-41
lines changed

19 files changed

+439
-41
lines changed

.size-limit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ module.exports = [
120120
import: createImport('init', 'ErrorBoundary', 'reactRouterV6BrowserTracingIntegration'),
121121
ignore: ['react/jsx-runtime'],
122122
gzip: true,
123-
limit: '40.5 KB',
123+
limit: '41 KB',
124124
},
125125
// Vue SDK (ESM)
126126
{

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/linked-traces/negatively-sampled/init.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ window.Sentry = Sentry;
44

55
Sentry.init({
66
dsn: 'https://[email protected]/1337',
7-
integrations: [Sentry.browserTracingIntegration()],
7+
// We want to ignore redirects for this test
8+
integrations: [Sentry.browserTracingIntegration({ detectRedirects: false })],
89
tracesSampler: ctx => {
910
if (ctx.attributes['sentry.origin'] === 'auto.pageload.browser') {
1011
return 0;

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/navigation-aborting-pageload/init.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ window.Sentry = Sentry;
44

55
Sentry.init({
66
dsn: 'https://[email protected]/1337',
7-
integrations: [Sentry.browserTracingIntegration()],
7+
integrations: [Sentry.browserTracingIntegration({ idleTimeout: 2000 })],
88
tracesSampleRate: 1,
99
});
1010

11-
// Immediately navigate to a new page to abort the pageload
12-
window.history.pushState({}, '', '/sub-page');
11+
// Navigate to a new page to abort the pageload
12+
// We have to wait >300ms to avoid the redirect handling
13+
setTimeout(() => {
14+
window.history.pushState({}, '', '/sub-page');
15+
}, 500);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: [Sentry.browserTracingIntegration()],
8+
tracesSampleRate: 1,
9+
debug: true,
10+
});
11+
12+
document.getElementById('btn1').addEventListener('click', () => {
13+
// Trigger navigation later than click, so the last click is more than 300ms ago
14+
setTimeout(() => {
15+
window.history.pushState({}, '', '/sub-page');
16+
17+
// then trigger redirect inside of this navigation, which should be detected as a redirect
18+
// because the last click was more than 300ms ago
19+
setTimeout(() => {
20+
window.history.pushState({}, '', '/sub-page-redirect');
21+
}, 100);
22+
}, 400);
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<button id="btn1">Trigger navigation</button>
7+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { expect } from '@playwright/test';
2+
import { sentryTest } from '../../../../../utils/fixtures';
3+
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../../utils/helpers';
4+
5+
sentryTest(
6+
'should create a navigation.redirect span if a click happened more than 300ms before navigation',
7+
async ({ getLocalTestUrl, page }) => {
8+
if (shouldSkipTracingTest()) {
9+
sentryTest.skip();
10+
}
11+
12+
const url = await getLocalTestUrl({ testDir: __dirname });
13+
14+
const pageloadRequestPromise = waitForTransactionRequest(page, event => event.contexts?.trace?.op === 'pageload');
15+
const navigationRequestPromise = waitForTransactionRequest(
16+
page,
17+
event => event.contexts?.trace?.op === 'navigation',
18+
);
19+
20+
await page.goto(url);
21+
22+
await pageloadRequestPromise;
23+
24+
// Now trigger navigation, and then a redirect in the navigation, with
25+
await page.click('#btn1');
26+
27+
const navigationRequest = envelopeRequestParser(await navigationRequestPromise);
28+
29+
expect(navigationRequest.contexts?.trace?.op).toBe('navigation');
30+
expect(navigationRequest.transaction).toEqual('/sub-page');
31+
32+
const spans = navigationRequest.spans || [];
33+
34+
expect(spans).toContainEqual(
35+
expect.objectContaining({
36+
op: 'navigation.redirect',
37+
description: '/sub-page-redirect',
38+
}),
39+
);
40+
},
41+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: [Sentry.browserTracingIntegration()],
8+
tracesSampleRate: 1,
9+
debug: true,
10+
});
11+
12+
document.getElementById('btn1').addEventListener('click', () => {
13+
// trigger redirect immediately
14+
window.history.pushState({}, '', '/sub-page');
15+
});
16+
17+
// Now trigger click, whic should trigger navigation
18+
document.getElementById('btn1').click();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<button id="btn1">Trigger navigation</button>
7+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { expect } from '@playwright/test';
2+
import { sentryTest } from '../../../../../utils/fixtures';
3+
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../../utils/helpers';
4+
5+
sentryTest(
6+
'should not create a navigation.redirect span if a click happened before navigation',
7+
async ({ getLocalTestUrl, page }) => {
8+
if (shouldSkipTracingTest()) {
9+
sentryTest.skip();
10+
}
11+
12+
const url = await getLocalTestUrl({ testDir: __dirname });
13+
14+
const pageloadRequestPromise = waitForTransactionRequest(page, event => event.contexts?.trace?.op === 'pageload');
15+
const navigationRequestPromise = waitForTransactionRequest(
16+
page,
17+
event => event.contexts?.trace?.op === 'navigation',
18+
);
19+
20+
await page.goto(url);
21+
22+
const pageloadRequest = envelopeRequestParser(await pageloadRequestPromise);
23+
// Ensure a navigation span is sent, too
24+
await navigationRequestPromise;
25+
26+
const spans = pageloadRequest.spans || [];
27+
28+
expect(spans).not.toContainEqual(
29+
expect.objectContaining({
30+
op: 'navigation.redirect',
31+
}),
32+
);
33+
},
34+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: [Sentry.browserTracingIntegration()],
8+
tracesSampleRate: 1,
9+
});
10+
11+
// trigger redirect immediately
12+
window.history.pushState({}, '', '/sub-page');

0 commit comments

Comments
 (0)