From 0f57878ab2a561a1e36bd1b787325ce83dad9073 Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Wed, 13 Nov 2024 16:40:28 +0100 Subject: [PATCH] test(e2e): Add nuxt 3 minimum supported e2e test app with pinned nitro 2.9.7 dep --- .github/workflows/build.yml | 1 + .../test-applications/nuxt-3-min/.gitignore | 24 ++++ .../test-applications/nuxt-3-min/.npmrc | 2 + .../test-applications/nuxt-3-min/app.vue | 17 +++ .../nuxt-3-min/components/ErrorButton.vue | 22 ++++ .../nuxt-3-min/copyIITM.bash | 7 ++ .../nuxt-3-min/nuxt.config.ts | 20 ++++ .../test-applications/nuxt-3-min/package.json | 30 +++++ .../nuxt-3-min/pages/client-error.vue | 11 ++ .../nuxt-3-min/pages/fetch-server-error.vue | 13 +++ .../nuxt-3-min/pages/index.vue | 3 + .../nuxt-3-min/pages/test-param/[param].vue | 23 ++++ .../nuxt-3-min/playwright.config.ts | 19 ++++ .../nuxt-3-min/public/favicon.ico | Bin 0 -> 4286 bytes .../nuxt-3-min/sentry.client.config.ts | 10 ++ .../nuxt-3-min/sentry.server.config.ts | 8 ++ .../server/api/param-error/[param].ts | 5 + .../nuxt-3-min/server/api/server-error.ts | 5 + .../server/api/test-param/[param].ts | 7 ++ .../nuxt-3-min/server/tsconfig.json | 3 + .../nuxt-3-min/start-event-proxy.mjs | 6 + .../nuxt-3-min/tests/errors.client.test.ts | 105 ++++++++++++++++++ .../nuxt-3-min/tests/errors.server.test.ts | 40 +++++++ .../nuxt-3-min/tests/tracing.client.test.ts | 57 ++++++++++ .../nuxt-3-min/tests/tracing.server.test.ts | 46 ++++++++ .../nuxt-3-min/tests/tracing.test.ts | 51 +++++++++ .../nuxt-3-min/tsconfig.json | 4 + .../test-applications/nuxt-3/package.json | 2 +- 28 files changed, 540 insertions(+), 1 deletion(-) create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/.gitignore create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/.npmrc create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/app.vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/components/ErrorButton.vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/copyIITM.bash create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/nuxt.config.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/client-error.vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/fetch-server-error.vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/index.vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/[param].vue create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/playwright.config.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/public/favicon.ico create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.client.config.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.server.config.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/param-error/[param].ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/server-error.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/test-param/[param].ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/server/tsconfig.json create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/start-event-proxy.mjs create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.client.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.server.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-3-min/tsconfig.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79fc0ff4a73c..3698fb38e495 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -938,6 +938,7 @@ jobs: 'node-koa', 'node-connect', 'nuxt-3', + 'nuxt-3-min', 'nuxt-4', 'vue-3', 'webpack-4', diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/.gitignore b/dev-packages/e2e-tests/test-applications/nuxt-3-min/.gitignore new file mode 100644 index 000000000000..4a7f73a2ed0d --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/.gitignore @@ -0,0 +1,24 @@ +# Nuxt dev/build outputs +.output +.data +.nuxt +.nitro +.cache +dist + +# Node dependencies +node_modules + +# Logs +logs +*.log + +# Misc +.DS_Store +.fleet +.idea + +# Local env files +.env +.env.* +!.env.example diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/.npmrc b/dev-packages/e2e-tests/test-applications/nuxt-3-min/.npmrc new file mode 100644 index 000000000000..070f80f05092 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/.npmrc @@ -0,0 +1,2 @@ +@sentry:registry=http://127.0.0.1:4873 +@sentry-internal:registry=http://127.0.0.1:4873 diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/app.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-min/app.vue new file mode 100644 index 000000000000..23283a522546 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/app.vue @@ -0,0 +1,17 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/components/ErrorButton.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-min/components/ErrorButton.vue new file mode 100644 index 000000000000..92ea714ae489 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/components/ErrorButton.vue @@ -0,0 +1,22 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/copyIITM.bash b/dev-packages/e2e-tests/test-applications/nuxt-3-min/copyIITM.bash new file mode 100644 index 000000000000..0e04d001c968 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/copyIITM.bash @@ -0,0 +1,7 @@ +# This script copies the `import-in-the-middle` content of the E2E test project root `node_modules` to the build output `node_modules` +# For some reason, some files are missing in the output (like `hook.mjs`) and this is not reproducible in external, standalone projects. +# +# Things we tried (that did not fix the problem): +# - Adding a resolution for `@vercel/nft` v0.27.0 (this worked in the standalone project) +# - Also adding `@vercel/nft` v0.27.0 to pnpm `peerDependencyRules` +cp -r node_modules/.pnpm/import-in-the-middle@1.*/node_modules/import-in-the-middle .output/server/node_modules/import-in-the-middle diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/nuxt.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/nuxt.config.ts new file mode 100644 index 000000000000..87e046ed39e9 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/nuxt.config.ts @@ -0,0 +1,20 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + modules: ['@sentry/nuxt/module'], + imports: { + autoImport: false, + }, + runtimeConfig: { + public: { + sentry: { + dsn: 'https://public@dsn.ingest.sentry.io/1337', + }, + }, + }, + nitro: { + rollupConfig: { + // @sentry/... is set external to prevent bundling all of Sentry into the `runtime.mjs` file in the build output + external: [/@sentry\/.*/], + }, + }, +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json b/dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json new file mode 100644 index 000000000000..18f798f89246 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json @@ -0,0 +1,30 @@ +{ + "name": "nuxt-3-min", + "description": "E2E test app for the minimum nuxt 3 version our nuxt SDK supports.", + "private": true, + "type": "module", + "scripts": { + "build": "nuxt build && bash ./copyIITM.bash", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "start": "node .output/server/index.mjs", + "clean": "npx nuxi cleanup", + "test": "playwright test", + "test:build": "pnpm install && npx playwright install && pnpm build", + "test:assert": "pnpm test" + }, + "dependencies": { + "@sentry/nuxt": "latest || *", + "nuxt": "3.13.2" + }, + "devDependencies": { + "@nuxt/test-utils": "^3.14.1", + "@playwright/test": "^1.44.1", + "@sentry-internal/test-utils": "link:../../../test-utils" + }, + "overrides": { + "nitropack": "2.9.7", + "@vercel/nft": "^0.27.4" + } +} diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/client-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/client-error.vue new file mode 100644 index 000000000000..d244ef773140 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/client-error.vue @@ -0,0 +1,11 @@ + + + + + + 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 new file mode 100644 index 000000000000..8cb2a9997e58 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/fetch-server-error.vue @@ -0,0 +1,13 @@ + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/index.vue b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/index.vue new file mode 100644 index 000000000000..74513c5697f3 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/index.vue @@ -0,0 +1,3 @@ + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/[param].vue b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/[param].vue new file mode 100644 index 000000000000..e83392b37b5c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/pages/test-param/[param].vue @@ -0,0 +1,23 @@ + + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/playwright.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/playwright.config.ts new file mode 100644 index 000000000000..aa1ff8e9743c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/playwright.config.ts @@ -0,0 +1,19 @@ +import { fileURLToPath } from 'node:url'; +import type { ConfigOptions } from '@nuxt/test-utils/playwright'; +import { getPlaywrightConfig } from '@sentry-internal/test-utils'; + +const nuxtConfigOptions: ConfigOptions = { + nuxt: { + rootDir: fileURLToPath(new URL('.', import.meta.url)), + }, +}; + +/* Make sure to import from '@nuxt/test-utils/playwright' in the tests + * Like this: import { expect, test } from '@nuxt/test-utils/playwright' */ + +const config = getPlaywrightConfig({ + startCommand: `pnpm start`, + use: { ...nuxtConfigOptions }, +}); + +export default config; diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/public/favicon.ico b/dev-packages/e2e-tests/test-applications/nuxt-3-min/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..18993ad91cfd43e03b074dd0b5cc3f37ab38e49c GIT binary patch literal 4286 zcmeHLOKuuL5PjK%MHWVi6lD zOGiREbCw`xmFozJ^aNatJY>w+g ze6a2@u~m#^BZm@8wco9#Crlli0uLb^3E$t2-WIc^#(?t)*@`UpuofJ(Uyh@F>b3Ph z$D^m8Xq~pTkGJ4Q`Q2)te3mgkWYZ^Ijq|hkiP^9`De={bQQ%heZC$QU2UpP(-tbl8 zPWD2abEew;oat@w`uP3J^YpsgT%~jT(Dk%oU}sa$7|n6hBjDj`+I;RX(>)%lm_7N{+B7Mu%H?422lE%MBJH!!YTN2oT7xr>>N-8OF$C&qU^ z>vLsa{$0X%q1fjOe3P1mCv#lN{xQ4_*HCSAZjTb1`}mlc+9rl8$B3OP%VT@mch_~G z7Y+4b{r>9e=M+7vSI;BgB?ryZDY4m>&wcHSn81VH1N~`0gvwH{ z8dv#hG|OK`>1;j7tM#B)Z7zDN?{6=dUal}$e { + throw new Error('Nuxt 3 Param Server error'); +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/server-error.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/server-error.ts new file mode 100644 index 000000000000..ec961a010510 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/server-error.ts @@ -0,0 +1,5 @@ +import { defineEventHandler } from '#imports'; + +export default defineEventHandler(event => { + throw new Error('Nuxt 3 Server error'); +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/test-param/[param].ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/test-param/[param].ts new file mode 100644 index 000000000000..1867874cd494 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/api/test-param/[param].ts @@ -0,0 +1,7 @@ +import { defineEventHandler, getRouterParam } from '#imports'; + +export default defineEventHandler(event => { + const param = getRouterParam(event, 'param'); + + return `Param: ${param}!`; +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/tsconfig.json b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/tsconfig.json new file mode 100644 index 000000000000..b9ed69c19eaf --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/server/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../.nuxt/tsconfig.server.json" +} diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/start-event-proxy.mjs b/dev-packages/e2e-tests/test-applications/nuxt-3-min/start-event-proxy.mjs new file mode 100644 index 000000000000..f7e78ea06418 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/start-event-proxy.mjs @@ -0,0 +1,6 @@ +import { startEventProxyServer } from '@sentry-internal/test-utils'; + +startEventProxyServer({ + port: 3031, + proxyServerName: 'nuxt-3-min', +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts new file mode 100644 index 000000000000..66f86755218e --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.client.test.ts @@ -0,0 +1,105 @@ +import { expect, test } from '@nuxt/test-utils/playwright'; +import { waitForError } from '@sentry-internal/test-utils'; + +test.describe('client-side errors', async () => { + test('captures error thrown on click', async ({ page }) => { + const errorPromise = waitForError('nuxt-3-min', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Nuxt-3-min E2E test app'; + }); + + await page.goto(`/client-error`); + await page.locator('#errorBtn').click(); + + const error = await errorPromise; + + expect(error.transaction).toEqual('/client-error'); + expect(error).toMatchObject({ + exception: { + values: [ + { + type: 'Error', + value: 'Error thrown from Nuxt-3-min E2E test app', + mechanism: { + handled: false, + }, + }, + ], + }, + }); + }); + + test('shows parametrized route on button error', async ({ page }) => { + const errorPromise = waitForError('nuxt-3-min', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Param Route Button'; + }); + + await page.goto(`/test-param/1234`); + await page.locator('#errorBtn').click(); + + const error = await errorPromise; + + expect(error.sdk.name).toEqual('sentry.javascript.nuxt'); + expect(error.transaction).toEqual('/test-param/:param()'); + expect(error.request.url).toMatch(/\/test-param\/1234/); + expect(error).toMatchObject({ + exception: { + values: [ + { + type: 'Error', + value: 'Error thrown from Param Route Button', + mechanism: { + handled: false, + }, + }, + ], + }, + }); + }); + + test('page is still interactive after client error', async ({ page }) => { + const error1Promise = waitForError('nuxt-3-min', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Nuxt-3-min E2E test app'; + }); + + await page.goto(`/client-error`); + await page.locator('#errorBtn').click(); + + const error1 = await error1Promise; + + const error2Promise = waitForError('nuxt-3-min', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Another Error thrown from Nuxt-3-min E2E test app'; + }); + + await page.locator('#errorBtn2').click(); + + const error2 = await error2Promise; + + expect(error1).toMatchObject({ + exception: { + values: [ + { + type: 'Error', + value: 'Error thrown from Nuxt-3-min E2E test app', + mechanism: { + handled: false, + }, + }, + ], + }, + }); + + expect(error2).toMatchObject({ + exception: { + values: [ + { + type: 'Error', + value: 'Another Error thrown from Nuxt-3-min E2E test app', + mechanism: { + handled: false, + }, + }, + ], + }, + }); + }); +}); 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 new file mode 100644 index 000000000000..8f20aa938893 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/errors.server.test.ts @@ -0,0 +1,40 @@ +import { expect, test } from '@playwright/test'; +import { waitForError } from '@sentry-internal/test-utils'; + +test.describe('server-side errors', async () => { + test('captures api fetch error (fetched on click)', async ({ page }) => { + const errorPromise = waitForError('nuxt-3-min', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Nuxt 3 Server error'; + }); + + await page.goto(`/fetch-server-error`); + await page.getByText('Fetch Server Data', { exact: true }).click(); + + const error = await errorPromise; + + expect(error.transaction).toEqual('GET /api/server-error'); + + const exception = error.exception.values[0]; + expect(exception.type).toEqual('Error'); + expect(exception.value).toEqual('Nuxt 3 Server error'); + expect(exception.mechanism.handled).toBe(false); + }); + + test('captures api fetch error (fetched on click) with parametrized route', async ({ page }) => { + const errorPromise = waitForError('nuxt-3-min', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Nuxt 3 Param Server error'; + }); + + await page.goto(`/test-param/1234`); + await page.getByRole('button', { name: 'Fetch Server Error', exact: true }).click(); + + const error = await errorPromise; + + expect(error.transaction).toEqual('GET /api/param-error/1234'); + + const exception = error.exception.values[0]; + expect(exception.type).toEqual('Error'); + expect(exception.value).toEqual('Nuxt 3 Param Server error'); + expect(exception.mechanism.handled).toBe(false); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.client.test.ts new file mode 100644 index 000000000000..9d0b3c694a1c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.client.test.ts @@ -0,0 +1,57 @@ +import { expect, test } from '@nuxt/test-utils/playwright'; +import { waitForTransaction } from '@sentry-internal/test-utils'; +import type { Span } from '@sentry/nuxt'; + +test('sends a pageload root span with a parameterized URL', async ({ page }) => { + const transactionPromise = waitForTransaction('nuxt-3-min', async transactionEvent => { + return transactionEvent.transaction === '/test-param/:param()'; + }); + + await page.goto(`/test-param/1234`); + + const rootSpan = await transactionPromise; + + expect(rootSpan).toMatchObject({ + contexts: { + trace: { + data: { + 'sentry.source': 'route', + 'sentry.origin': 'auto.pageload.vue', + 'sentry.op': 'pageload', + 'params.param': '1234', + }, + op: 'pageload', + origin: 'auto.pageload.vue', + }, + }, + transaction: '/test-param/:param()', + transaction_info: { + source: 'route', + }, + }); +}); + +test('sends component tracking spans when `trackComponents` is enabled', async ({ page }) => { + const transactionPromise = waitForTransaction('nuxt-3-min', async transactionEvent => { + return transactionEvent.transaction === '/client-error'; + }); + + await page.goto(`/client-error`); + + const rootSpan = await transactionPromise; + const errorButtonSpan = rootSpan.spans.find((span: Span) => span.description === 'Vue '); + + const expected = { + data: { 'sentry.origin': 'auto.ui.vue', 'sentry.op': 'ui.vue.mount' }, + description: 'Vue ', + op: 'ui.vue.mount', + parent_span_id: expect.any(String), + span_id: expect.any(String), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: expect.any(String), + origin: 'auto.ui.vue', + }; + + expect(errorButtonSpan).toMatchObject(expected); +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.server.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.server.test.ts new file mode 100644 index 000000000000..6f2085e38cd7 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.server.test.ts @@ -0,0 +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/core'; + +test('sends a server action transaction on pageload', async ({ page }) => { + const transactionPromise = waitForTransaction('nuxt-3-min', transactionEvent => { + return transactionEvent.transaction.includes('GET /test-param/'); + }); + + await page.goto('/test-param/1234'); + + const transaction = await transactionPromise; + + expect(transaction.contexts.trace).toEqual( + expect.objectContaining({ + data: expect.objectContaining({ + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.http', + }), + }), + ); +}); + +test('does not send transactions for build asset folder "_nuxt"', async ({ page }) => { + let buildAssetFolderOccurred = false; + + waitForTransaction('nuxt-3-min', transactionEvent => { + if (transactionEvent.transaction?.match(/^GET \/_nuxt\//)) { + buildAssetFolderOccurred = true; + } + return false; // expects to return a boolean (but not relevant here) + }); + + const transactionEventPromise = waitForTransaction('nuxt-3-min', transactionEvent => { + return transactionEvent.transaction.includes('GET /test-param/'); + }); + + await page.goto('/test-param/1234'); + + const transactionEvent = await transactionEventPromise; + + expect(buildAssetFolderOccurred).toBe(false); + + // todo: url not yet parametrized + expect(transactionEvent.transaction).toBe('GET /test-param/1234'); +}); 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 new file mode 100644 index 000000000000..b110f27843e2 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts @@ -0,0 +1,51 @@ +import { expect, test } from '@playwright/test'; +import { waitForTransaction } from '@sentry-internal/test-utils'; + +test.describe('distributed tracing', () => { + const PARAM = 's0me-param'; + + test('capture a distributed pageload trace', async ({ page }) => { + const clientTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => { + return txnEvent.transaction === '/test-param/:param()'; + }); + + const serverTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => { + return txnEvent.transaction.includes('GET /test-param/'); + }); + + const [_, clientTxnEvent, serverTxnEvent] = await Promise.all([ + page.goto(`/test-param/${PARAM}`), + clientTxnEventPromise, + serverTxnEventPromise, + expect(page.getByText(`Param: ${PARAM}`)).toBeVisible(), + ]); + + expect(clientTxnEvent).toMatchObject({ + transaction: '/test-param/:param()', + transaction_info: { source: 'route' }, + type: 'transaction', + contexts: { + trace: { + op: 'pageload', + origin: 'auto.pageload.vue', + }, + }, + }); + + expect(serverTxnEvent).toMatchObject({ + transaction: 'GET /test-param/s0me-param', // todo: parametrize (nitro) + transaction_info: { source: 'url' }, + type: 'transaction', + contexts: { + trace: { + op: 'http.server', + origin: 'auto.http.otel.http', + }, + }, + }); + + // connected trace + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverTxnEvent.contexts?.trace?.trace_id); + expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/tsconfig.json b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tsconfig.json new file mode 100644 index 000000000000..a746f2a70c28 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/tsconfig.json @@ -0,0 +1,4 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "extends": "./.nuxt/tsconfig.json" +} diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/package.json b/dev-packages/e2e-tests/test-applications/nuxt-3/package.json index 6c8eb1fcdd95..0b9654108d48 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@sentry/nuxt": "latest || *", - "nuxt": "3.13.1" + "nuxt": "^3.13.1" }, "devDependencies": { "@nuxt/test-utils": "^3.14.1",