diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/init.js new file mode 100644 index 000000000000..63ce47b4c91c --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/init.js @@ -0,0 +1,13 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + tracesSampleRate: 1, + integrations: [ + Sentry.browserTracingIntegration({ + _experiments: { enableInteractions: true }, + }), + ], +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/subject.js new file mode 100644 index 000000000000..f45d2c974586 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/subject.js @@ -0,0 +1,7 @@ +// Clicking the navigate button will push a new history state, triggering navigation +document.querySelector('[data-test-id=navigate-button]').addEventListener('click', () => { + const loc = window.location; + const url = loc.href.includes('#nav') ? loc.pathname : `${loc.pathname}#nav`; + + history.pushState({}, '', url); +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/template.html b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/template.html new file mode 100644 index 000000000000..789445ddfdd4 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/test.ts new file mode 100644 index 000000000000..4931aaa4b172 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions-navigation-click/test.ts @@ -0,0 +1,39 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../../utils/fixtures'; +import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers'; + +sentryTest( + 'click-triggered navigation should produce a root navigation transaction', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + await waitForTransactionRequest(page); // "pageload" root span + + const interactionRequestPromise = waitForTransactionRequest( + page, + evt => evt.contexts?.trace?.op === 'ui.action.click', + ); + const navigationRequestPromise = waitForTransactionRequest(page, evt => evt.contexts?.trace?.op === 'navigation'); + + await page.locator('[data-test-id=navigate-button]').click(); + + const interactionEvent = envelopeRequestParser(await interactionRequestPromise); + const navigationEvent = envelopeRequestParser(await navigationRequestPromise); + + // Navigation is root span, not a child span on the interaction + expect(interactionEvent.contexts?.trace?.op).toBe('ui.action.click'); + expect(navigationEvent.contexts?.trace?.op).toBe('navigation'); + + expect(interactionEvent.contexts?.trace?.trace_id).not.toEqual(navigationEvent.contexts?.trace?.trace_id); + + // does not contain a child navigation span + const interactionSpans = interactionEvent.spans || []; + const hasNavigationChild = interactionSpans.some(span => span.op === 'navigation' || span.op === 'http.server'); + expect(hasNavigationChild).toBeFalsy(); + }, +); diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index edec1b1617b6..305b1e0322a0 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -536,6 +536,9 @@ export const browserTracingIntegration = ((_options: Partial