From 2edf0afc720698923d65e6d479b3cb4b50f2d6ec Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Wed, 2 Jul 2025 13:23:12 +0200 Subject: [PATCH 1/7] rename error button --- .../nuxt-3-dynamic-import/pages/fetch-server-error.vue | 8 ++++---- .../nuxt-3-dynamic-import/tests/errors.server.test.ts | 2 +- .../nuxt-3-min/pages/fetch-server-error.vue | 8 ++++---- .../nuxt-3-min/tests/errors.server.test.ts | 2 +- .../nuxt-3-top-level-import/pages/fetch-server-error.vue | 8 ++++---- .../nuxt-3-top-level-import/tests/errors.server.test.ts | 4 ++-- .../test-applications/nuxt-3/pages/fetch-server-error.vue | 8 ++++---- .../test-applications/nuxt-3/tests/errors.server.test.ts | 2 +- .../nuxt-4/app/pages/fetch-server-error.vue | 8 ++++---- .../test-applications/nuxt-4/tests/errors.server.test.ts | 2 +- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue index 8cb2a9997e58..25ed45233d98 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue @@ -1,13 +1,13 @@ diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts index b781642c2b4f..3dbc2d8e55e9 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.server.test.ts @@ -8,7 +8,7 @@ test.describe('server-side errors', async () => { }); await page.goto(`/fetch-server-error`); - await page.getByText('Fetch Server Data', { exact: true }).click(); + await page.getByText('Fetch Server Error', { exact: true }).click(); const error = await errorPromise; diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/fetch-server-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/fetch-server-error.vue index 8cb2a9997e58..25ed45233d98 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/fetch-server-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/fetch-server-error.vue @@ -1,13 +1,13 @@ diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts index 8f20aa938893..099ec8a24fa7 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts @@ -8,7 +8,7 @@ test.describe('server-side errors', async () => { }); await page.goto(`/fetch-server-error`); - await page.getByText('Fetch Server Data', { exact: true }).click(); + await page.getByText('Fetch Server Error', { exact: true }).click(); const error = await errorPromise; diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/fetch-server-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/fetch-server-error.vue index 8cb2a9997e58..25ed45233d98 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/fetch-server-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/fetch-server-error.vue @@ -1,13 +1,13 @@ diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts index 053ec5b6ab67..de520ed57f8c 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/errors.server.test.ts @@ -12,7 +12,7 @@ test.describe('server-side errors', async () => { }); await page.goto(`/fetch-server-error`); - await page.getByText('Fetch Server Data', { exact: true }).click(); + await page.getByText('Fetch Server Error', { exact: true }).click(); const transactionEvent = await transactionEventPromise; const error = await errorPromise; @@ -40,7 +40,7 @@ test.describe('server-side errors', async () => { }); await page.goto(`/fetch-server-error`); - await page.getByText('Fetch Server Data', { exact: true }).click(); + await page.getByText('Fetch Server Error', { exact: true }).click(); const transactionEvent = await transactionEventPromise; const error = await errorPromise; diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/pages/fetch-server-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-3/pages/fetch-server-error.vue index 8cb2a9997e58..25ed45233d98 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/pages/fetch-server-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/pages/fetch-server-error.vue @@ -1,13 +1,13 @@ diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts index d1556d511bf0..c590413e4b14 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.server.test.ts @@ -8,7 +8,7 @@ test.describe('server-side errors', async () => { }); await page.goto(`/fetch-server-error`); - await page.getByText('Fetch Server Data', { exact: true }).click(); + await page.getByText('Fetch Server Error', { exact: true }).click(); const error = await errorPromise; diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/fetch-server-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/fetch-server-error.vue index 8cb2a9997e58..25ed45233d98 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/fetch-server-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/fetch-server-error.vue @@ -1,13 +1,13 @@ diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts index 396870d19925..862b92217f7b 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.server.test.ts @@ -8,7 +8,7 @@ test.describe('server-side errors', async () => { }); await page.goto(`/fetch-server-error`); - await page.getByText('Fetch Server Data', { exact: true }).click(); + await page.getByText('Fetch Server Error', { exact: true }).click(); const error = await errorPromise; From 963cc3f8dc1b01b9607c2a13bcfd472cdfd13dda Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Wed, 2 Jul 2025 13:59:20 +0200 Subject: [PATCH 2/7] test(nuxt): Add test for distributed server request --- .../nuxt-4/tests/tracing.test.ts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts index 505a912c95d5..511880da17a6 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts @@ -66,4 +66,70 @@ test.describe('distributed tracing', () => { expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id); expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId); }); + + test('capture a distributed server request with parametrization', async ({ page }) => { + const clientTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { + return txnEvent.transaction === '/test-param/:param()'; + }); + + const ssrTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { + return txnEvent.transaction.includes('GET /test-param/'); + }); + + const serverReqTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { + return txnEvent.transaction.includes('GET /api/test-param/'); + }); + + const [, clientTxnEvent, ssrTxnEvent, , , serverReqTxnEvent] = await Promise.all([ + page.goto(`/test-param/${PARAM}`), + clientTxnEventPromise, + ssrTxnEventPromise, + expect(page.getByText(`Param: ${PARAM}`)).toBeVisible(), + page.getByText('Fetch Server Data', { exact: true }).click(), + serverReqTxnEventPromise, + ]); + + const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/test-param/${PARAM}`); + + expect(ssrTxnEvent).toMatchObject({ + transaction: `GET /test-param/${PARAM}`, // todo: parametrize (nitro) + transaction_info: { source: 'url' }, + type: 'transaction', + contexts: { + trace: { + op: 'http.server', + origin: 'auto.http.otel.http', + }, + }, + }); + + expect(httpClientSpan).toMatchObject({ + description: `GET /api/test-param/${PARAM}`, // todo: parametrize (nitro) + parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent + data: expect.objectContaining({ + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + 'http.request_method': 'GET', + }), + }); + + expect(serverReqTxnEvent).toMatchObject({ + transaction: `GET /api/test-param/${PARAM}`, // todo: parametrize (nitro) + transaction_info: { source: 'url' }, + type: 'transaction', + contexts: { + trace: { + op: 'http.server', + origin: 'auto.http.otel.http', + parent_span_id: httpClientSpan?.span_id, // http.client span is parent + }, + }, + }); + + // All share the same trace_id + expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined(); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id); + }); }); From 86de9e060db826fcaad8ffb85425842255fc3707 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Wed, 2 Jul 2025 14:28:55 +0200 Subject: [PATCH 3/7] fix button naming to be exact --- .../nuxt-3-dynamic-import/pages/fetch-server-error.vue | 2 +- .../nuxt-3-dynamic-import/pages/test-param/[param].vue | 7 +++---- .../nuxt-3-dynamic-import/tests/errors.server.test.ts | 4 ++-- .../nuxt-3-min/pages/fetch-server-error.vue | 2 +- .../nuxt-3-min/pages/test-param/[param].vue | 7 +++---- .../nuxt-3-min/tests/errors.server.test.ts | 4 ++-- .../nuxt-3-top-level-import/pages/fetch-server-error.vue | 2 +- .../nuxt-3-top-level-import/pages/test-param/[param].vue | 7 +++---- .../nuxt-3-top-level-import/tests/errors.server.test.ts | 6 +++--- .../test-applications/nuxt-3/pages/fetch-server-error.vue | 2 +- .../test-applications/nuxt-3/pages/test-param/[param].vue | 7 +++---- .../test-applications/nuxt-3/tests/errors.server.test.ts | 4 ++-- .../nuxt-4/app/pages/fetch-server-error.vue | 2 +- .../nuxt-4/app/pages/test-param/[param].vue | 7 +++---- .../test-applications/nuxt-4/tests/errors.server.test.ts | 4 ++-- 15 files changed, 31 insertions(+), 36 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue index 25ed45233d98..0e9aeb34b4fc 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/fetch-server-error.vue @@ -1,6 +1,6 @@ diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/[param].vue b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/[param].vue index e83392b37b5c..019404aaf460 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/[param].vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/[param].vue @@ -1,12 +1,12 @@ + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts index 511880da17a6..f8bcc819dc58 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts @@ -10,7 +10,7 @@ test.describe('distributed tracing', () => { }); const serverTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { - return txnEvent.transaction.includes('GET /test-param/'); + return txnEvent.transaction?.includes('GET /test-param/') ?? false; }); const [_, clientTxnEvent, serverTxnEvent] = await Promise.all([ @@ -67,66 +67,87 @@ test.describe('distributed tracing', () => { expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId); }); - test('capture a distributed server request with parametrization', async ({ page }) => { + test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => { const clientTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { - return txnEvent.transaction === '/test-param/:param()'; + return txnEvent.transaction === '/test-param/fetch-api/:param()'; }); - const ssrTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { - return txnEvent.transaction.includes('GET /test-param/'); + return txnEvent.transaction?.includes('GET /test-param/fetch-api') ?? false; }); - const serverReqTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { - return txnEvent.transaction.includes('GET /api/test-param/'); + return txnEvent.transaction?.includes('GET /api/test-param/') ?? false; }); - const [, clientTxnEvent, ssrTxnEvent, , , serverReqTxnEvent] = await Promise.all([ - page.goto(`/test-param/${PARAM}`), + // Navigate to the page which will trigger an API call from the client-side + await page.goto(`/test-param/fetch-api/${PARAM}`); + + const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([ clientTxnEventPromise, ssrTxnEventPromise, - expect(page.getByText(`Param: ${PARAM}`)).toBeVisible(), - page.getByText('Fetch Server Data', { exact: true }).click(), serverReqTxnEventPromise, ]); const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/test-param/${PARAM}`); - expect(ssrTxnEvent).toMatchObject({ - transaction: `GET /test-param/${PARAM}`, // todo: parametrize (nitro) - transaction_info: { source: 'url' }, - type: 'transaction', - contexts: { - trace: { - op: 'http.server', - origin: 'auto.http.otel.http', - }, - }, - }); - - expect(httpClientSpan).toMatchObject({ - description: `GET /api/test-param/${PARAM}`, // todo: parametrize (nitro) - parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent - data: expect.objectContaining({ - 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.browser', - 'http.request_method': 'GET', + expect(clientTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: '/test-param/fetch-api/:param()', // parametrized route + transaction_info: { source: 'route' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'pageload', + origin: 'auto.pageload.vue', + }), + }), }), - }); - - expect(serverReqTxnEvent).toMatchObject({ - transaction: `GET /api/test-param/${PARAM}`, // todo: parametrize (nitro) - transaction_info: { source: 'url' }, - type: 'transaction', - contexts: { - trace: { - op: 'http.server', - origin: 'auto.http.otel.http', - parent_span_id: httpClientSpan?.span_id, // http.client span is parent - }, - }, - }); + ); + + expect(httpClientSpan).toBeDefined(); + expect(httpClientSpan).toEqual( + expect.objectContaining({ + description: `GET /api/test-param/${PARAM}`, // fixme: parametrize + parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent + data: expect.objectContaining({ + url: `/api/test-param/${PARAM}`, // fixme: parametrize + type: 'fetch', + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + 'http.method': 'GET', + }), + }), + ); + + expect(ssrTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /test-param/fetch-api/${PARAM}`, // fixme: parametrize (nitro) + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + }), + }), + }), + ); + + expect(serverReqTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /api/test-param/${PARAM}`, + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + parent_span_id: httpClientSpan?.span_id, // http.client span is parent + }), + }), + }), + ); - // All share the same trace_id + // All 3 transactions and the http.client span should share the same trace_id expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined(); expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id); expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id); From 56c916f03c5c608ea445adc30c179021544b2696 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Mon, 7 Jul 2025 13:56:57 +0200 Subject: [PATCH 5/7] Standardize test case --- dev-packages/e2e-tests/README.md | 19 ++++++++++++++++++ .../pages/test-param/fetch-api/[param].vue | 16 --------------- .../app/pages/test-param/user/[userId].vue | 16 +++++++++++++++ .../nuxt-4/server/api/user/[userId].ts | 7 +++++++ .../nuxt-4/tests/tracing.test.ts | 20 +++++++++---------- 5 files changed, 52 insertions(+), 26 deletions(-) delete mode 100644 dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/fetch-api/[param].vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/user/[userId].vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-4/server/api/user/[userId].ts diff --git a/dev-packages/e2e-tests/README.md b/dev-packages/e2e-tests/README.md index 919d74e78542..7a52495d3b4c 100644 --- a/dev-packages/e2e-tests/README.md +++ b/dev-packages/e2e-tests/README.md @@ -133,3 +133,22 @@ A standardized frontend test application has the following features: ### Standardized Backend Test Apps TBD + +### Standardized Frontend-to-Backend Test Apps + +A standardized Meta test application has the following features: + +- Has a parameterized backend API route `/user/:id` that returns a JSON object with the user ID. +- Has a parameterized frontend page (can be SSR) `/user/:id` that fetches the user data on the client-side from the API route and displays it. + +The following test cases for connected tracing should be implemented in the test app: + +- Capturing a distributed page load trace when a page is loaded + - The HTML meta-tag should include the Sentry trace data and baggage + - The server root span should be the parent of the client pageload span + - All routes (server and client) should be parameterized, e.g. `/user/5` should be captured as `/user/:id` route +- Capturing a distributed trace when requesting the API from the client-side + - There should be three transactions involved: the client pageload, the server "pageload", and the server API request + - The client pageload should include an `http.client` span that is the parent of the server API request span + - All three transactions and the `http.client` span should share the same `trace_id` + - All `transaction` names and the `span` description should be parameterized, e.g. `/user/5` should be captured as `/user/:id` route diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/fetch-api/[param].vue b/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/fetch-api/[param].vue deleted file mode 100644 index 8a65881c84e8..000000000000 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/fetch-api/[param].vue +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/user/[userId].vue b/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/user/[userId].vue new file mode 100644 index 000000000000..41daf0460b05 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/test-param/user/[userId].vue @@ -0,0 +1,16 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/server/api/user/[userId].ts b/dev-packages/e2e-tests/test-applications/nuxt-4/server/api/user/[userId].ts new file mode 100644 index 000000000000..eb268d2f3e13 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/server/api/user/[userId].ts @@ -0,0 +1,7 @@ +import { defineEventHandler, getRouterParam } from '#imports'; + +export default defineEventHandler(event => { + const userId = getRouterParam(event, 'userId'); + + return `UserId Param: ${userId}!`; +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts index f8bcc819dc58..bb824f60f7d1 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/tracing.test.ts @@ -69,17 +69,17 @@ test.describe('distributed tracing', () => { test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => { const clientTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { - return txnEvent.transaction === '/test-param/fetch-api/:param()'; + return txnEvent.transaction === '/test-param/user/:userId()'; }); const ssrTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { - return txnEvent.transaction?.includes('GET /test-param/fetch-api') ?? false; + return txnEvent.transaction?.includes('GET /test-param/user') ?? false; }); const serverReqTxnEventPromise = waitForTransaction('nuxt-4', txnEvent => { - return txnEvent.transaction?.includes('GET /api/test-param/') ?? false; + return txnEvent.transaction?.includes('GET /api/user/') ?? false; }); // Navigate to the page which will trigger an API call from the client-side - await page.goto(`/test-param/fetch-api/${PARAM}`); + await page.goto(`/test-param/user/${PARAM}`); const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([ clientTxnEventPromise, @@ -87,12 +87,12 @@ test.describe('distributed tracing', () => { serverReqTxnEventPromise, ]); - const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/test-param/${PARAM}`); + const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`); expect(clientTxnEvent).toEqual( expect.objectContaining({ type: 'transaction', - transaction: '/test-param/fetch-api/:param()', // parametrized route + transaction: '/test-param/user/:userId()', // parametrized route transaction_info: { source: 'route' }, contexts: expect.objectContaining({ trace: expect.objectContaining({ @@ -106,10 +106,10 @@ test.describe('distributed tracing', () => { expect(httpClientSpan).toBeDefined(); expect(httpClientSpan).toEqual( expect.objectContaining({ - description: `GET /api/test-param/${PARAM}`, // fixme: parametrize + description: `GET /api/user/${PARAM}`, // fixme: parametrize parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent data: expect.objectContaining({ - url: `/api/test-param/${PARAM}`, // fixme: parametrize + url: `/api/user/${PARAM}`, type: 'fetch', 'sentry.op': 'http.client', 'sentry.origin': 'auto.http.browser', @@ -121,7 +121,7 @@ test.describe('distributed tracing', () => { expect(ssrTxnEvent).toEqual( expect.objectContaining({ type: 'transaction', - transaction: `GET /test-param/fetch-api/${PARAM}`, // fixme: parametrize (nitro) + transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro) transaction_info: { source: 'url' }, contexts: expect.objectContaining({ trace: expect.objectContaining({ @@ -135,7 +135,7 @@ test.describe('distributed tracing', () => { expect(serverReqTxnEvent).toEqual( expect.objectContaining({ type: 'transaction', - transaction: `GET /api/test-param/${PARAM}`, + transaction: `GET /api/user/${PARAM}`, transaction_info: { source: 'url' }, contexts: expect.objectContaining({ trace: expect.objectContaining({ From 2be99a2165ce9290fdb41f14c4d21c758bf3b9f8 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Mon, 7 Jul 2025 14:20:38 +0200 Subject: [PATCH 6/7] add distributed test case to all nuxt tests --- .../pages/test-param/user/[userId].vue | 16 ++++ .../server/api/user/[userId].ts | 7 ++ .../tests/tracing.test.ts | 87 +++++++++++++++++++ .../pages/test-param/user/[userId].vue | 16 ++++ .../nuxt-3-min/server/api/user/[userId].ts | 7 ++ .../nuxt-3-min/tests/tracing.test.ts | 87 +++++++++++++++++++ .../pages/test-param/user/[userId].vue | 16 ++++ .../server/api/user/[userId].ts | 7 ++ .../tests/tracing.test.ts | 87 +++++++++++++++++++ .../nuxt-3/pages/test-param/user/[userId].vue | 16 ++++ .../nuxt-3/server/api/user/[userId].ts | 7 ++ .../nuxt-3/tests/tracing.test.ts | 87 +++++++++++++++++++ 12 files changed, 440 insertions(+) create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/user/[userId].vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/server/api/user/[userId].ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/user/[userId].vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/user/[userId].ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/test-param/user/[userId].vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/server/api/user/[userId].ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3/pages/test-param/user/[userId].vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3/server/api/user/[userId].ts diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/user/[userId].vue b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/user/[userId].vue new file mode 100644 index 000000000000..41daf0460b05 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/pages/test-param/user/[userId].vue @@ -0,0 +1,16 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/server/api/user/[userId].ts b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/server/api/user/[userId].ts new file mode 100644 index 000000000000..eb268d2f3e13 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/server/api/user/[userId].ts @@ -0,0 +1,7 @@ +import { defineEventHandler, getRouterParam } from '#imports'; + +export default defineEventHandler(event => { + const userId = getRouterParam(event, 'userId'); + + return `UserId Param: ${userId}!`; +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/tracing.test.ts index 0bc6ffa80b73..17c2704279b3 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/tracing.test.ts @@ -66,4 +66,91 @@ test.describe('distributed tracing', () => { expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id); expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId); }); + + test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => { + const clientTxnEventPromise = waitForTransaction('nuxt-3-dynamic-import', txnEvent => { + return txnEvent.transaction === '/test-param/user/:userId()'; + }); + const ssrTxnEventPromise = waitForTransaction('nuxt-3-dynamic-import', txnEvent => { + return txnEvent.transaction?.includes('GET /test-param/user') ?? false; + }); + const serverReqTxnEventPromise = waitForTransaction('nuxt-3-dynamic-import', txnEvent => { + return txnEvent.transaction?.includes('GET /api/user/') ?? false; + }); + + // Navigate to the page which will trigger an API call from the client-side + await page.goto(`/test-param/user/${PARAM}`); + + const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([ + clientTxnEventPromise, + ssrTxnEventPromise, + serverReqTxnEventPromise, + ]); + + const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`); + + expect(clientTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: '/test-param/user/:userId()', // parametrized route + transaction_info: { source: 'route' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'pageload', + origin: 'auto.pageload.vue', + }), + }), + }), + ); + + expect(httpClientSpan).toBeDefined(); + expect(httpClientSpan).toEqual( + expect.objectContaining({ + description: `GET /api/user/${PARAM}`, // fixme: parametrize + parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent + data: expect.objectContaining({ + url: `/api/user/${PARAM}`, + type: 'fetch', + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + 'http.method': 'GET', + }), + }), + ); + + expect(ssrTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro) + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + }), + }), + }), + ); + + expect(serverReqTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /api/user/${PARAM}`, + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + parent_span_id: httpClientSpan?.span_id, // http.client span is parent + }), + }), + }), + ); + + // All 3 transactions and the http.client span should share the same trace_id + expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined(); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id); + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/user/[userId].vue b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/user/[userId].vue new file mode 100644 index 000000000000..41daf0460b05 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/user/[userId].vue @@ -0,0 +1,16 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/user/[userId].ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/user/[userId].ts new file mode 100644 index 000000000000..eb268d2f3e13 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/user/[userId].ts @@ -0,0 +1,7 @@ +import { defineEventHandler, getRouterParam } from '#imports'; + +export default defineEventHandler(event => { + const userId = getRouterParam(event, 'userId'); + + return `UserId Param: ${userId}!`; +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts index cb86df11fe84..0daa9a856236 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts @@ -66,4 +66,91 @@ test.describe('distributed tracing', () => { expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id); expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId); }); + + test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => { + const clientTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => { + return txnEvent.transaction === '/test-param/user/:userId()'; + }); + const ssrTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => { + return txnEvent.transaction?.includes('GET /test-param/user') ?? false; + }); + const serverReqTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => { + return txnEvent.transaction?.includes('GET /api/user/') ?? false; + }); + + // Navigate to the page which will trigger an API call from the client-side + await page.goto(`/test-param/user/${PARAM}`); + + const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([ + clientTxnEventPromise, + ssrTxnEventPromise, + serverReqTxnEventPromise, + ]); + + const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`); + + expect(clientTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: '/test-param/user/:userId()', // parametrized route + transaction_info: { source: 'route' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'pageload', + origin: 'auto.pageload.vue', + }), + }), + }), + ); + + expect(httpClientSpan).toBeDefined(); + expect(httpClientSpan).toEqual( + expect.objectContaining({ + description: `GET /api/user/${PARAM}`, // fixme: parametrize + parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent + data: expect.objectContaining({ + url: `/api/user/${PARAM}`, + type: 'fetch', + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + 'http.method': 'GET', + }), + }), + ); + + expect(ssrTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro) + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + }), + }), + }), + ); + + expect(serverReqTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /api/user/${PARAM}`, + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + parent_span_id: httpClientSpan?.span_id, // http.client span is parent + }), + }), + }), + ); + + // All 3 transactions and the http.client span should share the same trace_id + expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined(); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id); + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/test-param/user/[userId].vue b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/test-param/user/[userId].vue new file mode 100644 index 000000000000..41daf0460b05 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/pages/test-param/user/[userId].vue @@ -0,0 +1,16 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/server/api/user/[userId].ts b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/server/api/user/[userId].ts new file mode 100644 index 000000000000..eb268d2f3e13 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/server/api/user/[userId].ts @@ -0,0 +1,7 @@ +import { defineEventHandler, getRouterParam } from '#imports'; + +export default defineEventHandler(event => { + const userId = getRouterParam(event, 'userId'); + + return `UserId Param: ${userId}!`; +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/tracing.test.ts index 69c4bd2833c4..5248926e30fb 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/tracing.test.ts @@ -66,4 +66,91 @@ test.describe('distributed tracing', () => { expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id); expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId); }); + + test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => { + const clientTxnEventPromise = waitForTransaction('nuxt-3-top-level-import', txnEvent => { + return txnEvent.transaction === '/test-param/user/:userId()'; + }); + const ssrTxnEventPromise = waitForTransaction('nuxt-3-top-level-import', txnEvent => { + return txnEvent.transaction?.includes('GET /test-param/user') ?? false; + }); + const serverReqTxnEventPromise = waitForTransaction('nuxt-3-top-level-import', txnEvent => { + return txnEvent.transaction?.includes('GET /api/user/') ?? false; + }); + + // Navigate to the page which will trigger an API call from the client-side + await page.goto(`/test-param/user/${PARAM}`); + + const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([ + clientTxnEventPromise, + ssrTxnEventPromise, + serverReqTxnEventPromise, + ]); + + const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`); + + expect(clientTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: '/test-param/user/:userId()', // parametrized route + transaction_info: { source: 'route' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'pageload', + origin: 'auto.pageload.vue', + }), + }), + }), + ); + + expect(httpClientSpan).toBeDefined(); + expect(httpClientSpan).toEqual( + expect.objectContaining({ + description: `GET /api/user/${PARAM}`, // fixme: parametrize + parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent + data: expect.objectContaining({ + url: `/api/user/${PARAM}`, + type: 'fetch', + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + 'http.method': 'GET', + }), + }), + ); + + expect(ssrTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro) + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + }), + }), + }), + ); + + expect(serverReqTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /api/user/${PARAM}`, + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + parent_span_id: httpClientSpan?.span_id, // http.client span is parent + }), + }), + }), + ); + + // All 3 transactions and the http.client span should share the same trace_id + expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined(); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id); + }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/pages/test-param/user/[userId].vue b/dev-packages/e2e-tests/test-applications/nuxt-3/pages/test-param/user/[userId].vue new file mode 100644 index 000000000000..41daf0460b05 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/pages/test-param/user/[userId].vue @@ -0,0 +1,16 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/server/api/user/[userId].ts b/dev-packages/e2e-tests/test-applications/nuxt-3/server/api/user/[userId].ts new file mode 100644 index 000000000000..eb268d2f3e13 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/server/api/user/[userId].ts @@ -0,0 +1,7 @@ +import { defineEventHandler, getRouterParam } from '#imports'; + +export default defineEventHandler(event => { + const userId = getRouterParam(event, 'userId'); + + return `UserId Param: ${userId}!`; +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/tracing.test.ts index 523ece4cc085..58eb03eccb88 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/tracing.test.ts @@ -66,4 +66,91 @@ test.describe('distributed tracing', () => { expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id); expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId); }); + + test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => { + const clientTxnEventPromise = waitForTransaction('nuxt-3', txnEvent => { + return txnEvent.transaction === '/test-param/user/:userId()'; + }); + const ssrTxnEventPromise = waitForTransaction('nuxt-3', txnEvent => { + return txnEvent.transaction?.includes('GET /test-param/user') ?? false; + }); + const serverReqTxnEventPromise = waitForTransaction('nuxt-3', txnEvent => { + return txnEvent.transaction?.includes('GET /api/user/') ?? false; + }); + + // Navigate to the page which will trigger an API call from the client-side + await page.goto(`/test-param/user/${PARAM}`); + + const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([ + clientTxnEventPromise, + ssrTxnEventPromise, + serverReqTxnEventPromise, + ]); + + const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`); + + expect(clientTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: '/test-param/user/:userId()', // parametrized route + transaction_info: { source: 'route' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'pageload', + origin: 'auto.pageload.vue', + }), + }), + }), + ); + + expect(httpClientSpan).toBeDefined(); + expect(httpClientSpan).toEqual( + expect.objectContaining({ + description: `GET /api/user/${PARAM}`, // fixme: parametrize + parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent + data: expect.objectContaining({ + url: `/api/user/${PARAM}`, + type: 'fetch', + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + 'http.method': 'GET', + }), + }), + ); + + expect(ssrTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro) + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + }), + }), + }), + ); + + expect(serverReqTxnEvent).toEqual( + expect.objectContaining({ + type: 'transaction', + transaction: `GET /api/user/${PARAM}`, + transaction_info: { source: 'url' }, + contexts: expect.objectContaining({ + trace: expect.objectContaining({ + op: 'http.server', + origin: 'auto.http.otel.http', + parent_span_id: httpClientSpan?.span_id, // http.client span is parent + }), + }), + }), + ); + + // All 3 transactions and the http.client span should share the same trace_id + expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined(); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id); + }); }); From 32d72fbb42aded3d197cbf4924f8505eb6d4719d Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Mon, 7 Jul 2025 14:23:55 +0200 Subject: [PATCH 7/7] update readme --- dev-packages/e2e-tests/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev-packages/e2e-tests/README.md b/dev-packages/e2e-tests/README.md index 7a52495d3b4c..a1eb1b559b9c 100644 --- a/dev-packages/e2e-tests/README.md +++ b/dev-packages/e2e-tests/README.md @@ -136,11 +136,13 @@ TBD ### Standardized Frontend-to-Backend Test Apps -A standardized Meta test application has the following features: +A standardized Meta-Framework test application has the following features: - Has a parameterized backend API route `/user/:id` that returns a JSON object with the user ID. - Has a parameterized frontend page (can be SSR) `/user/:id` that fetches the user data on the client-side from the API route and displays it. +This setup creates the scenario where the frontend page loads, and then immediately makes an API request to the backend API. + The following test cases for connected tracing should be implemented in the test app: - Capturing a distributed page load trace when a page is loaded