Skip to content

Commit 8cb70e3

Browse files
authored
test(browser-integration-tests): Test trace lifetime for outgoing fetch requests (#11614)
Add test for `sentry-trace` and `baggage` header values so that the headers contain the correct traceId in the folllowing four scenarios: * request during pageload span * request after pageload span * request during navigation span * request after navigation span
1 parent 1a715fc commit 8cb70e3

File tree

5 files changed

+132
-4
lines changed

5 files changed

+132
-4
lines changed

dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/init.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ window.Sentry = Sentry;
55
Sentry.init({
66
dsn: 'https://public@dsn.ingest.sentry.io/1337',
77
integrations: [Sentry.browserTracingIntegration()],
8+
tracePropagationTargets: ['http://example.com'],
89
tracesSampleRate: 1,
910
});

dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/navigation/test.ts

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,9 @@ sentryTest('error after navigation has navigation traceId', async ({ getLocalTes
4545
const navigationTraceId = navigationEvent.contexts?.trace?.trace_id;
4646
expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/);
4747

48-
const [, errorEvent] = await Promise.all([
49-
page.locator('#errorBtn').click(),
50-
getFirstSentryEnvelopeRequest<Event>(page),
51-
]);
48+
const errorEventPromise = getFirstSentryEnvelopeRequest<Event>(page);
49+
await page.locator('#errorBtn').click();
50+
const errorEvent = await errorEventPromise;
5251

5352
const errorTraceId = errorEvent.contexts?.trace?.trace_id;
5453
expect(errorTraceId).toBe(navigationTraceId);
@@ -80,3 +79,67 @@ sentryTest('error during navigation has new navigation traceId', async ({ getLoc
8079
const errorTraceId = errorEvent?.contexts?.trace?.trace_id;
8180
expect(errorTraceId).toBe(navigationTraceId);
8281
});
82+
83+
sentryTest(
84+
'outgoing fetch request after navigation has navigation traceId in headers',
85+
async ({ getLocalTestPath, page }) => {
86+
if (shouldSkipTracingTest()) {
87+
sentryTest.skip();
88+
}
89+
90+
const url = await getLocalTestPath({ testDir: __dirname });
91+
92+
// ensure navigation transaction is finished
93+
await getFirstSentryEnvelopeRequest<Event>(page, url);
94+
95+
const navigationEvent = await getFirstSentryEnvelopeRequest<Event>(page, `${url}#foo`);
96+
expect(navigationEvent.contexts?.trace?.op).toBe('navigation');
97+
98+
const navigationTraceId = navigationEvent.contexts?.trace?.trace_id;
99+
expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/);
100+
101+
const requestPromise = page.waitForRequest('http://example.com/*');
102+
await page.locator('#fetchBtn').click();
103+
const request = await requestPromise;
104+
const headers = request.headers();
105+
106+
// sampling decision is deferred b/c of no active span at the time of request
107+
expect(headers['sentry-trace']).toMatch(new RegExp(`^${navigationTraceId}-[0-9a-f]{16}$`));
108+
expect(headers['baggage']).toEqual(
109+
`sentry-environment=production,sentry-public_key=public,sentry-trace_id=${navigationTraceId}`,
110+
);
111+
},
112+
);
113+
114+
sentryTest(
115+
'outgoing fetch request during navigation has navigation traceId in headers',
116+
async ({ getLocalTestPath, page }) => {
117+
if (shouldSkipTracingTest()) {
118+
sentryTest.skip();
119+
}
120+
121+
const url = await getLocalTestPath({ testDir: __dirname });
122+
123+
// ensure navigation transaction is finished
124+
await getFirstSentryEnvelopeRequest<Event>(page, url);
125+
126+
const navigationEventPromise = getFirstSentryEnvelopeRequest<Event>(page);
127+
const requestPromise = page.waitForRequest('http://example.com/*');
128+
await page.goto(`${url}#foo`);
129+
await page.locator('#fetchBtn').click();
130+
const [navigationEvent, request] = await Promise.all([navigationEventPromise, requestPromise]);
131+
132+
expect(navigationEvent.contexts?.trace?.op).toBe('navigation');
133+
134+
const navigationTraceId = navigationEvent.contexts?.trace?.trace_id;
135+
expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/);
136+
137+
const headers = request.headers();
138+
139+
// sampling decision is propagated from active span sampling decision
140+
expect(headers['sentry-trace']).toMatch(new RegExp(`^${navigationTraceId}-[0-9a-f]{16}-1$`));
141+
expect(headers['baggage']).toEqual(
142+
`sentry-environment=production,sentry-public_key=public,sentry-trace_id=${navigationTraceId},sentry-sample_rate=1,sentry-sampled=true`,
143+
);
144+
},
145+
);

dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/pageload/test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,61 @@ sentryTest('error during pageload has pageload traceId', async ({ getLocalTestPa
7676
const errorTraceId = errorEvent?.contexts?.trace?.trace_id;
7777
expect(errorTraceId).toBe(pageloadTraceId);
7878
});
79+
80+
sentryTest(
81+
'outgoing fetch request after pageload has pageload traceId in headers',
82+
async ({ getLocalTestPath, page }) => {
83+
if (shouldSkipTracingTest()) {
84+
sentryTest.skip();
85+
}
86+
87+
const url = await getLocalTestPath({ testDir: __dirname });
88+
89+
const pageloadEvent = await getFirstSentryEnvelopeRequest<Event>(page, url);
90+
expect(pageloadEvent.contexts?.trace?.op).toBe('pageload');
91+
92+
const pageloadTraceId = pageloadEvent.contexts?.trace?.trace_id;
93+
expect(pageloadTraceId).toMatch(/^[0-9a-f]{32}$/);
94+
95+
const requestPromise = page.waitForRequest('http://example.com/*');
96+
await page.locator('#fetchBtn').click();
97+
const request = await requestPromise;
98+
const headers = request.headers();
99+
100+
// sampling decision is deferred b/c of no active span at the time of request
101+
expect(headers['sentry-trace']).toMatch(new RegExp(`^${pageloadTraceId}-[0-9a-f]{16}$`));
102+
expect(headers['baggage']).toEqual(
103+
`sentry-environment=production,sentry-public_key=public,sentry-trace_id=${pageloadTraceId}`,
104+
);
105+
},
106+
);
107+
108+
sentryTest(
109+
'outgoing fetch request during pageload has pageload traceId in headers',
110+
async ({ getLocalTestPath, page }) => {
111+
if (shouldSkipTracingTest()) {
112+
sentryTest.skip();
113+
}
114+
115+
const url = await getLocalTestPath({ testDir: __dirname });
116+
117+
const pageloadEventPromise = getFirstSentryEnvelopeRequest<Event>(page);
118+
const requestPromise = page.waitForRequest('http://example.com/*');
119+
await page.goto(url);
120+
await page.locator('#fetchBtn').click();
121+
const [pageloadEvent, request] = await Promise.all([pageloadEventPromise, requestPromise]);
122+
123+
expect(pageloadEvent.contexts?.trace?.op).toBe('pageload');
124+
125+
const navigationTraceId = pageloadEvent.contexts?.trace?.trace_id;
126+
expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/);
127+
128+
const headers = request.headers();
129+
130+
// sampling decision is propagated from active span sampling decision
131+
expect(headers['sentry-trace']).toMatch(new RegExp(`^${navigationTraceId}-[0-9a-f]{16}-1$`));
132+
expect(headers['baggage']).toEqual(
133+
`sentry-environment=production,sentry-public_key=public,sentry-trace_id=${navigationTraceId},sentry-sample_rate=1,sentry-sampled=true`,
134+
);
135+
},
136+
);

dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/subject.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@ const errorBtn = document.getElementById('errorBtn');
22
errorBtn.addEventListener('click', () => {
33
throw new Error('Sentry Test Error');
44
});
5+
6+
const fetchBtn = document.getElementById('fetchBtn');
7+
fetchBtn.addEventListener('click', async () => {
8+
await fetch('http://example.com');
9+
});

dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/template.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
</head>
66
<body>
77
<button id="errorBtn">Throw Error</button>
8+
<button id="fetchBtn">Fetch Request</button>
89
</body>
910
</html>

0 commit comments

Comments
 (0)