diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/entry-client.tsx b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/entry-client.tsx index d9900ed5689d..11087fbb5918 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/entry-client.tsx +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/entry-client.tsx @@ -4,7 +4,6 @@ import { solidRouterBrowserTracingIntegration } from '@sentry/solidstart/solidro import { StartClient, mount } from '@solidjs/start/client'; Sentry.init({ - traceLifecycle: 'static', // We can't use env variables here, seems like they are stripped // out in production builds. dsn: 'https://public@dsn.ingest.sentry.io/1337', diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts index d89f2566f8be..3dd5d8933b7b 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts @@ -1,7 +1,6 @@ import * as Sentry from '@sentry/solidstart'; Sentry.init({ - traceLifecycle: 'static', dsn: process.env.E2E_TEST_DSN, environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.client.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.client.test.ts index 5b23badf4e6b..3d7b254e101a 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.client.test.ts @@ -1,119 +1,81 @@ import { expect, test } from '@playwright/test'; -import { waitForTransaction } from '@sentry-internal/test-utils'; +import { getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils'; -test('sends a pageload transaction', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-dynamic-import', async transactionEvent => { - return transactionEvent?.transaction === '/' && transactionEvent.contexts?.trace?.op === 'pageload'; +test('sends a pageload span', async ({ page }) => { + const spanPromise = waitForStreamedSpan('solidstart-dynamic-import', span => { + return span.name === '/' && getSpanOp(span) === 'pageload' && span.is_segment; }); await page.goto('/'); - const pageloadTransaction = await transactionPromise; + const pageloadSpan = await spanPromise; - expect(pageloadTransaction).toMatchObject({ - contexts: { - trace: { - op: 'pageload', - origin: 'auto.pageload.browser', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/', - 'url.path': '/', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/), - }, - }, - }, - transaction: '/', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(pageloadSpan)).toBe('pageload'); + expect(pageloadSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.pageload.browser', type: 'string' }, + 'sentry.op': { value: 'pageload', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/', type: 'string' }, + 'url.path': { value: '/', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/$/), type: 'string' }, }); }); -test('sends a navigation transaction with parametrized route', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-dynamic-import', async transactionEvent => { - return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation'; +test('sends a navigation span with parametrized route', async ({ page }) => { + const spanPromise = waitForStreamedSpan('solidstart-dynamic-import', span => { + return span.name === '/users/:id' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goto(`/`); await page.locator('#navLink').click(); - const navigationTransaction = await transactionPromise; + const navigationSpan = await spanPromise; - expect(navigationTransaction).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/users/:id', - 'url.path': '/users/5', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/), - }, - }, - }, - transaction: '/users/:id', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(navigationSpan)).toBe('navigation'); + expect(navigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/users/:id', type: 'string' }, + 'url.path': { value: '/users/5', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/), type: 'string' }, }); }); -test('updates the transaction when using the back button', async ({ page }) => { +test('updates the span when using the back button', async ({ page }) => { // Solid Router sends a `-1` navigation when using the back button. // The sentry solidRouterBrowserTracingIntegration tries to update such - // transactions with the proper name once the `useLocation` hook triggers. - const navigationTxnPromise = waitForTransaction('solidstart-dynamic-import', async transactionEvent => { - return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation'; + // spans with the proper name once the `useLocation` hook triggers. + const navigationSpanPromise = waitForStreamedSpan('solidstart-dynamic-import', span => { + return span.name === '/users/:id' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goto(`/back-navigation`); await page.locator('#navLink').click(); - const navigationTxn = await navigationTxnPromise; + const navigationSpan = await navigationSpanPromise; - expect(navigationTxn).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/users/:id', - 'url.path': '/users/6', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/), - }, - }, - }, - transaction: '/users/:id', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(navigationSpan)).toBe('navigation'); + expect(navigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/users/:id', type: 'string' }, + 'url.path': { value: '/users/6', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/), type: 'string' }, }); - const backNavigationTxnPromise = waitForTransaction('solidstart-dynamic-import', async transactionEvent => { - return ( - transactionEvent?.transaction === '/back-navigation' && transactionEvent.contexts?.trace?.op === 'navigation' - ); + const backNavigationSpanPromise = waitForStreamedSpan('solidstart-dynamic-import', span => { + return span.name === '/back-navigation' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goBack(); - const backNavigationTxn = await backNavigationTxnPromise; + const backNavigationSpan = await backNavigationSpanPromise; - expect(backNavigationTxn).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/back-navigation', - 'url.path': '/back-navigation', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/), - }, - }, - }, - transaction: '/back-navigation', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(backNavigationSpan)).toBe('navigation'); + expect(backNavigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/back-navigation', type: 'string' }, + 'url.path': { value: '/back-navigation', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/), type: 'string' }, }); }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.server.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.server.test.ts index 6a332efd7d3f..01981e8aa78c 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/tests/performance.server.test.ts @@ -1,49 +1,46 @@ import { expect, test } from '@playwright/test'; -import { waitForTransaction } from '@sentry-internal/test-utils'; -import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/solidstart'; - -test('sends a server action transaction on pageload', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-dynamic-import', transactionEvent => { - return transactionEvent?.transaction === 'GET /users/6'; - }); +import { collectStreamedSpans, getSpanOp } from '@sentry-internal/test-utils'; + +test('sends a server action span on pageload', async ({ page }) => { + const spansPromise = collectStreamedSpans( + 'solidstart-dynamic-import', + spans => + spans.some( + span => + span.is_segment && getSpanOp(span) === 'http.server' && span.attributes['url.path']?.value === '/users/6', + ) && spans.some(span => span.name === 'getPrefecture'), + ); await page.goto('/users/6'); - const transaction = await transactionPromise; - - expect(transaction.spans).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - description: 'getPrefecture', - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart', - }, - }), - ]), - ); -}); + const spans = await spansPromise; + const functionSpan = spans.find(span => span.name === 'getPrefecture'); -test('sends a server action transaction on client navigation', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-dynamic-import', transactionEvent => { - return transactionEvent?.transaction === 'POST getPrefecture'; + expect(functionSpan).toBeDefined(); + expect(functionSpan?.attributes).toMatchObject({ + 'sentry.op': { value: 'function', type: 'string' }, + 'sentry.origin': { value: 'auto.function.solidstart', type: 'string' }, }); +}); + +test('sends a server action span on client navigation', async ({ page }) => { + const spansPromise = collectStreamedSpans( + 'solidstart-dynamic-import', + spans => + spans.some(span => span.is_segment && span.name === 'POST getPrefecture') && + spans.some(span => span.name === 'getPrefecture' && !span.is_segment), + ); await page.goto('/'); await page.locator('#navLink').click(); await page.waitForURL('/users/5'); - const transaction = await transactionPromise; - - expect(transaction.spans).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - description: 'getPrefecture', - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart', - }, - }), - ]), - ); + const spans = await spansPromise; + const functionSpan = spans.find(span => span.name === 'getPrefecture' && !span.is_segment); + + expect(functionSpan).toBeDefined(); + expect(functionSpan?.attributes).toMatchObject({ + 'sentry.op': { value: 'function', type: 'string' }, + 'sentry.origin': { value: 'auto.function.solidstart', type: 'string' }, + }); }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/src/entry-client.tsx b/dev-packages/e2e-tests/test-applications/solidstart-spa/src/entry-client.tsx index d9900ed5689d..11087fbb5918 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/src/entry-client.tsx +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/src/entry-client.tsx @@ -4,7 +4,6 @@ import { solidRouterBrowserTracingIntegration } from '@sentry/solidstart/solidro import { StartClient, mount } from '@solidjs/start/client'; Sentry.init({ - traceLifecycle: 'static', // We can't use env variables here, seems like they are stripped // out in production builds. dsn: 'https://public@dsn.ingest.sentry.io/1337', diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts b/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts index d89f2566f8be..3dd5d8933b7b 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts @@ -1,7 +1,6 @@ import * as Sentry from '@sentry/solidstart'; Sentry.init({ - traceLifecycle: 'static', dsn: process.env.E2E_TEST_DSN, environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.client.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.client.test.ts index feb729f22028..85feba680fac 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.client.test.ts @@ -1,119 +1,81 @@ import { expect, test } from '@playwright/test'; -import { waitForTransaction } from '@sentry-internal/test-utils'; +import { getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils'; -test('sends a pageload transaction', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-spa', async transactionEvent => { - return transactionEvent?.transaction === '/' && transactionEvent.contexts?.trace?.op === 'pageload'; +test('sends a pageload span', async ({ page }) => { + const spanPromise = waitForStreamedSpan('solidstart-spa', span => { + return span.name === '/' && getSpanOp(span) === 'pageload' && span.is_segment; }); await page.goto('/'); - const pageloadTransaction = await transactionPromise; + const pageloadSpan = await spanPromise; - expect(pageloadTransaction).toMatchObject({ - contexts: { - trace: { - op: 'pageload', - origin: 'auto.pageload.browser', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/', - 'url.path': '/', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/), - }, - }, - }, - transaction: '/', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(pageloadSpan)).toBe('pageload'); + expect(pageloadSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.pageload.browser', type: 'string' }, + 'sentry.op': { value: 'pageload', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/', type: 'string' }, + 'url.path': { value: '/', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/$/), type: 'string' }, }); }); -test('sends a navigation transaction with parametrized route', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-spa', async transactionEvent => { - return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation'; +test('sends a navigation span with parametrized route', async ({ page }) => { + const spanPromise = waitForStreamedSpan('solidstart-spa', span => { + return span.name === '/users/:id' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goto(`/`); await page.locator('#navLink').click(); - const navigationTransaction = await transactionPromise; + const navigationSpan = await spanPromise; - expect(navigationTransaction).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/users/:id', - 'url.path': '/users/5', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/), - }, - }, - }, - transaction: '/users/:id', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(navigationSpan)).toBe('navigation'); + expect(navigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/users/:id', type: 'string' }, + 'url.path': { value: '/users/5', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/), type: 'string' }, }); }); -test('updates the transaction when using the back button', async ({ page }) => { +test('updates the span when using the back button', async ({ page }) => { // Solid Router sends a `-1` navigation when using the back button. // The sentry solidRouterBrowserTracingIntegration tries to update such - // transactions with the proper name once the `useLocation` hook triggers. - const navigationTxnPromise = waitForTransaction('solidstart-spa', async transactionEvent => { - return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation'; + // spans with the proper name once the `useLocation` hook triggers. + const navigationSpanPromise = waitForStreamedSpan('solidstart-spa', span => { + return span.name === '/users/:id' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goto(`/back-navigation`); await page.locator('#navLink').click(); - const navigationTxn = await navigationTxnPromise; + const navigationSpan = await navigationSpanPromise; - expect(navigationTxn).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/users/:id', - 'url.path': '/users/6', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/), - }, - }, - }, - transaction: '/users/:id', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(navigationSpan)).toBe('navigation'); + expect(navigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/users/:id', type: 'string' }, + 'url.path': { value: '/users/6', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/), type: 'string' }, }); - const backNavigationTxnPromise = waitForTransaction('solidstart-spa', async transactionEvent => { - return ( - transactionEvent?.transaction === '/back-navigation' && transactionEvent.contexts?.trace?.op === 'navigation' - ); + const backNavigationSpanPromise = waitForStreamedSpan('solidstart-spa', span => { + return span.name === '/back-navigation' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goBack(); - const backNavigationTxn = await backNavigationTxnPromise; + const backNavigationSpan = await backNavigationSpanPromise; - expect(backNavigationTxn).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/back-navigation', - 'url.path': '/back-navigation', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/), - }, - }, - }, - transaction: '/back-navigation', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(backNavigationSpan)).toBe('navigation'); + expect(backNavigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/back-navigation', type: 'string' }, + 'url.path': { value: '/back-navigation', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/), type: 'string' }, }); }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.server.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.server.test.ts index f84e35ed97bb..59e81a6c521c 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/tests/performance.server.test.ts @@ -1,49 +1,44 @@ import { expect, test } from '@playwright/test'; -import { waitForTransaction } from '@sentry-internal/test-utils'; -import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/solidstart'; - -test('sends a server action transaction on pageload', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-spa', transactionEvent => { - return transactionEvent?.transaction === 'POST getPrefecture'; - }); +import { collectStreamedSpans } from '@sentry-internal/test-utils'; + +test('sends a server action span on pageload', async ({ page }) => { + const spansPromise = collectStreamedSpans( + 'solidstart-spa', + spans => + spans.some(span => span.is_segment && span.name === 'POST getPrefecture') && + spans.some(span => span.name === 'getPrefecture' && !span.is_segment), + ); await page.goto('/users/6'); - const transaction = await transactionPromise; - - expect(transaction.spans).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - description: 'getPrefecture', - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart', - }, - }), - ]), - ); -}); + const spans = await spansPromise; + const functionSpan = spans.find(span => span.name === 'getPrefecture' && !span.is_segment); -test('sends a server action transaction on client navigation', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-spa', transactionEvent => { - return transactionEvent?.transaction === 'POST getPrefecture'; + expect(functionSpan).toBeDefined(); + expect(functionSpan?.attributes).toMatchObject({ + 'sentry.op': { value: 'function', type: 'string' }, + 'sentry.origin': { value: 'auto.function.solidstart', type: 'string' }, }); +}); + +test('sends a server action span on client navigation', async ({ page }) => { + const spansPromise = collectStreamedSpans( + 'solidstart-spa', + spans => + spans.some(span => span.is_segment && span.name === 'POST getPrefecture') && + spans.some(span => span.name === 'getPrefecture' && !span.is_segment), + ); await page.goto('/'); await page.locator('#navLink').click(); await page.waitForURL('/users/5'); - const transaction = await transactionPromise; - - expect(transaction.spans).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - description: 'getPrefecture', - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart', - }, - }), - ]), - ); + const spans = await spansPromise; + const functionSpan = spans.find(span => span.name === 'getPrefecture' && !span.is_segment); + + expect(functionSpan).toBeDefined(); + expect(functionSpan?.attributes).toMatchObject({ + 'sentry.op': { value: 'function', type: 'string' }, + 'sentry.origin': { value: 'auto.function.solidstart', type: 'string' }, + }); }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/entry-client.tsx b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/entry-client.tsx index d9900ed5689d..11087fbb5918 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/entry-client.tsx +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/entry-client.tsx @@ -4,7 +4,6 @@ import { solidRouterBrowserTracingIntegration } from '@sentry/solidstart/solidro import { StartClient, mount } from '@solidjs/start/client'; Sentry.init({ - traceLifecycle: 'static', // We can't use env variables here, seems like they are stripped // out in production builds. dsn: 'https://public@dsn.ingest.sentry.io/1337', diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts index d89f2566f8be..3dd5d8933b7b 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts @@ -1,7 +1,6 @@ import * as Sentry from '@sentry/solidstart'; Sentry.init({ - traceLifecycle: 'static', dsn: process.env.E2E_TEST_DSN, environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.client.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.client.test.ts index c67354349bf9..fa2c8554530f 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.client.test.ts @@ -1,119 +1,81 @@ import { expect, test } from '@playwright/test'; -import { waitForTransaction } from '@sentry-internal/test-utils'; +import { getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils'; -test('sends a pageload transaction', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-top-level-import', async transactionEvent => { - return transactionEvent?.transaction === '/' && transactionEvent.contexts?.trace?.op === 'pageload'; +test('sends a pageload span', async ({ page }) => { + const spanPromise = waitForStreamedSpan('solidstart-top-level-import', span => { + return span.name === '/' && getSpanOp(span) === 'pageload' && span.is_segment; }); await page.goto('/'); - const pageloadTransaction = await transactionPromise; + const pageloadSpan = await spanPromise; - expect(pageloadTransaction).toMatchObject({ - contexts: { - trace: { - op: 'pageload', - origin: 'auto.pageload.browser', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/', - 'url.path': '/', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/$/), - }, - }, - }, - transaction: '/', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(pageloadSpan)).toBe('pageload'); + expect(pageloadSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.pageload.browser', type: 'string' }, + 'sentry.op': { value: 'pageload', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/', type: 'string' }, + 'url.path': { value: '/', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/$/), type: 'string' }, }); }); -test('sends a navigation transaction with parametrized route', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-top-level-import', async transactionEvent => { - return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation'; +test('sends a navigation span with parametrized route', async ({ page }) => { + const spanPromise = waitForStreamedSpan('solidstart-top-level-import', span => { + return span.name === '/users/:id' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goto(`/`); await page.locator('#navLink').click(); - const navigationTransaction = await transactionPromise; + const navigationSpan = await spanPromise; - expect(navigationTransaction).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/users/:id', - 'url.path': '/users/5', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/), - }, - }, - }, - transaction: '/users/:id', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(navigationSpan)).toBe('navigation'); + expect(navigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/users/:id', type: 'string' }, + 'url.path': { value: '/users/5', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/5$/), type: 'string' }, }); }); -test('updates the transaction when using the back button', async ({ page }) => { +test('updates the span when using the back button', async ({ page }) => { // Solid Router sends a `-1` navigation when using the back button. // The sentry solidRouterBrowserTracingIntegration tries to update such - // transactions with the proper name once the `useLocation` hook triggers. - const navigationTxnPromise = waitForTransaction('solidstart-top-level-import', async transactionEvent => { - return transactionEvent?.transaction === '/users/:id' && transactionEvent.contexts?.trace?.op === 'navigation'; + // spans with the proper name once the `useLocation` hook triggers. + const navigationSpanPromise = waitForStreamedSpan('solidstart-top-level-import', span => { + return span.name === '/users/:id' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goto(`/back-navigation`); await page.locator('#navLink').click(); - const navigationTxn = await navigationTxnPromise; + const navigationSpan = await navigationSpanPromise; - expect(navigationTxn).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/users/:id', - 'url.path': '/users/6', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/), - }, - }, - }, - transaction: '/users/:id', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(navigationSpan)).toBe('navigation'); + expect(navigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/users/:id', type: 'string' }, + 'url.path': { value: '/users/6', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/users\/6$/), type: 'string' }, }); - const backNavigationTxnPromise = waitForTransaction('solidstart-top-level-import', async transactionEvent => { - return ( - transactionEvent?.transaction === '/back-navigation' && transactionEvent.contexts?.trace?.op === 'navigation' - ); + const backNavigationSpanPromise = waitForStreamedSpan('solidstart-top-level-import', span => { + return span.name === '/back-navigation' && getSpanOp(span) === 'navigation' && span.is_segment; }); await page.goBack(); - const backNavigationTxn = await backNavigationTxnPromise; + const backNavigationSpan = await backNavigationSpanPromise; - expect(backNavigationTxn).toMatchObject({ - contexts: { - trace: { - op: 'navigation', - origin: 'auto.navigation.solidstart.solidrouter', - data: { - 'sentry.segment.name.source': 'route', - 'url.template': '/back-navigation', - 'url.path': '/back-navigation', - 'url.full': expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/), - }, - }, - }, - transaction: '/back-navigation', - transaction_info: { - source: 'route', - }, + expect(getSpanOp(backNavigationSpan)).toBe('navigation'); + expect(backNavigationSpan.attributes).toMatchObject({ + 'sentry.origin': { value: 'auto.navigation.solidstart.solidrouter', type: 'string' }, + 'sentry.op': { value: 'navigation', type: 'string' }, + 'sentry.segment.name.source': { value: 'route', type: 'string' }, + 'url.template': { value: '/back-navigation', type: 'string' }, + 'url.path': { value: '/back-navigation', type: 'string' }, + 'url.full': { value: expect.stringMatching(/^https?:\/\/localhost:\d+\/back-navigation$/), type: 'string' }, }); }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.server.test.ts b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.server.test.ts index 82a254827e06..1881c58450ee 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/tests/performance.server.test.ts @@ -1,49 +1,46 @@ import { expect, test } from '@playwright/test'; -import { waitForTransaction } from '@sentry-internal/test-utils'; -import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/solidstart'; - -test('sends a server action transaction on pageload', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-top-level-import', transactionEvent => { - return transactionEvent?.transaction === 'GET /users/6'; - }); +import { collectStreamedSpans, getSpanOp } from '@sentry-internal/test-utils'; + +test('sends a server action span on pageload', async ({ page }) => { + const spansPromise = collectStreamedSpans( + 'solidstart-top-level-import', + spans => + spans.some( + span => + span.is_segment && getSpanOp(span) === 'http.server' && span.attributes['url.path']?.value === '/users/6', + ) && spans.some(span => span.name === 'getPrefecture'), + ); await page.goto('/users/6'); - const transaction = await transactionPromise; - - expect(transaction.spans).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - description: 'getPrefecture', - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart', - }, - }), - ]), - ); -}); + const spans = await spansPromise; + const functionSpan = spans.find(span => span.name === 'getPrefecture'); -test('sends a server action transaction on client navigation', async ({ page }) => { - const transactionPromise = waitForTransaction('solidstart-top-level-import', transactionEvent => { - return transactionEvent?.transaction === 'POST getPrefecture'; + expect(functionSpan).toBeDefined(); + expect(functionSpan?.attributes).toMatchObject({ + 'sentry.op': { value: 'function', type: 'string' }, + 'sentry.origin': { value: 'auto.function.solidstart', type: 'string' }, }); +}); + +test('sends a server action span on client navigation', async ({ page }) => { + const spansPromise = collectStreamedSpans( + 'solidstart-top-level-import', + spans => + spans.some(span => span.is_segment && span.name === 'POST getPrefecture') && + spans.some(span => span.name === 'getPrefecture' && !span.is_segment), + ); await page.goto('/'); await page.locator('#navLink').click(); await page.waitForURL('/users/5'); - const transaction = await transactionPromise; - - expect(transaction.spans).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - description: 'getPrefecture', - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.solidstart', - }, - }), - ]), - ); + const spans = await spansPromise; + const functionSpan = spans.find(span => span.name === 'getPrefecture' && !span.is_segment); + + expect(functionSpan).toBeDefined(); + expect(functionSpan?.attributes).toMatchObject({ + 'sentry.op': { value: 'function', type: 'string' }, + 'sentry.origin': { value: 'auto.function.solidstart', type: 'string' }, + }); });