From 877553cb582512338dd2b1d27beb034a6cecd4f6 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 15 Apr 2024 17:25:51 +0200 Subject: [PATCH] test(browser-integration-tests): Test trace lifetime for outgoing `fetch` requests --- .../suites/tracing/trace-lifetime/init.js | 1 + .../tracing/trace-lifetime/navigation/test.ts | 71 +++++++++++++++++-- .../tracing/trace-lifetime/pageload/test.ts | 58 +++++++++++++++ .../suites/tracing/trace-lifetime/subject.js | 5 ++ .../tracing/trace-lifetime/template.html | 1 + 5 files changed, 132 insertions(+), 4 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/init.js b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/init.js index 83076460599f..7cd076a052e5 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/init.js +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/init.js @@ -5,5 +5,6 @@ window.Sentry = Sentry; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', integrations: [Sentry.browserTracingIntegration()], + tracePropagationTargets: ['http://example.com'], tracesSampleRate: 1, }); diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/navigation/test.ts b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/navigation/test.ts index bf4e4445b0af..0ed99e3b7ec9 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/navigation/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/navigation/test.ts @@ -45,10 +45,9 @@ sentryTest('error after navigation has navigation traceId', async ({ getLocalTes const navigationTraceId = navigationEvent.contexts?.trace?.trace_id; expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/); - const [, errorEvent] = await Promise.all([ - page.locator('#errorBtn').click(), - getFirstSentryEnvelopeRequest(page), - ]); + const errorEventPromise = getFirstSentryEnvelopeRequest(page); + await page.locator('#errorBtn').click(); + const errorEvent = await errorEventPromise; const errorTraceId = errorEvent.contexts?.trace?.trace_id; expect(errorTraceId).toBe(navigationTraceId); @@ -80,3 +79,67 @@ sentryTest('error during navigation has new navigation traceId', async ({ getLoc const errorTraceId = errorEvent?.contexts?.trace?.trace_id; expect(errorTraceId).toBe(navigationTraceId); }); + +sentryTest( + 'outgoing fetch request after navigation has navigation traceId in headers', + async ({ getLocalTestPath, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestPath({ testDir: __dirname }); + + // ensure navigation transaction is finished + await getFirstSentryEnvelopeRequest(page, url); + + const navigationEvent = await getFirstSentryEnvelopeRequest(page, `${url}#foo`); + expect(navigationEvent.contexts?.trace?.op).toBe('navigation'); + + const navigationTraceId = navigationEvent.contexts?.trace?.trace_id; + expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/); + + const requestPromise = page.waitForRequest('http://example.com/*'); + await page.locator('#fetchBtn').click(); + const request = await requestPromise; + const headers = request.headers(); + + // sampling decision is deferred b/c of no active span at the time of request + expect(headers['sentry-trace']).toMatch(new RegExp(`^${navigationTraceId}-[0-9a-f]{16}$`)); + expect(headers['baggage']).toEqual( + `sentry-environment=production,sentry-public_key=public,sentry-trace_id=${navigationTraceId}`, + ); + }, +); + +sentryTest( + 'outgoing fetch request during navigation has navigation traceId in headers', + async ({ getLocalTestPath, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestPath({ testDir: __dirname }); + + // ensure navigation transaction is finished + await getFirstSentryEnvelopeRequest(page, url); + + const navigationEventPromise = getFirstSentryEnvelopeRequest(page); + const requestPromise = page.waitForRequest('http://example.com/*'); + await page.goto(`${url}#foo`); + await page.locator('#fetchBtn').click(); + const [navigationEvent, request] = await Promise.all([navigationEventPromise, requestPromise]); + + expect(navigationEvent.contexts?.trace?.op).toBe('navigation'); + + const navigationTraceId = navigationEvent.contexts?.trace?.trace_id; + expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/); + + const headers = request.headers(); + + // sampling decision is propagated from active span sampling decision + expect(headers['sentry-trace']).toMatch(new RegExp(`^${navigationTraceId}-[0-9a-f]{16}-1$`)); + expect(headers['baggage']).toEqual( + `sentry-environment=production,sentry-public_key=public,sentry-trace_id=${navigationTraceId},sentry-sample_rate=1,sentry-sampled=true`, + ); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/pageload/test.ts b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/pageload/test.ts index d1a847e01e2c..69141a107bbc 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/pageload/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/pageload/test.ts @@ -76,3 +76,61 @@ sentryTest('error during pageload has pageload traceId', async ({ getLocalTestPa const errorTraceId = errorEvent?.contexts?.trace?.trace_id; expect(errorTraceId).toBe(pageloadTraceId); }); + +sentryTest( + 'outgoing fetch request after pageload has pageload traceId in headers', + async ({ getLocalTestPath, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestPath({ testDir: __dirname }); + + const pageloadEvent = await getFirstSentryEnvelopeRequest(page, url); + expect(pageloadEvent.contexts?.trace?.op).toBe('pageload'); + + const pageloadTraceId = pageloadEvent.contexts?.trace?.trace_id; + expect(pageloadTraceId).toMatch(/^[0-9a-f]{32}$/); + + const requestPromise = page.waitForRequest('http://example.com/*'); + await page.locator('#fetchBtn').click(); + const request = await requestPromise; + const headers = request.headers(); + + // sampling decision is deferred b/c of no active span at the time of request + expect(headers['sentry-trace']).toMatch(new RegExp(`^${pageloadTraceId}-[0-9a-f]{16}$`)); + expect(headers['baggage']).toEqual( + `sentry-environment=production,sentry-public_key=public,sentry-trace_id=${pageloadTraceId}`, + ); + }, +); + +sentryTest( + 'outgoing fetch request during pageload has pageload traceId in headers', + async ({ getLocalTestPath, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestPath({ testDir: __dirname }); + + const pageloadEventPromise = getFirstSentryEnvelopeRequest(page); + const requestPromise = page.waitForRequest('http://example.com/*'); + await page.goto(url); + await page.locator('#fetchBtn').click(); + const [pageloadEvent, request] = await Promise.all([pageloadEventPromise, requestPromise]); + + expect(pageloadEvent.contexts?.trace?.op).toBe('pageload'); + + const navigationTraceId = pageloadEvent.contexts?.trace?.trace_id; + expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/); + + const headers = request.headers(); + + // sampling decision is propagated from active span sampling decision + expect(headers['sentry-trace']).toMatch(new RegExp(`^${navigationTraceId}-[0-9a-f]{16}-1$`)); + expect(headers['baggage']).toEqual( + `sentry-environment=production,sentry-public_key=public,sentry-trace_id=${navigationTraceId},sentry-sample_rate=1,sentry-sampled=true`, + ); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/subject.js b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/subject.js index 5131ea7631e9..38e475a5f216 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/subject.js +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/subject.js @@ -2,3 +2,8 @@ const errorBtn = document.getElementById('errorBtn'); errorBtn.addEventListener('click', () => { throw new Error('Sentry Test Error'); }); + +const fetchBtn = document.getElementById('fetchBtn'); +fetchBtn.addEventListener('click', async () => { + await fetch('http://example.com'); +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/template.html b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/template.html index a29ad2056a45..218c42031ccf 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/template.html +++ b/dev-packages/browser-integration-tests/suites/tracing/trace-lifetime/template.html @@ -5,5 +5,6 @@ +