diff --git a/.size-limit.js b/.size-limit.js index 5e94a923e656..739c3f62aae1 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -3,28 +3,28 @@ module.exports = [ { name: '@sentry/browser (incl. Tracing, Replay, Feedback) - Webpack (gzipped)', path: 'packages/browser/build/npm/esm/index.js', - import: '{ init, Replay, BrowserTracing, Feedback }', + import: '{ init, Replay, browserTracingIntegration, Feedback }', gzip: true, limit: '90 KB', }, { name: '@sentry/browser (incl. Tracing, Replay) - Webpack (gzipped)', path: 'packages/browser/build/npm/esm/index.js', - import: '{ init, Replay, BrowserTracing }', + import: '{ init, Replay, browserTracingIntegration }', gzip: true, limit: '75 KB', }, { name: '@sentry/browser (incl. Tracing, Replay with Canvas) - Webpack (gzipped)', path: 'packages/browser/build/npm/esm/index.js', - import: '{ init, Replay, BrowserTracing, ReplayCanvas }', + import: '{ init, Replay, browserTracingIntegration, ReplayCanvas }', gzip: true, limit: '90 KB', }, { name: '@sentry/browser (incl. Tracing, Replay) - Webpack with treeshaking flags (gzipped)', path: 'packages/browser/build/npm/esm/index.js', - import: '{ init, Replay, BrowserTracing }', + import: '{ init, Replay, browserTracingIntegration }', gzip: true, limit: '75 KB', modifyWebpackConfig: function (config) { @@ -43,7 +43,7 @@ module.exports = [ { name: '@sentry/browser (incl. Tracing) - Webpack (gzipped)', path: 'packages/browser/build/npm/esm/index.js', - import: '{ init, BrowserTracing }', + import: '{ init, browserTracingIntegration }', gzip: true, limit: '35 KB', }, @@ -138,7 +138,7 @@ module.exports = [ { name: '@sentry/react (incl. Tracing, Replay) - Webpack (gzipped)', path: 'packages/react/build/esm/index.js', - import: '{ init, BrowserTracing, Replay }', + import: '{ init, browserTracingIntegration, Replay }', gzip: true, limit: '75 KB', }, @@ -154,7 +154,7 @@ module.exports = [ { name: '@sentry/nextjs Client (incl. Tracing, Replay) - Webpack (gzipped)', path: 'packages/nextjs/build/esm/client/index.js', - import: '{ init, BrowserTracing, Replay }', + import: '{ init, browserTracingIntegration, Replay }', gzip: true, limit: '110 KB', }, diff --git a/dev-packages/browser-integration-tests/loader-suites/loader/onLoad/customBrowserTracing/test.ts b/dev-packages/browser-integration-tests/loader-suites/loader/onLoad/customBrowserTracing/test.ts index 64b7fb800533..12cf305fab7d 100644 --- a/dev-packages/browser-integration-tests/loader-suites/loader/onLoad/customBrowserTracing/test.ts +++ b/dev-packages/browser-integration-tests/loader-suites/loader/onLoad/customBrowserTracing/test.ts @@ -7,7 +7,7 @@ import { waitForTransactionRequestOnUrl, } from '../../../../utils/helpers'; -sentryTest('should handle custom added BrowserTracing integration', async ({ getLocalTestUrl, page }) => { +sentryTest('should handle custom added browserTracingIntegration instances', async ({ getLocalTestUrl, page }) => { if (shouldSkipTracingTest()) { sentryTest.skip(); } diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/init.js deleted file mode 100644 index cd05f29615bb..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/init.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 1, - integrations: [new Sentry.Integrations.BrowserTracing()], -}); - -// This should not fail -Sentry.addTracingExtensions(); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/template.html b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/template.html deleted file mode 100644 index 2b3e2f0b27b4..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/template.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/test.ts deleted file mode 100644 index e37181ee815b..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegrationHashShim/test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../utils/fixtures'; -import { shouldSkipTracingTest } from '../../../utils/helpers'; - -sentryTest( - 'exports a shim Integrations.BrowserTracing integration for non-tracing bundles', - async ({ getLocalTestPath, page }) => { - // Skip in tracing tests - if (!shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const consoleMessages: string[] = []; - page.on('console', msg => consoleMessages.push(msg.text())); - - let requestCount = 0; - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - requestCount++; - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestPath({ testDir: __dirname }); - - await page.goto(url); - - expect(requestCount).toBe(0); - expect(consoleMessages).toEqual([ - 'You are using new BrowserTracing() even though this bundle does not include tracing.', - ]); - }, -); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/init.js deleted file mode 100644 index 95f654dd4428..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/init.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - sampleRate: 1, - integrations: [new Sentry.BrowserTracing()], -}); - -// This should not fail -Sentry.addTracingExtensions(); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/template.html b/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/template.html deleted file mode 100644 index 2b3e2f0b27b4..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/template.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/test.ts deleted file mode 100644 index 7b6027694734..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingShim/test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../utils/fixtures'; -import { shouldSkipTracingTest } from '../../../utils/helpers'; - -sentryTest('exports a shim BrowserTracing integration for non-tracing bundles', async ({ getLocalTestPath, page }) => { - // Skip in tracing tests - if (!shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const consoleMessages: string[] = []; - page.on('console', msg => consoleMessages.push(msg.text())); - - let requestCount = 0; - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - requestCount++; - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestPath({ testDir: __dirname }); - - await page.goto(url); - - expect(requestCount).toBe(0); - expect(consoleMessages).toEqual([ - 'You are using new BrowserTracing() even though this bundle does not include tracing.', - ]); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/init.js deleted file mode 100644 index 62685d4b6d18..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/init.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing({ idleTimeout: 9000, startTransactionOnPageLoad: false })], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/subject.js deleted file mode 100644 index e40426fdbe26..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/subject.js +++ /dev/null @@ -1,16 +0,0 @@ -document.getElementById('go-background').addEventListener('click', () => { - Object.defineProperty(document, 'hidden', { value: true, writable: true }); - const ev = document.createEvent('Event'); - ev.initEvent('visibilitychange'); - document.dispatchEvent(ev); -}); - -document.getElementById('start-span').addEventListener('click', () => { - const span = Sentry.startInactiveSpan({ name: 'test-span' }); - window.span = span; - Sentry.getCurrentScope().setSpan(span); -}); - -window.getSpanJson = () => { - return Sentry.spanToJSON(window.span); -}; diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/template.html b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/template.html deleted file mode 100644 index 772158d31f51..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/template.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/test.ts deleted file mode 100644 index fad37e85d6b4..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-custom/test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { expect } from '@playwright/test'; -import type { SpanJSON } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should finish a custom transaction when the page goes background', async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - page.goto(url); - - await page.locator('#start-span').click(); - const spanJsonBefore: SpanJSON = await page.evaluate('window.getSpanJson()'); - - const id_before = spanJsonBefore.span_id; - const description_before = spanJsonBefore.description; - const status_before = spanJsonBefore.status; - - expect(description_before).toBe('test-span'); - expect(status_before).toBeUndefined(); - - await page.locator('#go-background').click(); - const spanJsonAfter: SpanJSON = await page.evaluate('window.getSpanJson()'); - - const id_after = spanJsonAfter.span_id; - const description_after = spanJsonAfter.description; - const status_after = spanJsonAfter.status; - const data_after = spanJsonAfter.data; - - expect(id_before).toBe(id_after); - expect(description_after).toBe(description_before); - expect(status_after).toBe('cancelled'); - expect(data_after?.['sentry.cancellation_reason']).toBe('document.hidden'); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/subject.js deleted file mode 100644 index b657f38ac009..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/subject.js +++ /dev/null @@ -1,8 +0,0 @@ -document.getElementById('go-background').addEventListener('click', () => { - setTimeout(() => { - Object.defineProperty(document, 'hidden', { value: true, writable: true }); - const ev = document.createEvent('Event'); - ev.initEvent('visibilitychange'); - document.dispatchEvent(ev); - }, 250); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/template.html b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/template.html deleted file mode 100644 index 31cfc73ec3c3..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/template.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/test.ts deleted file mode 100644 index 1feda2e850e5..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/backgroundtab-pageload/test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { expect } from '@playwright/test'; -import type { Event } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should finish pageload transaction when the page goes background', async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - const url = await getLocalTestPath({ testDir: __dirname }); - - await page.goto(url); - await page.locator('#go-background').click(); - - const pageloadTransaction = await getFirstSentryEnvelopeRequest(page); - - expect(pageloadTransaction.contexts?.trace?.op).toBe('pageload'); - expect(pageloadTransaction.contexts?.trace?.status).toBe('cancelled'); - expect(pageloadTransaction.contexts?.trace?.data?.['sentry.cancellation_reason']).toBe('document.hidden'); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/init.js deleted file mode 100644 index ec8b0cb08034..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/init.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [ - new Sentry.BrowserTracing({ - idleTimeout: 1000, - _experiments: { - enableHTTPTimings: true, - }, - }), - ], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/subject.js deleted file mode 100644 index f62499b1e9c5..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/subject.js +++ /dev/null @@ -1 +0,0 @@ -fetch('http://example.com/0').then(fetch('http://example.com/1').then(fetch('http://example.com/2'))); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/test.ts deleted file mode 100644 index b6da7522d82c..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/http-timings/test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { expect } from '@playwright/test'; -import type { SerializedEvent } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getMultipleSentryEnvelopeRequests, shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should create fetch spans with http timing @firefox', async ({ browserName, getLocalTestPath, page }) => { - const supportedBrowsers = ['chromium', 'firefox']; - - if (shouldSkipTracingTest() || !supportedBrowsers.includes(browserName)) { - sentryTest.skip(); - } - await page.route('http://example.com/*', async route => { - const request = route.request(); - const postData = await request.postDataJSON(); - - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify(Object.assign({ id: 1 }, postData)), - }); - }); - - const url = await getLocalTestPath({ testDir: __dirname }); - - const envelopes = await getMultipleSentryEnvelopeRequests(page, 2, { url, timeout: 10000 }); - const tracingEvent = envelopes[envelopes.length - 1]; // last envelope contains tracing data on all browsers - - // eslint-disable-next-line deprecation/deprecation - const requestSpans = tracingEvent.spans?.filter(({ op }) => op === 'http.client'); - - expect(requestSpans).toHaveLength(3); - - await page.pause(); - requestSpans?.forEach((span, index) => - expect(span).toMatchObject({ - description: `GET http://example.com/${index}`, - parent_span_id: tracingEvent.contexts?.trace?.span_id, - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: tracingEvent.contexts?.trace?.trace_id, - data: expect.objectContaining({ - 'http.request.redirect_start': expect.any(Number), - 'http.request.fetch_start': expect.any(Number), - 'http.request.domain_lookup_start': expect.any(Number), - 'http.request.domain_lookup_end': expect.any(Number), - 'http.request.connect_start': expect.any(Number), - 'http.request.secure_connection_start': expect.any(Number), - 'http.request.connection_end': expect.any(Number), - 'http.request.request_start': expect.any(Number), - 'http.request.response_start': expect.any(Number), - 'http.request.response_end': expect.any(Number), - 'network.protocol.version': expect.any(String), - }), - }), - ); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/init.js deleted file mode 100644 index 14e743361fd7..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/init.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing()], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/assets/script.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/assets/script.js deleted file mode 100644 index a37a2c70ad27..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/assets/script.js +++ /dev/null @@ -1,17 +0,0 @@ -const delay = e => { - const startTime = Date.now(); - - function getElasped() { - const time = Date.now(); - return time - startTime; - } - - while (getElasped() < 70) { - // - } - - e.target.classList.add('clicked'); -}; - -document.querySelector('[data-test-id=interaction-button]').addEventListener('click', delay); -document.querySelector('[data-test-id=annotated-button]').addEventListener('click', delay); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/init.js deleted file mode 100644 index f8f8cf526a6b..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/init.js +++ /dev/null @@ -1,17 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [ - new Sentry.BrowserTracing({ - idleTimeout: 1000, - _experiments: { - enableInteractions: true, - enableLongTask: false, - }, - }), - ], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/template.html b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/template.html deleted file mode 100644 index 3357fb20a94e..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/template.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - -
Rendered Before Long Task
- - - - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/test.ts deleted file mode 100644 index fa9d2889bae3..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/interactions/test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { Route } from '@playwright/test'; -import { expect } from '@playwright/test'; -import type { SerializedEvent, Span, SpanContext, Transaction } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { - getFirstSentryEnvelopeRequest, - getMultipleSentryEnvelopeRequests, - shouldSkipTracingTest, -} from '../../../../utils/helpers'; - -type TransactionJSON = ReturnType & { - spans: ReturnType[]; - contexts: SpanContext; - platform: string; - type: string; -}; - -const wait = (time: number) => new Promise(res => setTimeout(res, time)); - -sentryTest('should capture interaction transaction. @firefox', async ({ browserName, getLocalTestPath, page }) => { - const supportedBrowsers = ['chromium', 'firefox']; - - if (shouldSkipTracingTest() || !supportedBrowsers.includes(browserName)) { - sentryTest.skip(); - } - - await page.route('**/path/to/script.js', (route: Route) => route.fulfill({ path: `${__dirname}/assets/script.js` })); - - const url = await getLocalTestPath({ testDir: __dirname }); - - await page.goto(url); - await getFirstSentryEnvelopeRequest(page); - - await page.locator('[data-test-id=interaction-button]').click(); - await page.locator('.clicked[data-test-id=interaction-button]').isVisible(); - - const envelopes = await getMultipleSentryEnvelopeRequests(page, 1); - expect(envelopes).toHaveLength(1); - - const eventData = envelopes[0]; - - expect(eventData.contexts).toMatchObject({ trace: { op: 'ui.action.click' } }); - expect(eventData.platform).toBe('javascript'); - expect(eventData.type).toBe('transaction'); - expect(eventData.spans).toHaveLength(1); - - const interactionSpan = eventData.spans![0]; - expect(interactionSpan.op).toBe('ui.interaction.click'); - expect(interactionSpan.description).toBe('body > button.clicked'); - expect(interactionSpan.timestamp).toBeDefined(); - - const interactionSpanDuration = (interactionSpan.timestamp! - interactionSpan.start_timestamp) * 1000; - expect(interactionSpanDuration).toBeGreaterThan(65); - expect(interactionSpanDuration).toBeLessThan(200); -}); - -sentryTest( - 'should create only one transaction per interaction @firefox', - async ({ browserName, getLocalTestPath, page }) => { - const supportedBrowsers = ['chromium', 'firefox']; - - if (shouldSkipTracingTest() || !supportedBrowsers.includes(browserName)) { - sentryTest.skip(); - } - - await page.route('**/path/to/script.js', (route: Route) => - route.fulfill({ path: `${__dirname}/assets/script.js` }), - ); - - const url = await getLocalTestPath({ testDir: __dirname }); - await page.goto(url); - await getFirstSentryEnvelopeRequest(page); - - for (let i = 0; i < 4; i++) { - await wait(100); - await page.locator('[data-test-id=interaction-button]').click(); - const envelope = await getMultipleSentryEnvelopeRequests(page, 1); - expect(envelope[0].spans).toHaveLength(1); - } - }, -); - -sentryTest( - 'should use the component name for a clicked element when it is available', - async ({ browserName, getLocalTestPath, page }) => { - const supportedBrowsers = ['chromium', 'firefox']; - - if (shouldSkipTracingTest() || !supportedBrowsers.includes(browserName)) { - sentryTest.skip(); - } - - await page.route('**/path/to/script.js', (route: Route) => - route.fulfill({ path: `${__dirname}/assets/script.js` }), - ); - - const url = await getLocalTestPath({ testDir: __dirname }); - - await page.goto(url); - await getFirstSentryEnvelopeRequest(page); - - await page.locator('[data-test-id=annotated-button]').click(); - - const envelopes = await getMultipleSentryEnvelopeRequests(page, 1); - expect(envelopes).toHaveLength(1); - const eventData = envelopes[0]; - - expect(eventData.spans).toHaveLength(1); - - const interactionSpan = eventData.spans![0]; - expect(interactionSpan.op).toBe('ui.interaction.click'); - expect(interactionSpan.description).toBe('body > AnnotatedButton'); - }, -); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/assets/script.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/assets/script.js deleted file mode 100644 index 9ac3d6fb33d2..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/assets/script.js +++ /dev/null @@ -1,12 +0,0 @@ -(() => { - const startTime = Date.now(); - - function getElasped() { - const time = Date.now(); - return time - startTime; - } - - while (getElasped() < 101) { - // - } -})(); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/init.js deleted file mode 100644 index 8dba00211a01..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/init.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing({ enableLongTask: false, idleTimeout: 9000 })], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/template.html b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/template.html deleted file mode 100644 index 5c3a14114991..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/template.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - -
Rendered Before Long Task
- - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/test.ts deleted file mode 100644 index d460d2883afd..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-disabled/test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Route } from '@playwright/test'; -import { expect } from '@playwright/test'; -import type { SerializedEvent } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should not capture long task when flag is disabled.', async ({ browserName, getLocalTestPath, page }) => { - // Long tasks only work on chrome - if (shouldSkipTracingTest() || browserName !== 'chromium') { - sentryTest.skip(); - } - - await page.route('**/path/to/script.js', (route: Route) => route.fulfill({ path: `${__dirname}/assets/script.js` })); - - const url = await getLocalTestPath({ testDir: __dirname }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - const uiSpans = eventData.spans?.filter(({ op }) => op?.startsWith('ui')); - - expect(uiSpans?.length).toBe(0); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/assets/script.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/assets/script.js deleted file mode 100644 index 5a2aef02028d..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/assets/script.js +++ /dev/null @@ -1,12 +0,0 @@ -(() => { - const startTime = Date.now(); - - function getElasped() { - const time = Date.now(); - return time - startTime; - } - - while (getElasped() < 105) { - // - } -})(); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/init.js deleted file mode 100644 index 155966847b1c..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/init.js +++ /dev/null @@ -1,13 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [ - new Sentry.BrowserTracing({ - idleTimeout: 9000, - }), - ], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/template.html b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/template.html deleted file mode 100644 index 5c3a14114991..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/template.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - -
Rendered Before Long Task
- - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/test.ts deleted file mode 100644 index 1ed0bcda2a89..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/long-tasks-enabled/test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { Route } from '@playwright/test'; -import { expect } from '@playwright/test'; -import type { SerializedEvent } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should capture long task.', async ({ browserName, getLocalTestPath, page }) => { - // Long tasks only work on chrome - if (shouldSkipTracingTest() || browserName !== 'chromium') { - sentryTest.skip(); - } - - await page.route('**/path/to/script.js', (route: Route) => route.fulfill({ path: `${__dirname}/assets/script.js` })); - - const url = await getLocalTestPath({ testDir: __dirname }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - const uiSpans = eventData.spans?.filter(({ op }) => op?.startsWith('ui')); - - expect(uiSpans?.length).toBeGreaterThan(0); - - const [firstUISpan] = uiSpans || []; - expect(firstUISpan).toEqual( - expect.objectContaining({ - op: 'ui.long-task', - description: 'Main UI thread blocked', - parent_span_id: eventData.contexts?.trace?.span_id, - }), - ); - const start = firstUISpan.start_timestamp ?? 0; - const end = firstUISpan.timestamp ?? 0; - const duration = end - start; - - expect(duration).toBeGreaterThanOrEqual(0.1); - expect(duration).toBeLessThanOrEqual(0.15); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/init.js deleted file mode 100644 index e6f49fa89562..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/init.js +++ /dev/null @@ -1,10 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing()], - tracesSampleRate: 1, - environment: 'staging', -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/template.html b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/template.html deleted file mode 100644 index 09984cb0c488..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/template.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/test.ts deleted file mode 100644 index ae89fd383cbb..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/meta/test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { expect } from '@playwright/test'; -import type { Event, EventEnvelopeHeaders } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { - envelopeHeaderRequestParser, - getFirstSentryEnvelopeRequest, - shouldSkipTracingTest, -} from '../../../../utils/helpers'; - -sentryTest( - 'should create a pageload transaction based on `sentry-trace` ', - async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - - expect(eventData.contexts?.trace).toMatchObject({ - op: 'pageload', - parent_span_id: '1121201211212012', - trace_id: '12312012123120121231201212312012', - }); - - expect(eventData.spans?.length).toBeGreaterThan(0); - }, -); - -sentryTest( - 'should pick up `baggage` tag, propagate the content in transaction and not add own data', - async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const envHeader = await getFirstSentryEnvelopeRequest(page, url, envelopeHeaderRequestParser); - - expect(envHeader.trace).toBeDefined(); - expect(envHeader.trace).toEqual({ - release: '2.1.12', - sample_rate: '0.3232', - trace_id: '123', - public_key: 'public', - }); - }, -); - -sentryTest( - "should create a navigation that's not influenced by `sentry-trace` ", - async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const pageloadRequest = await getFirstSentryEnvelopeRequest(page, url); - const navigationRequest = await getFirstSentryEnvelopeRequest(page, `${url}#foo`); - - expect(pageloadRequest.contexts?.trace).toMatchObject({ - op: 'pageload', - parent_span_id: '1121201211212012', - trace_id: '12312012123120121231201212312012', - }); - - expect(navigationRequest.contexts?.trace?.op).toBe('navigation'); - expect(navigationRequest.contexts?.trace?.trace_id).toBeDefined(); - expect(navigationRequest.contexts?.trace?.trace_id).not.toBe(pageloadRequest.contexts?.trace?.trace_id); - - const pageloadSpans = pageloadRequest.spans; - const navigationSpans = navigationRequest.spans; - - const pageloadSpanId = pageloadRequest.contexts?.trace?.span_id; - const navigationSpanId = navigationRequest.contexts?.trace?.span_id; - - expect(pageloadSpanId).toBeDefined(); - expect(navigationSpanId).toBeDefined(); - - pageloadSpans?.forEach(span => - expect(span).toMatchObject({ - parent_span_id: pageloadSpanId, - }), - ); - - navigationSpans?.forEach(span => - expect(span).toMatchObject({ - parent_span_id: navigationSpanId, - }), - ); - }, -); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/navigation/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/navigation/test.ts deleted file mode 100644 index 5a46a65a4392..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/navigation/test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { expect } from '@playwright/test'; -import type { Event } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should create a navigation transaction on page navigation', async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const pageloadRequest = await getFirstSentryEnvelopeRequest(page, url); - const navigationRequest = await getFirstSentryEnvelopeRequest(page, `${url}#foo`); - - expect(pageloadRequest.contexts?.trace?.op).toBe('pageload'); - expect(navigationRequest.contexts?.trace?.op).toBe('navigation'); - - expect(navigationRequest.transaction_info?.source).toEqual('url'); - - const pageloadTraceId = pageloadRequest.contexts?.trace?.trace_id; - const navigationTraceId = navigationRequest.contexts?.trace?.trace_id; - - expect(pageloadTraceId).toBeDefined(); - expect(navigationTraceId).toBeDefined(); - expect(pageloadTraceId).not.toEqual(navigationTraceId); - - const pageloadSpans = pageloadRequest.spans; - const navigationSpans = navigationRequest.spans; - - const pageloadSpanId = pageloadRequest.contexts?.trace?.span_id; - const navigationSpanId = navigationRequest.contexts?.trace?.span_id; - - expect(pageloadSpanId).toBeDefined(); - expect(navigationSpanId).toBeDefined(); - - pageloadSpans?.forEach(span => - expect(span).toMatchObject({ - parent_span_id: pageloadSpanId, - }), - ); - - navigationSpans?.forEach(span => - expect(span).toMatchObject({ - parent_span_id: navigationSpanId, - }), - ); - - expect(pageloadSpanId).not.toEqual(navigationSpanId); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageload/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageload/init.js deleted file mode 100644 index a1e77dae58c2..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageload/init.js +++ /dev/null @@ -1,10 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window._testBaseTimestamp = performance.timeOrigin / 1000; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing()], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageload/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageload/test.ts deleted file mode 100644 index 6a186b63b02a..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageload/test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect } from '@playwright/test'; -import type { Event } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should create a pageload transaction', async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - const timeOrigin = await page.evaluate('window._testBaseTimestamp'); - - const { start_timestamp: startTimestamp } = eventData; - - expect(startTimestamp).toBeCloseTo(timeOrigin, 1); - - expect(eventData.contexts?.trace?.op).toBe('pageload'); - expect(eventData.spans?.length).toBeGreaterThan(0); - expect(eventData.transaction_info?.source).toEqual('url'); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadDelayed/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadDelayed/init.js deleted file mode 100644 index 6e4774650261..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadDelayed/init.js +++ /dev/null @@ -1,13 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; -window._testBaseTimestamp = performance.timeOrigin / 1000; - -setTimeout(() => { - window._testTimeoutTimestamp = (performance.timeOrigin + performance.now()) / 1000; - Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing()], - tracesSampleRate: 1, - }); -}, 250); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadDelayed/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadDelayed/test.ts deleted file mode 100644 index 882c08d23c5e..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadDelayed/test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect } from '@playwright/test'; -import type { Event } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; - -sentryTest('should create a pageload transaction when initialized delayed', async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - const timeOrigin = await page.evaluate('window._testBaseTimestamp'); - const timeoutTimestamp = await page.evaluate('window._testTimeoutTimestamp'); - - const { start_timestamp: startTimestamp } = eventData; - - expect(startTimestamp).toBeCloseTo(timeOrigin, 1); - expect(startTimestamp).toBeLessThan(timeoutTimestamp); - - expect(eventData.contexts?.trace?.op).toBe('pageload'); - expect(eventData.spans?.length).toBeGreaterThan(0); - expect(eventData.transaction_info?.source).toEqual('url'); -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadWithHeartbeatTimeout/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadWithHeartbeatTimeout/init.js deleted file mode 100644 index 2a4797a74a15..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadWithHeartbeatTimeout/init.js +++ /dev/null @@ -1,14 +0,0 @@ -import * as Sentry from '@sentry/browser'; -import { startSpanManual } from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing()], - tracesSampleRate: 1, -}); - -setTimeout(() => { - startSpanManual({ name: 'pageload-child-span' }, () => {}); -}, 200); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadWithHeartbeatTimeout/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadWithHeartbeatTimeout/test.ts deleted file mode 100644 index ead37d6f8662..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/pageloadWithHeartbeatTimeout/test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect } from '@playwright/test'; -import type { SerializedEvent } from '@sentry/types'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; - -// This tests asserts that the pageload transaction will finish itself after about 15 seconds (3x5s of heartbeats) if it -// has a child span without adding any additional ones or finishing any of them finishing. All of the child spans that -// are still running should have the status "cancelled". -sentryTest( - 'should send a pageload transaction terminated via heartbeat timeout', - async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - - expect(eventData.contexts?.trace?.op).toBe('pageload'); - expect( - eventData.spans?.find(span => span.description === 'pageload-child-span' && span.status === 'cancelled'), - ).toBeDefined(); - }, -); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/init.js deleted file mode 100644 index 7cd076a052e5..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/init.js +++ /dev/null @@ -1,10 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -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/browsertracing/tracePropagationTargets/customTargets/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/subject.js deleted file mode 100644 index f62499b1e9c5..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/subject.js +++ /dev/null @@ -1 +0,0 @@ -fetch('http://example.com/0').then(fetch('http://example.com/1').then(fetch('http://example.com/2'))); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/test.ts deleted file mode 100644 index fb6e9e540c46..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/customTargets/test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../../utils/fixtures'; -import { shouldSkipTracingTest } from '../../../../../utils/helpers'; - -sentryTest( - 'should attach `sentry-trace` and `baggage` header to request matching tracePropagationTargets', - async ({ getLocalTestPath, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestPath({ testDir: __dirname }); - - const requests = ( - await Promise.all([ - page.goto(url), - Promise.all([0, 1, 2].map(idx => page.waitForRequest(`http://example.com/${idx}`))), - ]) - )[1]; - - expect(requests).toHaveLength(3); - - for (const request of requests) { - const requestHeaders = request.headers(); - - expect(requestHeaders).toMatchObject({ - 'sentry-trace': expect.any(String), - baggage: expect.any(String), - }); - } - }, -); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/init.js deleted file mode 100644 index 83076460599f..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/init.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [Sentry.browserTracingIntegration()], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/subject.js deleted file mode 100644 index 7e662b55c333..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/subject.js +++ /dev/null @@ -1 +0,0 @@ -fetch('/0').then(fetch('/1').then(fetch('/2'))); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/test.ts deleted file mode 100644 index f9f9af3ddb47..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsMatch/test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../../utils/fixtures'; -import { shouldSkipTracingTest } from '../../../../../utils/helpers'; - -sentryTest( - 'should attach `sentry-trace` and `baggage` header to same-origin requests when no tracePropagationTargets are defined', - async ({ getLocalTestUrl, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestUrl({ testDir: __dirname }); - - const requests = ( - await Promise.all([page.goto(url), Promise.all([0, 1, 2].map(idx => page.waitForRequest(`**/${idx}`)))]) - )[1]; - - expect(requests).toHaveLength(3); - - for (const request of requests) { - const requestHeaders = request.headers(); - expect(requestHeaders).toMatchObject({ - 'sentry-trace': expect.any(String), - baggage: expect.any(String), - }); - } - }, -); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/init.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/init.js deleted file mode 100644 index 83076460599f..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/init.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [Sentry.browserTracingIntegration()], - tracesSampleRate: 1, -}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/subject.js deleted file mode 100644 index f62499b1e9c5..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/subject.js +++ /dev/null @@ -1 +0,0 @@ -fetch('http://example.com/0').then(fetch('http://example.com/1').then(fetch('http://example.com/2'))); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/test.ts deleted file mode 100644 index 6739b7ce3621..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browsertracing/tracePropagationTargets/defaultTargetsNoMatch/test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../../utils/fixtures'; -import { shouldSkipTracingTest } from '../../../../../utils/helpers'; - -sentryTest( - 'should not attach `sentry-trace` and `baggage` header to cross-origin requests when no tracePropagationTargets are defined', - async ({ getLocalTestUrl, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestUrl({ testDir: __dirname }); - - const requests = ( - await Promise.all([page.goto(url), Promise.all([0, 1, 2].map(idx => page.waitForRequest(`**/${idx}`)))]) - )[1]; - - expect(requests).toHaveLength(3); - - for (const request of requests) { - const requestHeaders = request.headers(); - expect(requestHeaders).not.toMatchObject({ - 'sentry-trace': expect.any(String), - baggage: expect.any(String), - }); - } - }, -); diff --git a/dev-packages/browser-integration-tests/suites/tracing/envelope-header-transaction-name/init.js b/dev-packages/browser-integration-tests/suites/tracing/envelope-header-transaction-name/init.js index 647e6af5e963..8ac3d814b2bd 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/envelope-header-transaction-name/init.js +++ b/dev-packages/browser-integration-tests/suites/tracing/envelope-header-transaction-name/init.js @@ -5,16 +5,17 @@ window.Sentry = Sentry; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [new Sentry.BrowserTracing({ tracingOrigins: [/.*/] })], + integrations: [Sentry.browserTracingIntegration()], environment: 'production', tracesSampleRate: 1, debug: true, }); -const scope = Sentry.getCurrentScope(); -scope.setUser({ id: 'user123' }); -scope.addEventProcessor(event => { +Sentry.setUser({ id: 'user123' }); + +Sentry.addEventProcessor(event => { event.transaction = 'testTransactionDSC'; return event; }); -scope.getTransaction().setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'custom'); + +Sentry.getActiveSpan().setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'custom'); diff --git a/dev-packages/browser-integration-tests/suites/tracing/envelope-header/test.ts b/dev-packages/browser-integration-tests/suites/tracing/envelope-header/test.ts index 0d7e2b793553..6df352af5fc0 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/envelope-header/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/envelope-header/test.ts @@ -21,7 +21,7 @@ sentryTest( // In this test, we don't expect trace.transaction to be present because without a custom routing instrumentation // we for now don't have parameterization. This might change in the future but for now the only way of having - // transaction in DSC with the default BrowserTracing integration is when the transaction name is set manually. + // transaction in DSC with the default browserTracingIntegration is when the transaction name is set manually. // This scenario is covered in another integration test (envelope-header-transaction-name). expect(envHeader.trace).toBeDefined(); expect(envHeader.trace).toEqual({ diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/init.js b/dev-packages/browser-integration-tests/suites/tracing/metrics/init.js index 155966847b1c..ad1d8832b228 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/init.js +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/init.js @@ -5,7 +5,7 @@ window.Sentry = Sentry; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', integrations: [ - new Sentry.BrowserTracing({ + Sentry.browserTracingIntegration({ idleTimeout: 9000, }), ], diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/app/entry.client.tsx b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/app/entry.client.tsx index a56d13dddadc..1f1a48d28fbd 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/app/entry.client.tsx +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/app/entry.client.tsx @@ -13,8 +13,10 @@ Sentry.init({ environment: 'qa', // dynamic sampling bias to keep transactions dsn: window.ENV.SENTRY_DSN, integrations: [ - new Sentry.BrowserTracing({ - routingInstrumentation: Sentry.remixRouterInstrumentation(useEffect, useLocation, useMatches), + Sentry.browserTracingIntegration({ + useEffect, + useLocation, + useMatches, }), new Sentry.Replay(), ], diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app/app/entry.client.tsx b/dev-packages/e2e-tests/test-applications/create-remix-app/app/entry.client.tsx index a56d13dddadc..d5a8978376a4 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app/app/entry.client.tsx +++ b/dev-packages/e2e-tests/test-applications/create-remix-app/app/entry.client.tsx @@ -12,12 +12,7 @@ import { hydrateRoot } from 'react-dom/client'; Sentry.init({ environment: 'qa', // dynamic sampling bias to keep transactions dsn: window.ENV.SENTRY_DSN, - integrations: [ - new Sentry.BrowserTracing({ - routingInstrumentation: Sentry.remixRouterInstrumentation(useEffect, useLocation, useMatches), - }), - new Sentry.Replay(), - ], + integrations: [Sentry.browserTracingIntegration({ useEffect, useMatches, useLocation }), new Sentry.Replay()], // Performance Monitoring tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! // Session Replay diff --git a/dev-packages/overhead-metrics/test-apps/booking-app/with-replay.html b/dev-packages/overhead-metrics/test-apps/booking-app/with-replay.html index 7f471cc12c94..21f19f6260be 100644 --- a/dev-packages/overhead-metrics/test-apps/booking-app/with-replay.html +++ b/dev-packages/overhead-metrics/test-apps/booking-app/with-replay.html @@ -223,7 +223,7 @@

This is a test app.

replaysOnErrorSampleRate: 1.0, enableTracing: true, integrations: [ - new Sentry.Integrations.BrowserTracing(), + Sentry.browserTracingIntegration(), new Sentry.Integrations.Replay({ useCompression: true, flushMinDelay: 2000, diff --git a/dev-packages/overhead-metrics/test-apps/booking-app/with-sentry.html b/dev-packages/overhead-metrics/test-apps/booking-app/with-sentry.html index cd122c172ad2..94c581f184ab 100644 --- a/dev-packages/overhead-metrics/test-apps/booking-app/with-sentry.html +++ b/dev-packages/overhead-metrics/test-apps/booking-app/with-sentry.html @@ -220,7 +220,7 @@

This is a test app.

Sentry.init({ dsn: 'https://d16ae2d36f9249849c7964e9a3a8a608@o447951.ingest.sentry.io/5429213', enableTracing: true, - integrations: [new Sentry.Integrations.BrowserTracing()], + integrations: [Sentry.browserTracingIntegration()], }); diff --git a/packages/angular/src/tracing.ts b/packages/angular/src/tracing.ts index e07ee34f6516..4ac977c66f48 100644 --- a/packages/angular/src/tracing.ts +++ b/packages/angular/src/tracing.ts @@ -67,7 +67,7 @@ export function routingInstrumentation( export const instrumentAngularRouting = routingInstrumentation; /** - * A custom BrowserTracing integration for Angular. + * A custom browser tracing integration for Angular. * * Use this integration in combination with `TraceService` */ diff --git a/packages/astro/test/client/sdk.test.ts b/packages/astro/test/client/sdk.test.ts index 311287bfc533..50f4e3c9e354 100644 --- a/packages/astro/test/client/sdk.test.ts +++ b/packages/astro/test/client/sdk.test.ts @@ -56,7 +56,7 @@ describe('Sentry client SDK', () => { ['tracesSampleRate', { tracesSampleRate: 0 }], ['tracesSampler', { tracesSampler: () => 1.0 }], ['enableTracing', { enableTracing: true }], - ])('adds the BrowserTracing integration if tracing is enabled via %s', (_, tracingOptions) => { + ])('adds browserTracingIntegration if tracing is enabled via %s', (_, tracingOptions) => { init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', ...tracingOptions, @@ -72,7 +72,7 @@ describe('Sentry client SDK', () => { it.each([ ['enableTracing', { enableTracing: false }], ['no tracing option set', {}], - ])("doesn't add the BrowserTracing integration if tracing is disabled via %s", (_, tracingOptions) => { + ])("doesn't add browserTracingIntegration if tracing is disabled via %s", (_, tracingOptions) => { init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', ...tracingOptions, @@ -85,7 +85,7 @@ describe('Sentry client SDK', () => { expect(browserTracing).toBeUndefined(); }); - it("doesn't add the BrowserTracing integration if `__SENTRY_TRACING__` is set to false", () => { + it("doesn't add browserTracingIntegration if `__SENTRY_TRACING__` is set to false", () => { globalThis.__SENTRY_TRACING__ = false; init({ @@ -102,7 +102,7 @@ describe('Sentry client SDK', () => { delete globalThis.__SENTRY_TRACING__; }); - it('Overrides the automatically default BrowserTracing instance with a a user-provided browserTracingIntegration instance', () => { + it('Overrides the automatically default browserTracingIntegration instance with a a user-provided browserTracingIntegration instance', () => { init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', integrations: [ diff --git a/packages/astro/test/integration/snippets.test.ts b/packages/astro/test/integration/snippets.test.ts index ddd7188d9b18..b89522c78c89 100644 --- a/packages/astro/test/integration/snippets.test.ts +++ b/packages/astro/test/integration/snippets.test.ts @@ -50,7 +50,7 @@ describe('buildClientSnippet', () => { `); }); - it('does not include BrowserTracing if tracesSampleRate is 0', () => { + it('does not include browserTracingIntegration if tracesSampleRate is 0', () => { const snippet = buildClientSnippet({ tracesSampleRate: 0 }); expect(snippet).toMatchInlineSnapshot(` "import * as Sentry from \\"@sentry/astro\\"; diff --git a/packages/browser/src/helpers.ts b/packages/browser/src/helpers.ts index 6b9df98f1751..a232d24044dc 100644 --- a/packages/browser/src/helpers.ts +++ b/packages/browser/src/helpers.ts @@ -1,7 +1,5 @@ -import type { browserTracingIntegration } from '@sentry-internal/tracing'; -import { BrowserTracing } from '@sentry-internal/tracing'; import { captureException, withScope } from '@sentry/core'; -import type { Integration, Mechanism, WrappedFunction } from '@sentry/types'; +import type { Mechanism, WrappedFunction } from '@sentry/types'; import { GLOBAL_OBJ, addExceptionMechanism, @@ -155,35 +153,3 @@ export function wrap( return sentryWrapped; } - -/** - * This is a slim shim of `browserTracingIntegration` for the CDN bundles. - * Since the actual functional integration uses a different code from `BrowserTracing`, - * we want to avoid shipping both of them in the CDN bundles, as that would blow up the size. - * Instead, we provide a functional integration with the same API, but the old implementation. - * This means that it's not possible to register custom routing instrumentation, but that's OK for now. - * We also don't expose the utilities for this anyhow in the CDN bundles. - * For users that need custom routing in CDN bundles, they have to continue using `new BrowserTracing()` until v8. - */ -export function bundleBrowserTracingIntegration( - options: Parameters[0] = {}, -): Integration { - // Migrate some options from the old integration to the new one - // eslint-disable-next-line deprecation/deprecation - const opts: ConstructorParameters[0] = options; - - if (typeof options.markBackgroundSpan === 'boolean') { - opts.markBackgroundTransactions = options.markBackgroundSpan; - } - - if (typeof options.instrumentPageLoad === 'boolean') { - opts.startTransactionOnPageLoad = options.instrumentPageLoad; - } - - if (typeof options.instrumentNavigation === 'boolean') { - opts.startTransactionOnLocationChange = options.instrumentNavigation; - } - - // eslint-disable-next-line deprecation/deprecation - return new BrowserTracing(opts); -} diff --git a/packages/browser/src/index.bundle.feedback.ts b/packages/browser/src/index.bundle.feedback.ts index 8e653c2d4757..7cb0501e1a92 100644 --- a/packages/browser/src/index.bundle.feedback.ts +++ b/packages/browser/src/index.bundle.feedback.ts @@ -1,31 +1,25 @@ // This is exported so the loader does not fail when switching off Replay/Tracing import { Feedback, feedbackIntegration } from '@sentry-internal/feedback'; import { - BrowserTracing, - Replay, - addTracingExtensions, - browserTracingIntegration, - replayIntegration, + ReplayShim, + addTracingExtensionsShim, + browserTracingIntegrationShim, + replayIntegrationShim, } from '@sentry-internal/integration-shims'; import * as Sentry from './index.bundle.base'; // TODO (v8): Remove this as it was only needed for backwards compatibility // eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.Replay = Replay; - -// eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.BrowserTracing = BrowserTracing; +Sentry.Integrations.Replay = ReplayShim; export * from './index.bundle.base'; export { + browserTracingIntegrationShim as browserTracingIntegration, + addTracingExtensionsShim as addTracingExtensions, // eslint-disable-next-line deprecation/deprecation - BrowserTracing, - browserTracingIntegration, - addTracingExtensions, - // eslint-disable-next-line deprecation/deprecation - Replay, - replayIntegration, + ReplayShim as Replay, + replayIntegrationShim as replayIntegration, // eslint-disable-next-line deprecation/deprecation Feedback, feedbackIntegration, diff --git a/packages/browser/src/index.bundle.replay.ts b/packages/browser/src/index.bundle.replay.ts index 2e4619ab49ea..71baed234eba 100644 --- a/packages/browser/src/index.bundle.replay.ts +++ b/packages/browser/src/index.bundle.replay.ts @@ -1,10 +1,9 @@ // This is exported so the loader does not fail when switching off Replay/Tracing import { - BrowserTracing, - Feedback, - addTracingExtensions, - browserTracingIntegration, - feedbackIntegration, + FeedbackShim, + addTracingExtensionsShim, + browserTracingIntegrationShim, + feedbackIntegrationShim, } from '@sentry-internal/integration-shims'; import { Replay, replayIntegration } from '@sentry/replay'; @@ -14,20 +13,15 @@ import * as Sentry from './index.bundle.base'; // eslint-disable-next-line deprecation/deprecation Sentry.Integrations.Replay = Replay; -// eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.BrowserTracing = BrowserTracing; - export * from './index.bundle.base'; export { - // eslint-disable-next-line deprecation/deprecation - BrowserTracing, - browserTracingIntegration, - addTracingExtensions, + browserTracingIntegrationShim as browserTracingIntegration, + addTracingExtensionsShim as addTracingExtensions, // eslint-disable-next-line deprecation/deprecation Replay, replayIntegration, // eslint-disable-next-line deprecation/deprecation - Feedback, - feedbackIntegration, + FeedbackShim as Feedback, + feedbackIntegrationShim as feedbackIntegration, }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.ts index b103b6f4583d..0e75d5319ee2 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.ts @@ -1,8 +1,7 @@ import { Feedback, feedbackIntegration } from '@sentry-internal/feedback'; -import { BrowserTracing } from '@sentry-internal/tracing'; +import { browserTracingIntegration } from '@sentry-internal/tracing'; import { addTracingExtensions } from '@sentry/core'; import { Replay, replayIntegration } from '@sentry/replay'; -import { bundleBrowserTracingIntegration as browserTracingIntegration } from './helpers'; import * as Sentry from './index.bundle.base'; @@ -12,9 +11,6 @@ import * as Sentry from './index.bundle.base'; // eslint-disable-next-line deprecation/deprecation Sentry.Integrations.Replay = Replay; -// eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.BrowserTracing = BrowserTracing; - // We are patching the global object with our hub extension methods addTracingExtensions(); @@ -25,8 +21,6 @@ export { Replay, feedbackIntegration, replayIntegration, - // eslint-disable-next-line deprecation/deprecation - BrowserTracing, browserTracingIntegration, addTracingExtensions, }; diff --git a/packages/browser/src/index.bundle.tracing.replay.ts b/packages/browser/src/index.bundle.tracing.replay.ts index e817390aa39d..5b5fdef07bf6 100644 --- a/packages/browser/src/index.bundle.tracing.replay.ts +++ b/packages/browser/src/index.bundle.tracing.replay.ts @@ -1,8 +1,7 @@ -import { Feedback, feedbackIntegration } from '@sentry-internal/integration-shims'; -import { BrowserTracing } from '@sentry-internal/tracing'; +import { FeedbackShim, feedbackIntegrationShim } from '@sentry-internal/integration-shims'; +import { browserTracingIntegration } from '@sentry-internal/tracing'; import { addTracingExtensions } from '@sentry/core'; import { Replay, replayIntegration } from '@sentry/replay'; -import { bundleBrowserTracingIntegration as browserTracingIntegration } from './helpers'; import * as Sentry from './index.bundle.base'; @@ -12,21 +11,16 @@ import * as Sentry from './index.bundle.base'; // eslint-disable-next-line deprecation/deprecation Sentry.Integrations.Replay = Replay; -// eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.BrowserTracing = BrowserTracing; - // We are patching the global object with our hub extension methods addTracingExtensions(); export { // eslint-disable-next-line deprecation/deprecation - Feedback, + FeedbackShim as Feedback, // eslint-disable-next-line deprecation/deprecation Replay, replayIntegration, - feedbackIntegration, - // eslint-disable-next-line deprecation/deprecation - BrowserTracing, + feedbackIntegrationShim as feedbackIntegration, browserTracingIntegration, addTracingExtensions, }; diff --git a/packages/browser/src/index.bundle.tracing.ts b/packages/browser/src/index.bundle.tracing.ts index 704a646dcdb8..e3e75924c10f 100644 --- a/packages/browser/src/index.bundle.tracing.ts +++ b/packages/browser/src/index.bundle.tracing.ts @@ -1,32 +1,31 @@ // This is exported so the loader does not fail when switching off Replay -import { Feedback, Replay, feedbackIntegration, replayIntegration } from '@sentry-internal/integration-shims'; -import { BrowserTracing } from '@sentry-internal/tracing'; +import { + FeedbackShim, + ReplayShim, + feedbackIntegrationShim, + replayIntegrationShim, +} from '@sentry-internal/integration-shims'; +import { browserTracingIntegration } from '@sentry-internal/tracing'; import { addTracingExtensions } from '@sentry/core'; -import { bundleBrowserTracingIntegration as browserTracingIntegration } from './helpers'; import * as Sentry from './index.bundle.base'; -// TODO (v8): Remove this as it was only needed for backwards compatibility +// TODO(v8): Remove this as it was only needed for backwards compatibility // We want replay to be available under Sentry.Replay, to be consistent // with the NPM package version. // eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.Replay = Replay; - -// eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.BrowserTracing = BrowserTracing; +Sentry.Integrations.Replay = ReplayShim; // We are patching the global object with our hub extension methods addTracingExtensions(); export { // eslint-disable-next-line deprecation/deprecation - Feedback, - // eslint-disable-next-line deprecation/deprecation - Replay, - feedbackIntegration, - replayIntegration, + FeedbackShim as Feedback, // eslint-disable-next-line deprecation/deprecation - BrowserTracing, + ReplayShim as Replay, + feedbackIntegrationShim as feedbackIntegration, + replayIntegrationShim as replayIntegration, browserTracingIntegration, addTracingExtensions, }; diff --git a/packages/browser/src/index.bundle.ts b/packages/browser/src/index.bundle.ts index 3087d7d317ca..b113bd56d142 100644 --- a/packages/browser/src/index.bundle.ts +++ b/packages/browser/src/index.bundle.ts @@ -1,34 +1,28 @@ // This is exported so the loader does not fail when switching off Replay/Tracing import { - BrowserTracing, - Feedback, - Replay, - addTracingExtensions, - browserTracingIntegration, - feedbackIntegration, - replayIntegration, + FeedbackShim, + ReplayShim, + addTracingExtensionsShim, + browserTracingIntegrationShim, + feedbackIntegrationShim, + replayIntegrationShim, } from '@sentry-internal/integration-shims'; import * as Sentry from './index.bundle.base'; // TODO (v8): Remove this as it was only needed for backwards compatibility // eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.Replay = Replay; - -// eslint-disable-next-line deprecation/deprecation -Sentry.Integrations.BrowserTracing = BrowserTracing; +Sentry.Integrations.Replay = ReplayShim; export * from './index.bundle.base'; export { + addTracingExtensionsShim as addTracingExtensions, // eslint-disable-next-line deprecation/deprecation - BrowserTracing, - addTracingExtensions, - // eslint-disable-next-line deprecation/deprecation - Replay, + ReplayShim as Replay, // eslint-disable-next-line deprecation/deprecation - Feedback, - browserTracingIntegration, - feedbackIntegration, - replayIntegration, + FeedbackShim as Feedback, + browserTracingIntegrationShim as browserTracingIntegration, + feedbackIntegrationShim as feedbackIntegration, + replayIntegrationShim as replayIntegration, }; // Note: We do not export a shim for `Span` here, as that is quite complex and would blow up the bundle diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 9957e290acf5..a7e8bc2d8b0c 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -55,8 +55,6 @@ export { } from '@sentry-internal/feedback'; export { - // eslint-disable-next-line deprecation/deprecation - BrowserTracing, defaultRequestInstrumentationOptions, instrumentOutgoingRequests, browserTracingIntegration, diff --git a/packages/browser/test/unit/index.bundle.feedback.test.ts b/packages/browser/test/unit/index.bundle.feedback.test.ts index 5fe2940d1881..91475a34bb02 100644 --- a/packages/browser/test/unit/index.bundle.feedback.test.ts +++ b/packages/browser/test/unit/index.bundle.feedback.test.ts @@ -1,9 +1,5 @@ /* eslint-disable deprecation/deprecation */ -import { - BrowserTracing as BrowserTracingShim, - Replay as ReplayShim, - replayIntegration as replayIntegrationShim, -} from '@sentry-internal/integration-shims'; +import { ReplayShim, replayIntegrationShim } from '@sentry-internal/integration-shims'; import { Feedback, feedbackIntegration } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.feedback'; @@ -11,11 +7,6 @@ import * as TracingReplayBundle from '../../src/index.bundle.feedback'; describe('index.bundle.feedback', () => { it('has correct exports', () => { Object.keys(TracingReplayBundle.Integrations).forEach(key => { - // Skip BrowserTracing because it doesn't have a static id field. - if (key === 'BrowserTracing') { - return; - } - expect((TracingReplayBundle.Integrations[key] as any).id).toStrictEqual(expect.any(String)); }); @@ -23,9 +14,6 @@ describe('index.bundle.feedback', () => { expect(TracingReplayBundle.Replay).toBe(ReplayShim); expect(TracingReplayBundle.replayIntegration).toBe(replayIntegrationShim); - expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); - expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracingShim); - expect(TracingReplayBundle.Feedback).toBe(Feedback); expect(TracingReplayBundle.feedbackIntegration).toBe(feedbackIntegration); }); diff --git a/packages/browser/test/unit/index.bundle.replay.test.ts b/packages/browser/test/unit/index.bundle.replay.test.ts index e2d5640a2183..a40daa2ea0d6 100644 --- a/packages/browser/test/unit/index.bundle.replay.test.ts +++ b/packages/browser/test/unit/index.bundle.replay.test.ts @@ -1,9 +1,5 @@ /* eslint-disable deprecation/deprecation */ -import { - BrowserTracing as BrowserTracingShim, - Feedback as FeedbackShim, - feedbackIntegration as feedbackIntegrationShim, -} from '@sentry-internal/integration-shims'; +import { FeedbackShim, feedbackIntegrationShim } from '@sentry-internal/integration-shims'; import { Replay, replayIntegration } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.replay'; @@ -11,11 +7,6 @@ import * as TracingReplayBundle from '../../src/index.bundle.replay'; describe('index.bundle.replay', () => { it('has correct exports', () => { Object.keys(TracingReplayBundle.Integrations).forEach(key => { - // Skip BrowserTracing because it doesn't have a static id field. - if (key === 'BrowserTracing') { - return; - } - expect((TracingReplayBundle.Integrations[key] as any).id).toStrictEqual(expect.any(String)); }); @@ -23,9 +14,6 @@ describe('index.bundle.replay', () => { expect(TracingReplayBundle.Replay).toBe(Replay); expect(TracingReplayBundle.replayIntegration).toBe(replayIntegration); - expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); - expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracingShim); - expect(TracingReplayBundle.Feedback).toBe(FeedbackShim); expect(TracingReplayBundle.feedbackIntegration).toBe(feedbackIntegrationShim); }); diff --git a/packages/browser/test/unit/index.bundle.test.ts b/packages/browser/test/unit/index.bundle.test.ts index d637c8de1c3d..bf498477c73c 100644 --- a/packages/browser/test/unit/index.bundle.test.ts +++ b/packages/browser/test/unit/index.bundle.test.ts @@ -1,10 +1,9 @@ /* eslint-disable deprecation/deprecation */ import { - BrowserTracing as BrowserTracingShim, - Feedback as FeedbackShim, - Replay as ReplayShim, - feedbackIntegration as feedbackIntegrationShim, - replayIntegration as replayIntegrationShim, + FeedbackShim, + ReplayShim, + feedbackIntegrationShim, + replayIntegrationShim, } from '@sentry-internal/integration-shims'; import * as TracingBundle from '../../src/index.bundle'; @@ -12,11 +11,6 @@ import * as TracingBundle from '../../src/index.bundle'; describe('index.bundle', () => { it('has correct exports', () => { Object.keys(TracingBundle.Integrations).forEach(key => { - // Skip BrowserTracing because it doesn't have a static id field. - if (key === 'BrowserTracing') { - return; - } - expect((TracingBundle.Integrations[key] as any).id).toStrictEqual(expect.any(String)); }); @@ -24,9 +18,6 @@ describe('index.bundle', () => { expect(TracingBundle.Replay).toBe(ReplayShim); expect(TracingBundle.replayIntegration).toBe(replayIntegrationShim); - expect(TracingBundle.Integrations.BrowserTracing).toBe(BrowserTracingShim); - expect(TracingBundle.BrowserTracing).toBe(BrowserTracingShim); - expect(TracingBundle.Feedback).toBe(FeedbackShim); expect(TracingBundle.feedbackIntegration).toBe(feedbackIntegrationShim); }); diff --git a/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts b/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts index 29b700773d92..962934f064f8 100644 --- a/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.replay.feedback.test.ts @@ -1,5 +1,5 @@ /* eslint-disable deprecation/deprecation */ -import { BrowserTracing } from '@sentry-internal/tracing'; +import { browserTracingIntegration } from '@sentry-internal/tracing'; import { Feedback, Replay, feedbackIntegration, replayIntegration } from '@sentry/browser'; import * as TracingReplayFeedbackBundle from '../../src/index.bundle.tracing.replay.feedback'; @@ -7,11 +7,6 @@ import * as TracingReplayFeedbackBundle from '../../src/index.bundle.tracing.rep describe('index.bundle.tracing.replay.feedback', () => { it('has correct exports', () => { Object.keys(TracingReplayFeedbackBundle.Integrations).forEach(key => { - // Skip BrowserTracing because it doesn't have a static id field. - if (key === 'BrowserTracing') { - return; - } - expect((TracingReplayFeedbackBundle.Integrations[key] as any).id).toStrictEqual(expect.any(String)); }); @@ -19,8 +14,7 @@ describe('index.bundle.tracing.replay.feedback', () => { expect(TracingReplayFeedbackBundle.Replay).toBe(Replay); expect(TracingReplayFeedbackBundle.replayIntegration).toBe(replayIntegration); - expect(TracingReplayFeedbackBundle.Integrations.BrowserTracing).toBe(BrowserTracing); - expect(TracingReplayFeedbackBundle.BrowserTracing).toBe(BrowserTracing); + expect(TracingReplayFeedbackBundle.browserTracingIntegration).toBe(browserTracingIntegration); expect(TracingReplayFeedbackBundle.Feedback).toBe(Feedback); expect(TracingReplayFeedbackBundle.feedbackIntegration).toBe(feedbackIntegration); diff --git a/packages/browser/test/unit/index.bundle.tracing.replay.test.ts b/packages/browser/test/unit/index.bundle.tracing.replay.test.ts index 4db32003607e..a90eac6cbe60 100644 --- a/packages/browser/test/unit/index.bundle.tracing.replay.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.replay.test.ts @@ -1,9 +1,6 @@ /* eslint-disable deprecation/deprecation */ -import { - Feedback as FeedbackShim, - feedbackIntegration as feedbackIntegrationShim, -} from '@sentry-internal/integration-shims'; -import { BrowserTracing } from '@sentry-internal/tracing'; +import { FeedbackShim, feedbackIntegrationShim } from '@sentry-internal/integration-shims'; +import { browserTracingIntegration } from '@sentry-internal/tracing'; import { Replay, replayIntegration } from '@sentry/browser'; import * as TracingReplayBundle from '../../src/index.bundle.tracing.replay'; @@ -11,11 +8,6 @@ import * as TracingReplayBundle from '../../src/index.bundle.tracing.replay'; describe('index.bundle.tracing.replay', () => { it('has correct exports', () => { Object.keys(TracingReplayBundle.Integrations).forEach(key => { - // Skip BrowserTracing because it doesn't have a static id field. - if (key === 'BrowserTracing') { - return; - } - expect((TracingReplayBundle.Integrations[key] as any).id).toStrictEqual(expect.any(String)); }); @@ -23,8 +15,7 @@ describe('index.bundle.tracing.replay', () => { expect(TracingReplayBundle.Replay).toBe(Replay); expect(TracingReplayBundle.replayIntegration).toBe(replayIntegration); - expect(TracingReplayBundle.Integrations.BrowserTracing).toBe(BrowserTracing); - expect(TracingReplayBundle.BrowserTracing).toBe(BrowserTracing); + expect(TracingReplayBundle.browserTracingIntegration).toBe(browserTracingIntegration); expect(TracingReplayBundle.Feedback).toBe(FeedbackShim); expect(TracingReplayBundle.feedbackIntegration).toBe(feedbackIntegrationShim); diff --git a/packages/browser/test/unit/index.bundle.tracing.test.ts b/packages/browser/test/unit/index.bundle.tracing.test.ts index cf03a26f7054..0f8257ee4ad0 100644 --- a/packages/browser/test/unit/index.bundle.tracing.test.ts +++ b/packages/browser/test/unit/index.bundle.tracing.test.ts @@ -1,22 +1,17 @@ /* eslint-disable deprecation/deprecation */ import { - Feedback as FeedbackShim, - Replay as ReplayShim, - feedbackIntegration as feedbackIntegrationShim, - replayIntegration as replayIntegrationShim, + FeedbackShim, + ReplayShim, + feedbackIntegrationShim, + replayIntegrationShim, } from '@sentry-internal/integration-shims'; -import { BrowserTracing } from '@sentry-internal/tracing'; +import { browserTracingIntegration } from '@sentry-internal/tracing'; import * as TracingBundle from '../../src/index.bundle.tracing'; describe('index.bundle.tracing', () => { it('has correct exports', () => { Object.keys(TracingBundle.Integrations).forEach(key => { - // Skip BrowserTracing because it doesn't have a static id field. - if (key === 'BrowserTracing') { - return; - } - expect((TracingBundle.Integrations[key] as any).id).toStrictEqual(expect.any(String)); }); @@ -24,8 +19,7 @@ describe('index.bundle.tracing', () => { expect(TracingBundle.Replay).toBe(ReplayShim); expect(TracingBundle.replayIntegration).toBe(replayIntegrationShim); - expect(TracingBundle.Integrations.BrowserTracing).toBe(BrowserTracing); - expect(TracingBundle.BrowserTracing).toBe(BrowserTracing); + expect(TracingBundle.browserTracingIntegration).toBe(browserTracingIntegration); expect(TracingBundle.Feedback).toBe(FeedbackShim); expect(TracingBundle.feedbackIntegration).toBe(feedbackIntegrationShim); diff --git a/packages/gatsby/test/sdk.test.ts b/packages/gatsby/test/sdk.test.ts index 28206d1ef6c5..7abdc82c6834 100644 --- a/packages/gatsby/test/sdk.test.ts +++ b/packages/gatsby/test/sdk.test.ts @@ -48,7 +48,7 @@ describe('Initialize React SDK', () => { }); }); - test('Has BrowserTracing if tracing enabled', () => { + test('Has browserTracingIntegration if tracing enabled', () => { gatsbyInit({ tracesSampleRate: 1 }); expect(reactInit).toHaveBeenCalledTimes(1); const calledWith = reactInit.mock.calls[0][0]; @@ -66,13 +66,13 @@ describe('Integrations from options', () => { ['tracing disabled, no integrations', [], {}, []], ['tracing enabled, no integrations', [], { tracesSampleRate: 1 }, ['BrowserTracing']], [ - 'tracing disabled, with BrowserTracing as an array', + 'tracing disabled, with browserTracingIntegration as an array', [], { integrations: [browserTracingIntegration()] }, ['BrowserTracing'], ], [ - 'tracing disabled, with BrowserTracing as a function', + 'tracing disabled, with browserTracingIntegration as a function', [], { integrations: () => [browserTracingIntegration()], @@ -80,13 +80,13 @@ describe('Integrations from options', () => { ['BrowserTracing'], ], [ - 'tracing enabled, with BrowserTracing as an array', + 'tracing enabled, with browserTracingIntegration as an array', [], { tracesSampleRate: 1, integrations: [browserTracingIntegration()] }, ['BrowserTracing'], ], [ - 'tracing enabled, with BrowserTracing as a function', + 'tracing enabled, with browserTracingIntegration as a function', [], { tracesSampleRate: 1, integrations: () => [browserTracingIntegration()] }, ['BrowserTracing'], diff --git a/packages/integration-shims/package.json b/packages/integration-shims/package.json index 5bc5f40f039d..3d2c599058c8 100644 --- a/packages/integration-shims/package.json +++ b/packages/integration-shims/package.json @@ -39,6 +39,7 @@ "url": "https://github.com/getsentry/sentry-javascript/issues" }, "dependencies": { + "@sentry/core": "7.100.0", "@sentry/types": "7.100.0", "@sentry/utils": "7.100.0" }, diff --git a/packages/integration-shims/src/BrowserTracing.ts b/packages/integration-shims/src/BrowserTracing.ts index 1c68faf30469..32841d842718 100644 --- a/packages/integration-shims/src/BrowserTracing.ts +++ b/packages/integration-shims/src/BrowserTracing.ts @@ -1,58 +1,23 @@ -import type { Integration } from '@sentry/types'; +import { defineIntegration } from '@sentry/core'; import { consoleSandbox } from '@sentry/utils'; /** * This is a shim for the BrowserTracing integration. * It is needed in order for the CDN bundles to continue working when users add/remove tracing * from it, without changing their config. This is necessary for the loader mechanism. - * - * @deprecated Use `browserTracingIntegration()` instead. */ -class BrowserTracingShim implements Integration { - /** - * @inheritDoc - */ - public static id: string = 'BrowserTracing'; +export const browserTracingIntegrationShim = defineIntegration((_options?: unknown) => { + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.warn('You are using new BrowserTracing() even though this bundle does not include tracing.'); + }); - /** - * @inheritDoc - */ - public name: string; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public constructor(_options: any) { - // eslint-disable-next-line deprecation/deprecation - this.name = BrowserTracingShim.id; - - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn('You are using new BrowserTracing() even though this bundle does not include tracing.'); - }); - } - - /** jsdoc */ - public setupOnce(): void { - // noop - } -} - -/** - * This is a shim for the BrowserTracing integration. - * It is needed in order for the CDN bundles to continue working when users add/remove tracing - * from it, without changing their config. This is necessary for the loader mechanism. - */ -function browserTracingIntegrationShim(_options: unknown): Integration { - // eslint-disable-next-line deprecation/deprecation - return new BrowserTracingShim({}); -} - -export { - // eslint-disable-next-line deprecation/deprecation - BrowserTracingShim as BrowserTracing, - browserTracingIntegrationShim as browserTracingIntegration, -}; + return { + name: 'BrowserTracing', + }; +}); /** Shim function */ -export function addTracingExtensions(): void { +export function addTracingExtensionsShim(): void { // noop } diff --git a/packages/integration-shims/src/Feedback.ts b/packages/integration-shims/src/Feedback.ts index 7b717e3a4e3b..419071d2bd26 100644 --- a/packages/integration-shims/src/Feedback.ts +++ b/packages/integration-shims/src/Feedback.ts @@ -8,7 +8,7 @@ import { consoleSandbox } from '@sentry/utils'; * * @deprecated Use `feedbackIntegration()` instead. */ -class FeedbackShim implements Integration { +export class FeedbackShim implements Integration { /** * @inheritDoc */ @@ -75,10 +75,7 @@ class FeedbackShim implements Integration { * It is needed in order for the CDN bundles to continue working when users add/remove feedback * from it, without changing their config. This is necessary for the loader mechanism. */ -export function feedbackIntegration(_options: unknown): Integration { +export function feedbackIntegrationShim(_options: unknown): Integration { // eslint-disable-next-line deprecation/deprecation return new FeedbackShim({}); } - -// eslint-disable-next-line deprecation/deprecation -export { FeedbackShim as Feedback }; diff --git a/packages/integration-shims/src/Replay.ts b/packages/integration-shims/src/Replay.ts index 3bcc6c3e6563..ddebdbb14402 100644 --- a/packages/integration-shims/src/Replay.ts +++ b/packages/integration-shims/src/Replay.ts @@ -8,7 +8,7 @@ import { consoleSandbox } from '@sentry/utils'; * * @deprecated Use `replayIntegration()` instead. */ -class ReplayShim implements Integration { +export class ReplayShim implements Integration { /** * @inheritDoc */ @@ -56,10 +56,7 @@ class ReplayShim implements Integration { * It is needed in order for the CDN bundles to continue working when users add/remove replay * from it, without changing their config. This is necessary for the loader mechanism. */ -export function replayIntegration(_options: unknown): Integration { +export function replayIntegrationShim(_options: unknown): Integration { // eslint-disable-next-line deprecation/deprecation return new ReplayShim({}); } - -// eslint-disable-next-line deprecation/deprecation -export { ReplayShim as Replay }; diff --git a/packages/integration-shims/src/index.ts b/packages/integration-shims/src/index.ts index bffdf82c99f7..64124f4a93cc 100644 --- a/packages/integration-shims/src/index.ts +++ b/packages/integration-shims/src/index.ts @@ -1,18 +1,16 @@ export { // eslint-disable-next-line deprecation/deprecation - Feedback, - feedbackIntegration, + FeedbackShim, + feedbackIntegrationShim, } from './Feedback'; export { // eslint-disable-next-line deprecation/deprecation - Replay, - replayIntegration, + ReplayShim, + replayIntegrationShim, } from './Replay'; export { - // eslint-disable-next-line deprecation/deprecation - BrowserTracing, - browserTracingIntegration, - addTracingExtensions, + browserTracingIntegrationShim, + addTracingExtensionsShim, } from './BrowserTracing'; diff --git a/packages/nextjs/src/client/browserTracingIntegration.ts b/packages/nextjs/src/client/browserTracingIntegration.ts index 42af9f9a2045..d70eb3da0746 100644 --- a/packages/nextjs/src/client/browserTracingIntegration.ts +++ b/packages/nextjs/src/client/browserTracingIntegration.ts @@ -7,7 +7,7 @@ import type { Integration, StartSpanOptions } from '@sentry/types'; import { nextRouterInstrumentation } from './routing/nextRoutingInstrumentation'; /** - * A custom BrowserTracing integration for Next.js. + * A custom browser tracing integration for Next.js. */ export function browserTracingIntegration( options: Parameters[0] = {}, diff --git a/packages/node/test/integrations/http.test.ts b/packages/node/test/integrations/http.test.ts index 63559d9102d7..c2e85f8ac170 100644 --- a/packages/node/test/integrations/http.test.ts +++ b/packages/node/test/integrations/http.test.ts @@ -1,7 +1,7 @@ import * as http from 'http'; import * as https from 'https'; -import type { Hub, SentrySpan } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; +import type { Hub, SentrySpan } from '@sentry/core'; import { getCurrentHub, getIsolationScope, setCurrentClient } from '@sentry/core'; import { Transaction } from '@sentry/core'; import { getCurrentScope, setUser, spanToJSON, startInactiveSpan } from '@sentry/core'; diff --git a/packages/remix/test/integration/app_v1/entry.client.tsx b/packages/remix/test/integration/app_v1/entry.client.tsx index 17da03ff6a70..bdee1860d03f 100644 --- a/packages/remix/test/integration/app_v1/entry.client.tsx +++ b/packages/remix/test/integration/app_v1/entry.client.tsx @@ -7,8 +7,10 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', tracesSampleRate: 1, integrations: [ - new Sentry.BrowserTracing({ - routingInstrumentation: Sentry.remixRouterInstrumentation(useEffect, useLocation, useMatches), + Sentry.browserTracingIntegration({ + useEffect, + useLocation, + useMatches, }), ], }); diff --git a/packages/remix/test/integration/app_v2/entry.client.tsx b/packages/remix/test/integration/app_v2/entry.client.tsx index 17da03ff6a70..bdee1860d03f 100644 --- a/packages/remix/test/integration/app_v2/entry.client.tsx +++ b/packages/remix/test/integration/app_v2/entry.client.tsx @@ -7,8 +7,10 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', tracesSampleRate: 1, integrations: [ - new Sentry.BrowserTracing({ - routingInstrumentation: Sentry.remixRouterInstrumentation(useEffect, useLocation, useMatches), + Sentry.browserTracingIntegration({ + useEffect, + useLocation, + useMatches, }), ], }); diff --git a/packages/svelte/README.md b/packages/svelte/README.md index 5ea7bbed0fb8..bccd18a3c744 100644 --- a/packages/svelte/README.md +++ b/packages/svelte/README.md @@ -10,28 +10,29 @@ [![npm dm](https://img.shields.io/npm/dm/@sentry/svelte.svg)](https://www.npmjs.com/package/@sentry/svelte) [![npm dt](https://img.shields.io/npm/dt/@sentry/svelte.svg)](https://www.npmjs.com/package/@sentry/svelte) -This SDK currently only supports [Svelte](https://svelte.dev/) apps in the browser. -If you're using SvelteKit, we recommend using our dedicated [Sentry SvelteKit SDK](https://github.com/getsentry/sentry-javascript/tree/develop/packages/sveltekit). +This SDK currently only supports [Svelte](https://svelte.dev/) apps in the browser. If you're using SvelteKit, we +recommend using our dedicated +[Sentry SvelteKit SDK](https://github.com/getsentry/sentry-javascript/tree/develop/packages/sveltekit). ## General -This package is a wrapper around `@sentry/browser`, providing error monitoring and basic performance monitoring -features for [Svelte](https://svelte.dev/). +This package is a wrapper around `@sentry/browser`, providing error monitoring and basic performance monitoring features +for [Svelte](https://svelte.dev/). To use the SDK, initialize Sentry in your Svelte entry point `main.js` before you bootstrap your Svelte app: ```ts // main.js / main.ts -import App from "./App.svelte"; +import App from './App.svelte'; -import * as Sentry from "@sentry/svelte"; +import * as Sentry from '@sentry/svelte'; // Initialize the Sentry SDK here Sentry.init({ - dsn: "__DSN__", - release: "my-project-name@2.3.12", - integrations: [new Sentry.BrowserTracing()], + dsn: '__DSN__', + release: 'my-project-name@2.3.12', + integrations: [Sentry.browserTracingIntegration()], // Set tracesSampleRate to 1.0 to capture 100% // of transactions for performance monitoring. @@ -41,19 +42,25 @@ Sentry.init({ // Then bootstrap your Svelte app const app = new App({ - target: document.getElementById("app"), + target: document.getElementById('app'), }); export default app; ``` -The Sentry Svelte SDK supports all features from the `@sentry/browser` SDK. Until it becomes more stable, please refer to the Sentry [Browser SDK documentation](https://docs.sentry.io/platforms/javascript/) for more information and usage instructions. +The Sentry Svelte SDK supports all features from the `@sentry/browser` SDK. Until it becomes more stable, please refer +to the Sentry [Browser SDK documentation](https://docs.sentry.io/platforms/javascript/) for more information and usage +instructions. ## Sourcemaps and Releases -To generate source maps of your Svelte app bundle, check our guide [how to configure your bundler](https://docs.sentry.io/platforms/javascript/guides/svelte/sourcemaps/generating/) to emit source maps. +To generate source maps of your Svelte app bundle, check our guide +[how to configure your bundler](https://docs.sentry.io/platforms/javascript/guides/svelte/sourcemaps/generating/) to +emit source maps. -To [create releases and upload source maps](https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/cli/) to Sentry, we recommend using [`sentry-cli`](https://github.com/getsentry/sentry-cli). You can for instance create a bash script to take care of creating a release, uploading source maps and finalizing the release: +To [create releases and upload source maps](https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/cli/) to +Sentry, we recommend using [`sentry-cli`](https://github.com/getsentry/sentry-cli). You can for instance create a bash +script to take care of creating a release, uploading source maps and finalizing the release: ```bash #!/bin/bash @@ -69,6 +76,12 @@ sentry-cli releases files $VERSION upload-sourcemaps $SOURCEMAPS_PATH --org $ORG sentry-cli releases finalize $VERSION --org $ORG --project $PROJECT ``` -Please note that the paths provided in this example work for a typical Svelte project that adheres to the project structure set by [create-vite](https://www.npmjs.com/package/create-vite) with the `svelte(-ts)` template. If your project setup differs from this template, your configuration may need adjustments. Please refer to our documentation of [Advanced `sentry-cli` Sourcemaps Options](https://docs.sentry.io/product/cli/releases/#sentry-cli-sourcemaps) and to our [Sourcemaps Troubleshooting Guide](https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/). +Please note that the paths provided in this example work for a typical Svelte project that adheres to the project +structure set by [create-vite](https://www.npmjs.com/package/create-vite) with the `svelte(-ts)` template. If your +project setup differs from this template, your configuration may need adjustments. Please refer to our documentation of +[Advanced `sentry-cli` Sourcemaps Options](https://docs.sentry.io/product/cli/releases/#sentry-cli-sourcemaps) and to +our [Sourcemaps Troubleshooting Guide](https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/). -Check out our [Svelte source maps uploading](https://docs.sentry.io/platforms/javascript/guides/svelte/sourcemaps/uploading/) guide for more information. +Check out our +[Svelte source maps uploading](https://docs.sentry.io/platforms/javascript/guides/svelte/sourcemaps/uploading/) guide +for more information. diff --git a/packages/sveltekit/src/client/browserTracingIntegration.ts b/packages/sveltekit/src/client/browserTracingIntegration.ts index ab727e9d76f8..42817d49e22a 100644 --- a/packages/sveltekit/src/client/browserTracingIntegration.ts +++ b/packages/sveltekit/src/client/browserTracingIntegration.ts @@ -1,7 +1,6 @@ import { navigating, page } from '$app/stores'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; import { - BrowserTracing as OriginalBrowserTracing, WINDOW, browserTracingIntegration as originalBrowserTracingIntegration, startBrowserTracingNavigationSpan, @@ -10,26 +9,6 @@ import { } from '@sentry/svelte'; import type { Client, Integration, Span } from '@sentry/types'; import { dropUndefinedKeys } from '@sentry/utils'; -import { svelteKitRoutingInstrumentation } from './router'; - -/** - * A custom BrowserTracing integration for Sveltekit. - * - * @deprecated use `browserTracingIntegration()` instead. The new `browserTracingIntegration()` - * includes SvelteKit-specific routing instrumentation out of the box. Therefore there's no need - * to pass in `svelteKitRoutingInstrumentation` anymore. - */ -// eslint-disable-next-line deprecation/deprecation -export class BrowserTracing extends OriginalBrowserTracing { - // eslint-disable-next-line deprecation/deprecation - public constructor(options?: ConstructorParameters[0]) { - super({ - // eslint-disable-next-line deprecation/deprecation - routingInstrumentation: svelteKitRoutingInstrumentation, - ...options, - }); - } -} /** * A custom `BrowserTracing` integration for SvelteKit. diff --git a/packages/sveltekit/src/client/router.ts b/packages/sveltekit/src/client/router.ts deleted file mode 100644 index cb38aad2ea3a..000000000000 --- a/packages/sveltekit/src/client/router.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getActiveTransaction } from '@sentry/core'; -import { WINDOW } from '@sentry/svelte'; -import type { Span, Transaction, TransactionContext } from '@sentry/types'; - -import { navigating, page } from '$app/stores'; - -const DEFAULT_TAGS = { - 'routing.instrumentation': '@sentry/sveltekit', -}; - -/** - * Automatically creates pageload and navigation transactions for the client-side SvelteKit router. - * - * This instrumentation makes use of SvelteKit's `page` and `navigating` stores which can be accessed - * anywhere on the client side. - * - * @param startTransactionFn the function used to start (idle) transactions - * @param startTransactionOnPageLoad controls if pageload transactions should be created (defaults to `true`) - * @param startTransactionOnLocationChange controls if navigation transactions should be created (defauls to `true`) - * - * @deprecated use `browserTracingIntegration()` instead which includes SvelteKit-specific routing instrumentation out of the box. - * Therefore, this function will be removed in v8. - */ -export function svelteKitRoutingInstrumentation( - startTransactionFn: (context: TransactionContext) => T | undefined, - startTransactionOnPageLoad: boolean = true, - startTransactionOnLocationChange: boolean = true, -): void { - if (startTransactionOnPageLoad) { - instrumentPageload(startTransactionFn); - } - - if (startTransactionOnLocationChange) { - instrumentNavigations(startTransactionFn); - } -} - -function instrumentPageload(startTransactionFn: (context: TransactionContext) => Transaction | undefined): void { - const initialPath = WINDOW && WINDOW.location && WINDOW.location.pathname; - - const pageloadTransaction = startTransactionFn({ - name: initialPath, - op: 'pageload', - origin: 'auto.pageload.sveltekit', - tags: { - ...DEFAULT_TAGS, - }, - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', - }, - }); - - page.subscribe(page => { - if (!page) { - return; - } - - const routeId = page.route && page.route.id; - - if (pageloadTransaction && routeId) { - pageloadTransaction.updateName(routeId); - pageloadTransaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route'); - } - }); -} - -/** - * Use the `navigating` store to start a transaction on navigations. - */ -function instrumentNavigations(startTransactionFn: (context: TransactionContext) => Transaction | undefined): void { - let routingSpan: Span | undefined = undefined; - let activeTransaction: Transaction | undefined; - - navigating.subscribe(navigation => { - if (!navigation) { - // `navigating` emits a 'null' value when the navigation is completed. - // So in this case, we can finish the routing span. If the transaction was an IdleTransaction, - // it will finish automatically and if it was user-created users also need to finish it. - if (routingSpan) { - routingSpan.end(); - routingSpan = undefined; - } - return; - } - - const from = navigation.from; - const to = navigation.to; - - // for the origin we can fall back to window.location.pathname because in this emission, it still is set to the origin path - const rawRouteOrigin = (from && from.url.pathname) || (WINDOW && WINDOW.location && WINDOW.location.pathname); - - const rawRouteDestination = to && to.url.pathname; - - // We don't want to create transactions for navigations of same origin and destination. - // We need to look at the raw URL here because parameterized routes can still differ in their raw parameters. - if (rawRouteOrigin === rawRouteDestination) { - return; - } - - const parameterizedRouteOrigin = from && from.route.id; - const parameterizedRouteDestination = to && to.route.id; - - // eslint-disable-next-line deprecation/deprecation - activeTransaction = getActiveTransaction(); - - if (!activeTransaction) { - activeTransaction = startTransactionFn({ - name: parameterizedRouteDestination || rawRouteDestination || 'unknown', - op: 'navigation', - origin: 'auto.navigation.sveltekit', - attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: parameterizedRouteDestination ? 'route' : 'url' }, - tags: { - ...DEFAULT_TAGS, - }, - }); - } - - if (activeTransaction) { - if (routingSpan) { - // If a routing span is still open from a previous navigation, we finish it. - routingSpan.end(); - } - // eslint-disable-next-line deprecation/deprecation - routingSpan = activeTransaction.startChild({ - op: 'ui.sveltekit.routing', - name: 'SvelteKit Route Change', - origin: 'auto.ui.sveltekit', - }); - // eslint-disable-next-line deprecation/deprecation - activeTransaction.setTag('from', parameterizedRouteOrigin); - } - }); -} diff --git a/packages/sveltekit/src/client/sdk.ts b/packages/sveltekit/src/client/sdk.ts index a3c996457c46..86b869af65d3 100644 --- a/packages/sveltekit/src/client/sdk.ts +++ b/packages/sveltekit/src/client/sdk.ts @@ -1,13 +1,10 @@ import { applySdkMetadata, hasTracingEnabled, setTag } from '@sentry/core'; -import type { BrowserOptions, browserTracingIntegration } from '@sentry/svelte'; +import type { BrowserOptions } from '@sentry/svelte'; import { getDefaultIntegrations as getDefaultSvelteIntegrations } from '@sentry/svelte'; import { WINDOW, init as initSvelteSdk } from '@sentry/svelte'; import type { Integration } from '@sentry/types'; -import { - BrowserTracing, - browserTracingIntegration as svelteKitBrowserTracingIntegration, -} from './browserTracingIntegration'; +import { browserTracingIntegration as svelteKitBrowserTracingIntegration } from './browserTracingIntegration'; type WindowWithSentryFetchProxy = typeof WINDOW & { _sentryFetchProxy?: typeof fetch; @@ -29,8 +26,6 @@ export function init(options: BrowserOptions): void { applySdkMetadata(opts, 'sveltekit', ['sveltekit', 'svelte']); - fixBrowserTracingIntegration(opts); - // 1. Switch window.fetch to our fetch proxy we injected earlier const actualFetch = switchToFetchProxy(); @@ -45,61 +40,6 @@ export function init(options: BrowserOptions): void { setTag('runtime', 'browser'); } -// TODO v8: Remove this again -// We need to handle BrowserTracing passed to `integrations` that comes from `@sentry/tracing`, not `@sentry/sveltekit` :( -function fixBrowserTracingIntegration(options: BrowserOptions): void { - const { integrations } = options; - if (!integrations) { - return; - } - - if (Array.isArray(integrations)) { - options.integrations = maybeUpdateBrowserTracingIntegration(integrations); - } else { - options.integrations = defaultIntegrations => { - const userFinalIntegrations = integrations(defaultIntegrations); - - return maybeUpdateBrowserTracingIntegration(userFinalIntegrations); - }; - } -} - -function isNewBrowserTracingIntegration( - integration: Integration, -): integration is Integration & { options?: Parameters[0] } { - // eslint-disable-next-line deprecation/deprecation - return !!integration.afterAllSetup && !!(integration as BrowserTracing).options; -} - -function maybeUpdateBrowserTracingIntegration(integrations: Integration[]): Integration[] { - const browserTracing = integrations.find(integration => integration.name === 'BrowserTracing'); - - if (!browserTracing) { - return integrations; - } - - // If `browserTracingIntegration()` was added, we need to force-convert it to our custom one - if (isNewBrowserTracingIntegration(browserTracing)) { - const { options } = browserTracing; - // eslint-disable-next-line deprecation/deprecation - integrations[integrations.indexOf(browserTracing)] = new BrowserTracing(options); - } - - // If BrowserTracing was added, but it is not our forked version, - // replace it with our forked version with the same options - // eslint-disable-next-line deprecation/deprecation - if (!(browserTracing instanceof BrowserTracing)) { - // eslint-disable-next-line deprecation/deprecation - const options: ConstructorParameters[0] = (browserTracing as BrowserTracing).options; - // This option is overwritten by the custom integration - delete options.routingInstrumentation; - // eslint-disable-next-line deprecation/deprecation - integrations[integrations.indexOf(browserTracing)] = new BrowserTracing(options); - } - - return integrations; -} - function getDefaultIntegrations(options: BrowserOptions): Integration[] | undefined { // This evaluates to true unless __SENTRY_TRACING__ is text-replaced with "false", in which case everything inside // will get treeshaken away diff --git a/packages/sveltekit/test/client/router.test.ts b/packages/sveltekit/test/client/router.test.ts deleted file mode 100644 index ab8455c5c4e2..000000000000 --- a/packages/sveltekit/test/client/router.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -/* eslint-disable @typescript-eslint/unbound-method */ -import type { Transaction } from '@sentry/types'; -import { writable } from 'svelte/store'; -import type { SpyInstance } from 'vitest'; -import { vi } from 'vitest'; - -import { navigating, page } from '$app/stores'; - -import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; -import { svelteKitRoutingInstrumentation } from '../../src/client/router'; - -// we have to overwrite the global mock from `vitest.setup.ts` here to reset the -// `navigating` store for each test. -vi.mock('$app/stores', async () => { - return { - get navigating() { - return navigatingStore; - }, - page: writable(), - }; -}); - -let navigatingStore = writable(); - -describe('sveltekitRoutingInstrumentation', () => { - let returnedTransaction: (Transaction & { returnedTransaction: SpyInstance }) | undefined; - const mockedStartTransaction = vi.fn().mockImplementation(txnCtx => { - returnedTransaction = { - ...txnCtx, - updateName: vi.fn(), - setAttribute: vi.fn(), - startChild: vi.fn().mockImplementation(ctx => { - return { ...mockedRoutingSpan, ...ctx }; - }), - setTag: vi.fn(), - }; - return returnedTransaction; - }); - - const mockedRoutingSpan = { - end: () => {}, - }; - - const routingSpanFinishSpy = vi.spyOn(mockedRoutingSpan, 'end'); - - beforeEach(() => { - navigatingStore = writable(); - vi.clearAllMocks(); - }); - - it("starts a pageload transaction when it's called with default params", () => { - // eslint-disable-next-line deprecation/deprecation - svelteKitRoutingInstrumentation(mockedStartTransaction); - - expect(mockedStartTransaction).toHaveBeenCalledTimes(1); - expect(mockedStartTransaction).toHaveBeenCalledWith({ - name: '/', - op: 'pageload', - origin: 'auto.pageload.sveltekit', - tags: { - 'routing.instrumentation': '@sentry/sveltekit', - }, - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', - }, - }); - - // We emit an update to the `page` store to simulate the SvelteKit router lifecycle - page.set({ route: { id: 'testRoute' } }); - - // This should update the transaction name with the parameterized route: - expect(returnedTransaction?.updateName).toHaveBeenCalledTimes(1); - expect(returnedTransaction?.updateName).toHaveBeenCalledWith('testRoute'); - expect(returnedTransaction?.setAttribute).toHaveBeenCalledWith(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route'); - }); - - it("doesn't start a pageload transaction if `startTransactionOnPageLoad` is false", () => { - // eslint-disable-next-line deprecation/deprecation - svelteKitRoutingInstrumentation(mockedStartTransaction, false); - expect(mockedStartTransaction).toHaveBeenCalledTimes(0); - }); - - it("doesn't start a navigation transaction when `startTransactionOnLocationChange` is false", () => { - // eslint-disable-next-line deprecation/deprecation - svelteKitRoutingInstrumentation(mockedStartTransaction, false, false); - - // We emit an update to the `navigating` store to simulate the SvelteKit navigation lifecycle - navigating.set({ - from: { route: { id: '/users' }, url: { pathname: '/users' } }, - to: { route: { id: '/users/[id]' }, url: { pathname: '/users/7762' } }, - }); - - // This should update the transaction name with the parameterized route: - expect(mockedStartTransaction).toHaveBeenCalledTimes(0); - }); - - it('starts a navigation transaction when `startTransactionOnLocationChange` is true', () => { - // eslint-disable-next-line deprecation/deprecation - svelteKitRoutingInstrumentation(mockedStartTransaction, false, true); - - // We emit an update to the `navigating` store to simulate the SvelteKit navigation lifecycle - navigating.set({ - from: { route: { id: '/users' }, url: { pathname: '/users' } }, - to: { route: { id: '/users/[id]' }, url: { pathname: '/users/7762' } }, - }); - - // This should update the transaction name with the parameterized route: - expect(mockedStartTransaction).toHaveBeenCalledTimes(1); - expect(mockedStartTransaction).toHaveBeenCalledWith({ - name: '/users/[id]', - op: 'navigation', - origin: 'auto.navigation.sveltekit', - attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route' }, - tags: { - 'routing.instrumentation': '@sentry/sveltekit', - }, - }); - - // eslint-disable-next-line deprecation/deprecation - expect(returnedTransaction?.startChild).toHaveBeenCalledWith({ - op: 'ui.sveltekit.routing', - origin: 'auto.ui.sveltekit', - name: 'SvelteKit Route Change', - }); - - // eslint-disable-next-line deprecation/deprecation - expect(returnedTransaction?.setTag).toHaveBeenCalledWith('from', '/users'); - - // We emit `null` here to simulate the end of the navigation lifecycle - navigating.set(null); - - expect(routingSpanFinishSpy).toHaveBeenCalledTimes(1); - }); - - describe('handling same origin and destination navigations', () => { - it("doesn't start a navigation transaction if the raw navigation origin and destination are equal", () => { - // eslint-disable-next-line deprecation/deprecation - svelteKitRoutingInstrumentation(mockedStartTransaction, false, true); - - // We emit an update to the `navigating` store to simulate the SvelteKit navigation lifecycle - navigating.set({ - from: { route: { id: '/users/[id]' }, url: { pathname: '/users/7762' } }, - to: { route: { id: '/users/[id]' }, url: { pathname: '/users/7762' } }, - }); - - expect(mockedStartTransaction).toHaveBeenCalledTimes(0); - }); - - it('starts a navigation transaction if the raw navigation origin and destination are not equal', () => { - // eslint-disable-next-line deprecation/deprecation - svelteKitRoutingInstrumentation(mockedStartTransaction, false, true); - - navigating.set({ - from: { route: { id: '/users/[id]' }, url: { pathname: '/users/7762' } }, - to: { route: { id: '/users/[id]' }, url: { pathname: '/users/223412' } }, - }); - - expect(mockedStartTransaction).toHaveBeenCalledTimes(1); - expect(mockedStartTransaction).toHaveBeenCalledWith({ - name: '/users/[id]', - op: 'navigation', - origin: 'auto.navigation.sveltekit', - attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route' }, - tags: { - 'routing.instrumentation': '@sentry/sveltekit', - }, - }); - - // eslint-disable-next-line deprecation/deprecation - expect(returnedTransaction?.startChild).toHaveBeenCalledWith({ - op: 'ui.sveltekit.routing', - origin: 'auto.ui.sveltekit', - name: 'SvelteKit Route Change', - }); - - // eslint-disable-next-line deprecation/deprecation - expect(returnedTransaction?.setTag).toHaveBeenCalledWith('from', '/users/[id]'); - }); - - it('falls back to `window.location.pathname` to determine the raw origin', () => { - // eslint-disable-next-line deprecation/deprecation - svelteKitRoutingInstrumentation(mockedStartTransaction, false, true); - - // window.location.pathame is "/" in tests - - navigating.set({ - to: { route: {}, url: { pathname: '/' } }, - }); - - expect(mockedStartTransaction).toHaveBeenCalledTimes(0); - }); - }); -}); diff --git a/packages/sveltekit/test/client/sdk.test.ts b/packages/sveltekit/test/client/sdk.test.ts index 9e969c08504d..162ccd72852d 100644 --- a/packages/sveltekit/test/client/sdk.test.ts +++ b/packages/sveltekit/test/client/sdk.test.ts @@ -1,17 +1,9 @@ import type { BrowserClient } from '@sentry/svelte'; import * as SentrySvelte from '@sentry/svelte'; -import { - SDK_VERSION, - browserTracingIntegration, - getClient, - getCurrentScope, - getGlobalScope, - getIsolationScope, -} from '@sentry/svelte'; +import { SDK_VERSION, getClient, getCurrentScope, getGlobalScope, getIsolationScope } from '@sentry/svelte'; import { vi } from 'vitest'; -import { BrowserTracing, init } from '../../src/client'; -import { svelteKitRoutingInstrumentation } from '../../src/client/router'; +import { init } from '../../src/client'; const svelteInit = vi.spyOn(SentrySvelte, 'init'); @@ -61,7 +53,7 @@ describe('Sentry client SDK', () => { ['tracesSampleRate', { tracesSampleRate: 0 }], ['tracesSampler', { tracesSampler: () => 1.0 }], ['enableTracing', { enableTracing: true }], - ])('adds the BrowserTracing integration if tracing is enabled via %s', (_, tracingOptions) => { + ])('adds a browserTracingIntegration if tracing is enabled via %s', (_, tracingOptions) => { init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', ...tracingOptions, @@ -74,7 +66,7 @@ describe('Sentry client SDK', () => { it.each([ ['enableTracing', { enableTracing: false }], ['no tracing option set', {}], - ])("doesn't add the BrowserTracing integration if tracing is disabled via %s", (_, tracingOptions) => { + ])("doesn't add a browserTracingIntegration integration if tracing is disabled via %s", (_, tracingOptions) => { init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', ...tracingOptions, @@ -84,7 +76,7 @@ describe('Sentry client SDK', () => { expect(browserTracing).toBeUndefined(); }); - it("doesn't add the BrowserTracing integration if `__SENTRY_TRACING__` is set to false", () => { + it("doesn't add a browserTracingIntegration if `__SENTRY_TRACING__` is set to false", () => { // This is the closest we can get to unit-testing the `__SENTRY_TRACING__` tree-shaking guard // IRL, the code to add the integration would most likely be removed by the bundler. @@ -100,49 +92,6 @@ describe('Sentry client SDK', () => { delete globalThis.__SENTRY_TRACING__; }); - - it('Merges a user-provided BrowserTracing integration with the automatically added one', () => { - init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - // eslint-disable-next-line deprecation/deprecation - integrations: [new BrowserTracing({ finalTimeout: 10 })], - enableTracing: true, - }); - - // eslint-disable-next-line deprecation/deprecation - const browserTracing = getClient()?.getIntegrationByName('BrowserTracing') as BrowserTracing; - const options = browserTracing.options; - - expect(browserTracing).toBeDefined(); - - // This shows that the user-configured options are still here - expect(options.finalTimeout).toEqual(10); - - // But we force the routing instrumentation to be ours - // eslint-disable-next-line deprecation/deprecation - expect(options.routingInstrumentation).toEqual(svelteKitRoutingInstrumentation); - }); - - it('Merges a user-provided browserTracingIntegration with the automatically added one', () => { - init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - integrations: [browserTracingIntegration({ finalTimeout: 10 })], - enableTracing: true, - }); - - // eslint-disable-next-line deprecation/deprecation - const browserTracing = getClient()?.getIntegrationByName('BrowserTracing') as BrowserTracing; - const options = browserTracing.options; - - expect(browserTracing).toBeDefined(); - - // This shows that the user-configured options are still here - expect(options.finalTimeout).toEqual(10); - - // But we force the routing instrumentation to be ours - // eslint-disable-next-line deprecation/deprecation - expect(options.routingInstrumentation).toEqual(svelteKitRoutingInstrumentation); - }); }); }); }); diff --git a/packages/tracing-internal/src/browser/browserTracingIntegration.ts b/packages/tracing-internal/src/browser/browserTracingIntegration.ts index 02ef63d13aa7..fa0b7d514358 100644 --- a/packages/tracing-internal/src/browser/browserTracingIntegration.ts +++ b/packages/tracing-internal/src/browser/browserTracingIntegration.ts @@ -379,15 +379,12 @@ export const browserTracingIntegration = ((_options: Partial { expect(spanIsSampled(span!)).toBe(false); }); + it("doesn't create a pageload span when instrumentPageLoad is false", () => { + const client = new TestClient( + getDefaultClientOptions({ + integrations: [browserTracingIntegration({ instrumentPageLoad: false })], + }), + ); + setCurrentClient(client); + client.init(); + + const span = getActiveSpan(); + expect(span).not.toBeDefined(); + }); + it('works with tracing enabled but unsampled', () => { const client = new TestClient( getDefaultClientOptions({ @@ -181,6 +201,75 @@ describe('browserTracingIntegration', () => { }); }); + it('extracts window.location/self.location for sampling context in pageload transactions', () => { + // this is what is used to get the span name - JSDOM does not update this on it's own! + const dom = new JSDOM(undefined, { url: 'https://example.com/test' }); + Object.defineProperty(global, 'location', { value: dom.window.document.location, writable: true }); + + const tracesSampler = jest.fn(); + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration()], + tracesSampler, + }), + ); + setCurrentClient(client); + client.init(); + + expect(tracesSampler).toHaveBeenCalledWith( + expect.objectContaining({ + location: dom.window.document.location, + }), + ); + }); + + it('extracts window.location/self.location for sampling context in navigation transactions', () => { + const tracesSampler = jest.fn(); + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration({ instrumentPageLoad: false })], + tracesSampler, + }), + ); + setCurrentClient(client); + client.init(); + + // this is what is used to get the span name - JSDOM does not update this on it's own! + const dom = new JSDOM(undefined, { url: 'https://example.com/test' }); + Object.defineProperty(global, 'location', { value: dom.window.document.location, writable: true }); + + WINDOW.history.pushState({}, '', '/test'); + + expect(tracesSampler).toHaveBeenCalledWith( + expect.objectContaining({ + location: dom.window.document.location, + }), + ); + }); + + it("trims pageload transactions to the max duration of the transaction's children", () => { + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration()], + }), + ); + + setCurrentClient(client); + client.init(); + + const pageloadSpan = getActiveSpan(); + const childSpan = startInactiveSpan({ name: 'pageload-child' }); + const timestamp = timestampInSeconds(); + + childSpan?.end(timestamp); + pageloadSpan?.end(timestamp + 12345); + + expect(spanToJSON(pageloadSpan!).timestamp).toBe(timestamp); + }); + describe('startBrowserTracingPageLoadSpan', () => { it('works without integration setup', () => { const client = new TestClient( @@ -275,6 +364,87 @@ describe('browserTracingIntegration', () => { trace_id: expect.any(String), }); }); + + it('calls before beforeStartSpan', () => { + const mockBeforeStartSpan = jest.fn((options: StartSpanOptions) => options); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 0, + integrations: [ + browserTracingIntegration({ instrumentPageLoad: false, beforeStartSpan: mockBeforeStartSpan }), + ], + }), + ); + setCurrentClient(client); + client.init(); + + startBrowserTracingPageLoadSpan(client, { name: 'test span' }); + + expect(mockBeforeStartSpan).toHaveBeenCalledWith( + expect.objectContaining({ + name: 'test span', + op: 'pageload', + }), + ); + }); + + it('uses options overridden with beforeStartSpan', () => { + const mockBeforeStartSpan = jest.fn((options: StartSpanOptions) => ({ + ...options, + op: 'test op', + })); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 0, + integrations: [ + browserTracingIntegration({ + instrumentPageLoad: false, + instrumentNavigation: false, + beforeStartSpan: mockBeforeStartSpan, + }), + ], + }), + ); + setCurrentClient(client); + client.init(); + + startBrowserTracingPageLoadSpan(client, { name: 'test span' }); + + const pageloadSpan = getActiveSpan(); + + expect(spanToJSON(pageloadSpan!).op).toBe('test op'); + }); + }); + + it('sets source to "custom" if name is changed in beforeStartSpan', () => { + const mockBeforeStartSpan = jest.fn((options: StartSpanOptions) => ({ + ...options, + name: 'changed', + })); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 0, + integrations: [ + browserTracingIntegration({ + instrumentPageLoad: false, + instrumentNavigation: false, + beforeStartSpan: mockBeforeStartSpan, + }), + ], + }), + ); + setCurrentClient(client); + client.init(); + + startBrowserTracingPageLoadSpan(client, { name: 'test span' }); + + const pageloadSpan = getActiveSpan(); + + expect(spanToJSON(pageloadSpan!).description).toBe('changed'); + expect(spanToJSON(pageloadSpan!).data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]).toBe('custom'); }); describe('startBrowserTracingNavigationSpan', () => { @@ -371,5 +541,317 @@ describe('browserTracingIntegration', () => { trace_id: expect.any(String), }); }); + + it('calls before beforeStartSpan', () => { + const mockBeforeStartSpan = jest.fn((options: StartSpanOptions) => options); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 0, + integrations: [ + browserTracingIntegration({ + instrumentPageLoad: false, + instrumentNavigation: false, + beforeStartSpan: mockBeforeStartSpan, + }), + ], + }), + ); + setCurrentClient(client); + client.init(); + + startBrowserTracingNavigationSpan(client, { name: 'test span' }); + + expect(mockBeforeStartSpan).toHaveBeenCalledWith( + expect.objectContaining({ + name: 'test span', + op: 'navigation', + }), + ); + }); + + it('uses options overridden with beforeStartSpan', () => { + const mockBeforeStartSpan = jest.fn((options: StartSpanOptions) => ({ + ...options, + op: 'test op', + })); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 0, + integrations: [ + browserTracingIntegration({ + instrumentPageLoad: false, + instrumentNavigation: false, + beforeStartSpan: mockBeforeStartSpan, + }), + ], + }), + ); + setCurrentClient(client); + client.init(); + + startBrowserTracingNavigationSpan(client, { name: 'test span' }); + + const navigationSpan = getActiveSpan(); + + expect(spanToJSON(navigationSpan!).op).toBe('test op'); + }); + + it('sets source to "custom" if name is changed in beforeStartSpan', () => { + const mockBeforeStartSpan = jest.fn((options: StartSpanOptions) => ({ + ...options, + name: 'changed', + })); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 0, + integrations: [ + browserTracingIntegration({ + instrumentPageLoad: false, + instrumentNavigation: false, + beforeStartSpan: mockBeforeStartSpan, + }), + ], + }), + ); + setCurrentClient(client); + client.init(); + + startBrowserTracingNavigationSpan(client, { name: 'test span' }); + + const pageloadSpan = getActiveSpan(); + + expect(spanToJSON(pageloadSpan!).description).toBe('changed'); + expect(spanToJSON(pageloadSpan!).data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]).toBe('custom'); + }); + }); + + it('sets transaction context from sentry-trace header for pageload transactions', () => { + const name = 'sentry-trace'; + const content = '126de09502ae4e0fb26c6967190756a4-b6e54397b12a2a0f-1'; + document.head.innerHTML = + `` + ''; + const startIdleTransaction = jest.spyOn(hubExtensions, 'startIdleTransaction'); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration()], + }), + ); + setCurrentClient(client); + client.init(); + + expect(startIdleTransaction).toHaveBeenCalledWith( + expect.any(Object), + expect.objectContaining({ + traceId: '126de09502ae4e0fb26c6967190756a4', + parentSpanId: 'b6e54397b12a2a0f', + parentSampled: true, + metadata: { + dynamicSamplingContext: { release: '2.1.14' }, + }, + }), + expect.any(Number), + expect.any(Number), + expect.any(Boolean), + expect.any(Object), + expect.any(Number), + true, + ); + }); + + describe('using the tag data', () => { + it('uses the tracing data for pageload transactions', () => { + // make sampled false here, so we can see that it's being used rather than the tracesSampleRate-dictated one + document.head.innerHTML = + '' + + ''; + + const client = new TestClient( + getDefaultClientOptions({ + integrations: [browserTracingIntegration()], + }), + ); + setCurrentClient(client); + + // pageload transactions are created as part of the browserTracingIntegration's initialization + client.init(); + + // eslint-disable-next-line deprecation/deprecation + const transaction = getActiveTransaction() as IdleTransaction; + // eslint-disable-next-line deprecation/deprecation + const dynamicSamplingContext = transaction.getDynamicSamplingContext()!; + + expect(transaction).toBeDefined(); + expect(spanToJSON(transaction).op).toBe('pageload'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.traceId).toEqual('12312012123120121231201212312012'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.parentSpanId).toEqual('1121201211212012'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.sampled).toBe(false); + expect(dynamicSamplingContext).toBeDefined(); + expect(dynamicSamplingContext).toStrictEqual({ release: '2.1.14' }); + }); + + it('puts frozen Dynamic Sampling Context on pageload transactions if sentry-trace data and only 3rd party baggage is present', () => { + // make sampled false here, so we can see that it's being used rather than the tracesSampleRate-dictated one + document.head.innerHTML = + '' + + ''; + + const client = new TestClient( + getDefaultClientOptions({ + integrations: [browserTracingIntegration()], + }), + ); + setCurrentClient(client); + + // pageload transactions are created as part of the browserTracingIntegration's initialization + client.init(); + + // eslint-disable-next-line deprecation/deprecation + const transaction = getActiveTransaction() as IdleTransaction; + // eslint-disable-next-line deprecation/deprecation + const dynamicSamplingContext = transaction.getDynamicSamplingContext()!; + + expect(transaction).toBeDefined(); + expect(spanToJSON(transaction).op).toBe('pageload'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.traceId).toEqual('12312012123120121231201212312012'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.parentSpanId).toEqual('1121201211212012'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.sampled).toBe(false); + expect(dynamicSamplingContext).toStrictEqual({}); + }); + + it('ignores the meta tag data for navigation transactions', () => { + document.head.innerHTML = + '' + + ''; + + const client = new TestClient( + getDefaultClientOptions({ + integrations: [browserTracingIntegration({ instrumentPageLoad: false })], + }), + ); + setCurrentClient(client); + + // pageload transactions are created as part of the browserTracingIntegration's initialization + client.init(); + + // this is what is used to get the span name - JSDOM does not update this on it's own! + const dom = new JSDOM(undefined, { url: 'https://example.com/navigation-test' }); + Object.defineProperty(global, 'location', { value: dom.window.document.location, writable: true }); + + WINDOW.history.pushState({}, '', '/navigation-test'); + + // eslint-disable-next-line deprecation/deprecation + const transaction = getActiveTransaction() as IdleTransaction; + // eslint-disable-next-line deprecation/deprecation + const dynamicSamplingContext = transaction.getDynamicSamplingContext()!; + + expect(transaction).toBeDefined(); + expect(spanToJSON(transaction).op).toBe('navigation'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.traceId).not.toEqual('12312012123120121231201212312012'); + // eslint-disable-next-line deprecation/deprecation + expect(transaction.parentSpanId).toBeUndefined(); + expect(dynamicSamplingContext).toMatchObject({ + trace_id: expect.not.stringMatching('12312012123120121231201212312012'), + }); + transaction.end(); + }); + }); + + describe('idleTimeout', () => { + it('is created by default', () => { + jest.useFakeTimers(); + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration()], + }), + ); + setCurrentClient(client); + client.init(); + + const mockFinish = jest.fn(); + // eslint-disable-next-line deprecation/deprecation + const transaction = getActiveTransaction() as IdleTransaction; + transaction.sendAutoFinishSignal(); + transaction.end = mockFinish; + + // eslint-disable-next-line deprecation/deprecation + const span = transaction.startChild(); // activities = 1 + span.end(); // activities = 0 + + expect(mockFinish).toHaveBeenCalledTimes(0); + jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + expect(mockFinish).toHaveBeenCalledTimes(1); + }); + + it('can be a custom value', () => { + jest.useFakeTimers(); + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration({ idleTimeout: 2000 })], + }), + ); + setCurrentClient(client); + client.init(); + + const mockFinish = jest.fn(); + // eslint-disable-next-line deprecation/deprecation + const transaction = getActiveTransaction() as IdleTransaction; + transaction.sendAutoFinishSignal(); + transaction.end = mockFinish; + + // eslint-disable-next-line deprecation/deprecation + const span = transaction.startChild(); // activities = 1 + span.end(); // activities = 0 + + expect(mockFinish).toHaveBeenCalledTimes(0); + jest.advanceTimersByTime(2000); + expect(mockFinish).toHaveBeenCalledTimes(1); + }); + }); + + // TODO(lforst): I cannot manage to get this test to pass. + /* + it('heartbeatInterval can be a custom value', () => { + jest.useFakeTimers(); + + const interval = 200; + + const client = new TestClient( + getDefaultClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration({ heartbeatInterval: interval })], + }), + ); + + setCurrentClient(client); + client.init(); + + const mockFinish = jest.fn(); + // eslint-disable-next-line deprecation/deprecation + const transaction = getActiveTransaction() as IdleTransaction; + transaction.sendAutoFinishSignal(); + transaction.end = mockFinish; + + const span = startInactiveSpan({ name: 'child-span' }); // activities = 1 + span!.end(); // activities = 0 + + expect(mockFinish).toHaveBeenCalledTimes(0); + jest.advanceTimersByTime(interval * 3); + expect(mockFinish).toHaveBeenCalledTimes(1); }); + */ }); diff --git a/packages/tracing-internal/test/browser/browsertracing.test.ts b/packages/tracing-internal/test/browser/browsertracing.test.ts deleted file mode 100644 index e24e4d166099..000000000000 --- a/packages/tracing-internal/test/browser/browsertracing.test.ts +++ /dev/null @@ -1,589 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import { - SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, - TRACING_DEFAULTS, - getActiveTransaction, - getClient, - getCurrentHub, - setCurrentClient, - spanToJSON, -} from '@sentry/core'; -import * as hubExtensions from '@sentry/core'; -import type { BaseTransportOptions, ClientOptions, DsnComponents, HandlerDataHistory } from '@sentry/types'; -import { JSDOM } from 'jsdom'; - -import type { IdleTransaction } from '@sentry/core'; -import { timestampInSeconds } from '@sentry/utils'; -import type { BrowserTracingOptions } from '../../src/browser/browsertracing'; -import { BrowserTracing, getMetaContent } from '../../src/browser/browsertracing'; -import { defaultRequestInstrumentationOptions } from '../../src/browser/request'; -import { instrumentRoutingWithDefaults } from '../../src/browser/router'; -import { WINDOW } from '../../src/browser/types'; -import { TestClient, getDefaultClientOptions } from '../utils/TestClient'; - -let mockChangeHistory: (data: HandlerDataHistory) => void = () => {}; - -jest.mock('@sentry/utils', () => { - const actual = jest.requireActual('@sentry/utils'); - return { - ...actual, - - addHistoryInstrumentationHandler: (callback: (data: HandlerDataHistory) => void): void => { - mockChangeHistory = callback; - }, - }; -}); - -const mockStartTrackingWebVitals = jest.fn().mockReturnValue(() => () => {}); - -jest.mock('../../src/browser/metrics', () => ({ - addPerformanceEntries: jest.fn(), - startTrackingInteractions: jest.fn(), - startTrackingLongTasks: jest.fn(), - startTrackingWebVitals: () => mockStartTrackingWebVitals(), -})); - -const instrumentOutgoingRequestsMock = jest.fn(); -jest.mock('./../../src/browser/request', () => { - const actual = jest.requireActual('./../../src/browser/request'); - return { - ...actual, - instrumentOutgoingRequests: (options: Partial) => instrumentOutgoingRequestsMock(options), - }; -}); - -beforeAll(() => { - const dom = new JSDOM(); - // @ts-expect-error need to override global document - WINDOW.document = dom.window.document; - // @ts-expect-error need to override global document - WINDOW.window = dom.window; - WINDOW.location = dom.window.location; -}); - -describe('BrowserTracing', () => { - beforeEach(() => { - jest.useFakeTimers(); - const options = getDefaultClientOptions({ tracesSampleRate: 1 }); - const client = new TestClient(options); - setCurrentClient(client); - client.init(); - document.head.innerHTML = ''; - - mockStartTrackingWebVitals.mockClear(); - }); - - afterEach(() => { - const activeTransaction = getActiveTransaction(); - if (activeTransaction) { - // Should unset off of scope. - activeTransaction.end(); - } - }); - - function createBrowserTracing(setup?: boolean, _options?: Partial): BrowserTracing { - const instance = new BrowserTracing(_options); - if (setup) { - const processor = () => undefined; - instance.setupOnce(processor, () => getCurrentHub() as hubExtensions.Hub); - } - - return instance; - } - - // These are important enough to check with a test as incorrect defaults could - // break a lot of users' configurations. - it('is created with default settings', () => { - const browserTracing = createBrowserTracing(); - - expect(browserTracing.options).toEqual({ - enableLongTask: true, - _experiments: {}, - ...TRACING_DEFAULTS, - markBackgroundTransactions: true, - routingInstrumentation: instrumentRoutingWithDefaults, - startTransactionOnLocationChange: true, - startTransactionOnPageLoad: true, - ...defaultRequestInstrumentationOptions, - }); - }); - - it('is allows to disable enableLongTask via _experiments', () => { - const browserTracing = createBrowserTracing(false, { - _experiments: { - enableLongTask: false, - }, - }); - - expect(browserTracing.options).toEqual({ - enableLongTask: false, - ...TRACING_DEFAULTS, - markBackgroundTransactions: true, - routingInstrumentation: instrumentRoutingWithDefaults, - startTransactionOnLocationChange: true, - startTransactionOnPageLoad: true, - ...defaultRequestInstrumentationOptions, - _experiments: { - enableLongTask: false, - }, - }); - }); - - it('is allows to disable enableLongTask', () => { - const browserTracing = createBrowserTracing(false, { - enableLongTask: false, - }); - - expect(browserTracing.options).toEqual({ - enableLongTask: false, - _experiments: {}, - ...TRACING_DEFAULTS, - markBackgroundTransactions: true, - routingInstrumentation: instrumentRoutingWithDefaults, - startTransactionOnLocationChange: true, - startTransactionOnPageLoad: true, - ...defaultRequestInstrumentationOptions, - }); - }); - - /** - * All of these tests under `describe('route transaction')` are tested with - * `browserTracing.options = { routingInstrumentation: customInstrumentRouting }`, - * so that we can show this functionality works independent of the default routing integration. - */ - describe('route transaction', () => { - const customInstrumentRouting = (customStartTransaction: (obj: any) => void) => { - customStartTransaction({ name: 'a/path', op: 'pageload' }); - }; - - it('_experiements calls onStartRouteTransaction on route instrumentation', () => { - const onStartTranscation = jest.fn(); - createBrowserTracing(true, { - _experiments: { - onStartRouteTransaction: onStartTranscation, - }, - }); - - expect(onStartTranscation).toHaveBeenCalledTimes(1); - }); - - it('calls custom routing instrumenation', () => { - createBrowserTracing(true, { - routingInstrumentation: customInstrumentRouting, - }); - - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).toBeDefined(); - expect(spanToJSON(transaction).description).toBe('a/path'); - expect(spanToJSON(transaction).op).toBe('pageload'); - }); - - it('trims all transactions', () => { - createBrowserTracing(true, { - routingInstrumentation: customInstrumentRouting, - }); - - const transaction = getActiveTransaction() as IdleTransaction; - const span = transaction.startChild(); - - const timestamp = timestampInSeconds(); - span.end(timestamp); - transaction.end(timestamp + 12345); - - expect(spanToJSON(transaction).timestamp).toBe(timestamp); - }); - - describe('beforeNavigate', () => { - it('is called on transaction creation', () => { - const mockBeforeNavigation = jest.fn().mockReturnValue({ name: 'here/is/my/path' }); - createBrowserTracing(true, { - beforeNavigate: mockBeforeNavigation, - routingInstrumentation: customInstrumentRouting, - }); - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).toBeDefined(); - - expect(mockBeforeNavigation).toHaveBeenCalledTimes(1); - }); - - it('creates a transaction with sampled = false if beforeNavigate returns undefined', () => { - const mockBeforeNavigation = jest.fn().mockReturnValue(undefined); - createBrowserTracing(true, { - beforeNavigate: mockBeforeNavigation, - routingInstrumentation: customInstrumentRouting, - }); - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction.sampled).toBe(false); - - expect(mockBeforeNavigation).toHaveBeenCalledTimes(1); - }); - - it('can override default context values', () => { - const mockBeforeNavigation = jest.fn(ctx => ({ - ...ctx, - op: 'not-pageload', - })); - createBrowserTracing(true, { - beforeNavigate: mockBeforeNavigation, - routingInstrumentation: customInstrumentRouting, - }); - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).toBeDefined(); - expect(spanToJSON(transaction).op).toBe('not-pageload'); - - expect(mockBeforeNavigation).toHaveBeenCalledTimes(1); - }); - - it("sets transaction name source to `'custom'` if name is changed", () => { - const mockBeforeNavigation = jest.fn(ctx => ({ - ...ctx, - name: 'newName', - })); - createBrowserTracing(true, { - beforeNavigate: mockBeforeNavigation, - routingInstrumentation: customInstrumentRouting, - }); - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).toBeDefined(); - expect(spanToJSON(transaction).description).toBe('newName'); - expect(spanToJSON(transaction).data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]).toBe('custom'); - - expect(mockBeforeNavigation).toHaveBeenCalledTimes(1); - }); - - it('sets transaction name source to default `url` if name is not changed', () => { - const mockBeforeNavigation = jest.fn(ctx => ({ - ...ctx, - })); - createBrowserTracing(true, { - beforeNavigate: mockBeforeNavigation, - routingInstrumentation: (customStartTransaction: (obj: any) => void) => { - customStartTransaction({ - name: 'a/path', - op: 'pageload', - attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url' }, - }); - }, - }); - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).toBeDefined(); - expect(spanToJSON(transaction).description).toBe('a/path'); - expect(spanToJSON(transaction).data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]).toBe('url'); - - expect(mockBeforeNavigation).toHaveBeenCalledTimes(1); - }); - }); - - it('sets transaction context from sentry-trace header', () => { - const name = 'sentry-trace'; - const content = '126de09502ae4e0fb26c6967190756a4-b6e54397b12a2a0f-1'; - document.head.innerHTML = - `` + ''; - const startIdleTransaction = jest.spyOn(hubExtensions, 'startIdleTransaction'); - - createBrowserTracing(true, { routingInstrumentation: customInstrumentRouting }); - - expect(startIdleTransaction).toHaveBeenCalledWith( - expect.any(Object), - expect.objectContaining({ - traceId: '126de09502ae4e0fb26c6967190756a4', - parentSpanId: 'b6e54397b12a2a0f', - parentSampled: true, - metadata: { - dynamicSamplingContext: { release: '2.1.14' }, - }, - }), - expect.any(Number), - expect.any(Number), - expect.any(Boolean), - expect.any(Object), - expect.any(Number), - true, - ); - }); - - describe('idleTimeout', () => { - it('is created by default', () => { - createBrowserTracing(true, { routingInstrumentation: customInstrumentRouting }); - const mockFinish = jest.fn(); - const transaction = getActiveTransaction() as IdleTransaction; - transaction.sendAutoFinishSignal(); - transaction.end = mockFinish; - - const span = transaction.startChild(); // activities = 1 - span.end(); // activities = 0 - - expect(mockFinish).toHaveBeenCalledTimes(0); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); - expect(mockFinish).toHaveBeenCalledTimes(1); - }); - - it('can be a custom value', () => { - createBrowserTracing(true, { idleTimeout: 2000, routingInstrumentation: customInstrumentRouting }); - const mockFinish = jest.fn(); - const transaction = getActiveTransaction() as IdleTransaction; - transaction.sendAutoFinishSignal(); - transaction.end = mockFinish; - - const span = transaction.startChild(); // activities = 1 - span.end(); // activities = 0 - - expect(mockFinish).toHaveBeenCalledTimes(0); - jest.advanceTimersByTime(2000); - expect(mockFinish).toHaveBeenCalledTimes(1); - }); - - it('calls `_collectWebVitals` if enabled', () => { - createBrowserTracing(true, { routingInstrumentation: customInstrumentRouting }); - const transaction = getActiveTransaction() as IdleTransaction; - - const span = transaction.startChild(); // activities = 1 - span.end(); // activities = 0 - - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); - expect(mockStartTrackingWebVitals).toHaveBeenCalledTimes(1); - }); - }); - - describe('heartbeatInterval', () => { - it('can be a custom value', () => { - const interval = 200; - createBrowserTracing(true, { heartbeatInterval: interval, routingInstrumentation: customInstrumentRouting }); - const mockFinish = jest.fn(); - const transaction = getActiveTransaction() as IdleTransaction; - transaction.sendAutoFinishSignal(); - transaction.end = mockFinish; - - const span = transaction.startChild(); // activities = 1 - span.end(); // activities = 0 - - expect(mockFinish).toHaveBeenCalledTimes(0); - jest.advanceTimersByTime(interval * 3); - expect(mockFinish).toHaveBeenCalledTimes(1); - }); - }); - }); - - // Integration tests for the default routing instrumentation - describe('default routing instrumentation', () => { - describe('pageload transaction', () => { - it('is created on setup on scope', () => { - createBrowserTracing(true); - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).toBeDefined(); - - expect(spanToJSON(transaction).op).toBe('pageload'); - }); - - it('is not created if the option is false', () => { - createBrowserTracing(true, { startTransactionOnPageLoad: false }); - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).not.toBeDefined(); - }); - }); - - describe('navigation transaction', () => { - beforeEach(() => { - mockChangeHistory = () => undefined; - }); - - it('it is not created automatically at startup', () => { - createBrowserTracing(true); - jest.runAllTimers(); - - const transaction = getActiveTransaction() as IdleTransaction; - expect(transaction).not.toBeDefined(); - }); - - it('is created on location change', () => { - createBrowserTracing(true); - const transaction1 = getActiveTransaction() as IdleTransaction; - expect(spanToJSON(transaction1).op).toBe('pageload'); - expect(spanToJSON(transaction1).timestamp).not.toBeDefined(); - - mockChangeHistory({ to: 'here', from: 'there' }); - const transaction2 = getActiveTransaction() as IdleTransaction; - expect(spanToJSON(transaction2).op).toBe('navigation'); - - expect(spanToJSON(transaction1).timestamp).toBeDefined(); - }); - - it('is not created if startTransactionOnLocationChange is false', () => { - createBrowserTracing(true, { startTransactionOnLocationChange: false }); - const transaction1 = getActiveTransaction() as IdleTransaction; - expect(spanToJSON(transaction1).op).toBe('pageload'); - expect(spanToJSON(transaction1).timestamp).not.toBeDefined(); - - mockChangeHistory({ to: 'here', from: 'there' }); - const transaction2 = getActiveTransaction() as IdleTransaction; - expect(spanToJSON(transaction2).op).toBe('pageload'); - }); - }); - }); - - describe('sentry-trace and baggage elements', () => { - describe('getMetaContent', () => { - it('finds the specified tag and extracts the value', () => { - const name = 'sentry-trace'; - const content = '126de09502ae4e0fb26c6967190756a4-b6e54397b12a2a0f-1'; - document.head.innerHTML = ``; - - const metaTagValue = getMetaContent(name); - expect(metaTagValue).toBe(content); - }); - - it("doesn't return meta tags other than the one specified", () => { - document.head.innerHTML = ''; - - const metaTagValue = getMetaContent('dogpark'); - expect(metaTagValue).toBe(undefined); - }); - - it('can pick the correct tag out of multiple options', () => { - const name = 'sentry-trace'; - const content = '126de09502ae4e0fb26c6967190756a4-b6e54397b12a2a0f-1'; - const sentryTraceMeta = ``; - const otherMeta = ''; - document.head.innerHTML = `${sentryTraceMeta} ${otherMeta}`; - - const metaTagValue = getMetaContent(name); - expect(metaTagValue).toBe(content); - }); - }); - - describe('using the tag data', () => { - beforeEach(() => { - getClient()!.getOptions = () => { - return { - release: '1.0.0', - environment: 'production', - } as ClientOptions; - }; - - getClient()!.getDsn = () => { - return { - publicKey: 'pubKey', - } as DsnComponents; - }; - }); - - it('uses the tracing data for pageload transactions', () => { - // make sampled false here, so we can see that it's being used rather than the tracesSampleRate-dictated one - document.head.innerHTML = - '' + - ''; - - // pageload transactions are created as part of the BrowserTracing integration's initialization - createBrowserTracing(true); - const transaction = getActiveTransaction() as IdleTransaction; - const dynamicSamplingContext = transaction.getDynamicSamplingContext()!; - - expect(transaction).toBeDefined(); - expect(spanToJSON(transaction).op).toBe('pageload'); - expect(transaction.traceId).toEqual('12312012123120121231201212312012'); - expect(transaction.parentSpanId).toEqual('1121201211212012'); - expect(transaction.sampled).toBe(false); - expect(dynamicSamplingContext).toBeDefined(); - expect(dynamicSamplingContext).toStrictEqual({ release: '2.1.14' }); - }); - - it('puts frozen Dynamic Sampling Context on pageload transactions if sentry-trace data and only 3rd party baggage is present', () => { - // make sampled false here, so we can see that it's being used rather than the tracesSampleRate-dictated one - document.head.innerHTML = - '' + - ''; - - // pageload transactions are created as part of the BrowserTracing integration's initialization - createBrowserTracing(true); - const transaction = getActiveTransaction() as IdleTransaction; - const dynamicSamplingContext = transaction.getDynamicSamplingContext()!; - - expect(transaction).toBeDefined(); - expect(spanToJSON(transaction).op).toBe('pageload'); - expect(transaction.traceId).toEqual('12312012123120121231201212312012'); - expect(transaction.parentSpanId).toEqual('1121201211212012'); - expect(transaction.sampled).toBe(false); - expect(dynamicSamplingContext).toStrictEqual({}); - }); - - it('ignores the meta tag data for navigation transactions', () => { - mockChangeHistory = () => undefined; - document.head.innerHTML = - '' + - ''; - - createBrowserTracing(true); - - mockChangeHistory({ to: 'here', from: 'there' }); - const transaction = getActiveTransaction() as IdleTransaction; - const dynamicSamplingContext = transaction.getDynamicSamplingContext()!; - - expect(transaction).toBeDefined(); - expect(spanToJSON(transaction).op).toBe('navigation'); - expect(transaction.traceId).not.toEqual('12312012123120121231201212312012'); - expect(transaction.parentSpanId).toBeUndefined(); - expect(dynamicSamplingContext).toStrictEqual({ - release: '1.0.0', - environment: 'production', - public_key: 'pubKey', - sampled: 'false', - trace_id: expect.not.stringMatching('12312012123120121231201212312012'), - }); - }); - }); - }); - - describe('sampling', () => { - const dogParkLocation = { - hash: '#next-to-the-fountain', - host: 'the.dog.park', - hostname: 'the.dog.park', - href: 'mutualsniffing://the.dog.park/by/the/trees/?chase=me&please=thankyou#next-to-the-fountain', - origin: "'mutualsniffing://the.dog.park", - pathname: '/by/the/trees/', - port: '', - protocol: 'mutualsniffing:', - search: '?chase=me&please=thankyou', - }; - - it('extracts window.location/self.location for sampling context in pageload transactions', () => { - WINDOW.location = dogParkLocation as any; - - const tracesSampler = jest.fn(); - const options = getDefaultClientOptions({ tracesSampler }); - const client = new TestClient(options); - setCurrentClient(client); - client.init(); - // setting up the BrowserTracing integration automatically starts a pageload transaction - createBrowserTracing(true); - - expect(tracesSampler).toHaveBeenCalledWith( - expect.objectContaining({ - location: dogParkLocation, - transactionContext: expect.objectContaining({ op: 'pageload' }), - }), - ); - }); - - it('extracts window.location/self.location for sampling context in navigation transactions', () => { - WINDOW.location = dogParkLocation as any; - - const tracesSampler = jest.fn(); - const options = getDefaultClientOptions({ tracesSampler }); - const client = new TestClient(options); - setCurrentClient(client); - client.init(); - // setting up the BrowserTracing integration normally automatically starts a pageload transaction, but that's not - // what we're testing here - createBrowserTracing(true, { startTransactionOnPageLoad: false }); - - mockChangeHistory({ to: 'here', from: 'there' }); - expect(tracesSampler).toHaveBeenCalledWith( - expect.objectContaining({ - location: dogParkLocation, - transactionContext: expect.objectContaining({ op: 'navigation' }), - }), - ); - }); - }); -}); diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index 7c6b562a2f73..4d41b0f216bd 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -245,12 +245,12 @@ export interface Client { ): void; /** - * A hook for BrowserTracing to trigger a span start for a page load. + * A hook for the browser tracing integrations to trigger a span start for a page load. */ on(hook: 'startPageLoadSpan', callback: (options: StartSpanOptions) => void): void; /** - * A hook for BrowserTracing to trigger a span for a navigation. + * A hook for browser tracing integrations to trigger a span for a navigation. */ on(hook: 'startNavigationSpan', callback: (options: StartSpanOptions) => void): void; @@ -326,12 +326,12 @@ export interface Client { emit(hook: 'beforeSendFeedback', feedback: FeedbackEvent, options?: { includeReplay?: boolean }): void; /** - * Emit a hook event for BrowserTracing to trigger a span start for a page load. + * Emit a hook event for browser tracing integrations to trigger a span start for a page load. */ emit(hook: 'startPageLoadSpan', options: StartSpanOptions): void; /** - * Emit a hook event for BrowserTracing to trigger a span for a navigation. + * Emit a hook event for browser tracing integrations to trigger a span for a navigation. */ emit(hook: 'startNavigationSpan', options: StartSpanOptions): void; diff --git a/packages/vue/src/browserTracingIntegration.ts b/packages/vue/src/browserTracingIntegration.ts index d78bdd992d6b..e3d178628724 100644 --- a/packages/vue/src/browserTracingIntegration.ts +++ b/packages/vue/src/browserTracingIntegration.ts @@ -44,7 +44,7 @@ type VueBrowserTracingIntegrationOptions = Parameters