From 958160a25593118d4a22cbe234b6169e2cf2c59f Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 20 Dec 2023 18:03:06 +0100 Subject: [PATCH 1/4] test(e2e): Add tests to SvelteKit 2.x test application --- .../sveltekit-2/event-proxy-server.ts | 4 +- .../sveltekit-2/package.json | 5 +- .../sveltekit-2/playwright.config.ts | 42 ++-- .../sveltekit-2/src/hooks.server.ts | 13 +- .../sveltekit-2/src/routes/+layout.svelte | 13 + .../sveltekit-2/src/routes/+page.svelte | 24 ++ .../src/routes/api/users/+server.ts | 3 + .../src/routes/client-error/+page.svelte | 9 + .../routes/server-load-error/+page.server.ts | 6 + .../src/routes/server-load-error/+page.svelte | 9 + .../routes/server-route-error/+page.svelte | 9 + .../src/routes/server-route-error/+page.ts | 7 + .../src/routes/server-route-error/+server.ts | 6 + .../routes/universal-load-error/+page.svelte | 17 ++ .../src/routes/universal-load-error/+page.ts | 8 + .../routes/universal-load-fetch/+page.svelte | 14 ++ .../src/routes/universal-load-fetch/+page.ts | 5 + .../src/routes/users/+page.server.ts | 5 + .../sveltekit-2/src/routes/users/+page.svelte | 10 + .../src/routes/users/[id]/+page.server.ts | 5 + .../src/routes/users/[id]/+page.svelte | 14 ++ .../sveltekit-2/start-event-proxy.ts | 4 +- .../sveltekit-2/test/errors.client.test.ts | 64 +++++ .../sveltekit-2/test/errors.server.test.ts | 77 ++++++ .../sveltekit-2/test/performance.test.ts | 225 ++++++++++++++++++ .../sveltekit-2/test/utils.ts | 59 +++++ 26 files changed, 625 insertions(+), 32 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+layout.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/client-error/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts index 66a9e744846e..9dee679c71e4 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts @@ -247,7 +247,7 @@ async function registerCallbackServerPort(serverName: string, port: string): Pro await writeFile(tmpFilePath, port, { encoding: 'utf8' }); } -async function retrieveCallbackServerPort(serverName: string): Promise { +function retrieveCallbackServerPort(serverName: string): Promise { const tmpFilePath = path.join(os.tmpdir(), `${TEMP_FILE_PREFIX}${serverName}`); - return await readFile(tmpFilePath, 'utf8'); + return readFile(tmpFilePath, 'utf8'); } diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json index b55d9ff74df6..9d35aecf3278 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json @@ -10,15 +10,14 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "test:prod": "TEST_ENV=production playwright test", - "test:dev": "TEST_ENV=development playwright test", "test:build": "pnpm install && pnpm build", - "test:assert": "pnpm -v" + "test:assert": "pnpm test:prod" }, "dependencies": { "@sentry/sveltekit": "latest || *" }, "devDependencies": { - "@playwright/test": "^1.27.1", + "@playwright/test": "^1.36.2", "@sentry/types": "latest || *", "@sentry/utils": "latest || *", "@sveltejs/adapter-auto": "^3.0.0", diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts index bfa29df7d549..05a7c48f0a9b 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts @@ -1,19 +1,25 @@ -import type { PlaywrightTestConfig } from '@playwright/test'; -import { devices } from '@playwright/test'; +import type { PlaywrightTestConfig } from "@playwright/test"; +import { devices } from "@playwright/test"; + +// Fix urls not resolving to localhost on Node v17+ +// See: https://github.com/axios/axios/issues/3821#issuecomment-1413727575 +import { setDefaultResultOrder } from "dns"; +setDefaultResultOrder("ipv4first"); const testEnv = process.env.TEST_ENV; if (!testEnv) { - throw new Error('No test env defined'); + throw new Error("No test env defined"); } -const port = 3030; +const svelteKitPort = 3030; +const eventProxyPort = 3031; /** * See https://playwright.dev/docs/test-configuration. */ const config: PlaywrightTestConfig = { - testDir: './test', + testDir: "./test", /* Maximum time one test can run for. */ timeout: 150_000, expect: { @@ -28,26 +34,26 @@ const config: PlaywrightTestConfig = { /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* `next dev` is incredibly buggy with the app dir */ - retries: testEnv === 'development' ? 3 : 0, + retries: testEnv === "development" ? 3 : 0, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'list', + reporter: "list", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ actionTimeout: 0, /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: `http://localhost:${port}`, + baseURL: `http://localhost:${svelteKitPort}`, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: "on-first-retry", }, /* Configure projects for major browsers */ projects: [ { - name: 'chromium', + name: "chromium", use: { - ...devices['Desktop Chrome'], + ...devices["Desktop Chrome"], }, }, ], @@ -55,15 +61,17 @@ const config: PlaywrightTestConfig = { /* Run your local dev server before starting the tests */ webServer: [ { - command: 'pnpm ts-node --esm start-event-proxy.ts', - port: 3031, + command: "pnpm ts-node-script start-event-proxy.ts", + port: eventProxyPort, + reuseExistingServer: false, }, { command: - testEnv === 'development' - ? `pnpm wait-port ${port} && pnpm dev --port ${port}` - : `pnpm wait-port ${port} && pnpm preview --port ${port}`, - port, + testEnv === "development" + ? `pnpm wait-port ${eventProxyPort} && pnpm dev --port ${svelteKitPort}` + : `pnpm wait-port ${eventProxyPort} && pnpm preview --port ${svelteKitPort}`, + port: svelteKitPort, + reuseExistingServer: false, }, ], }; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts index ae99e0e0e7b4..89336221fb07 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts @@ -1,18 +1,15 @@ -import { E2E_TEST_DSN } from '$env/static/private'; -import * as Sentry from '@sentry/sveltekit'; +import { E2E_TEST_DSN } from "$env/static/private"; +import * as Sentry from "@sentry/sveltekit"; Sentry.init({ - environment: 'qa', // dynamic sampling bias to keep transactions + environment: "qa", // dynamic sampling bias to keep transactions dsn: E2E_TEST_DSN, debug: true, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, }); -const myErrorHandler = ({ error, event }: any) => { - console.error('An error occurred on the server side:', error, event); -}; - -export const handleError = Sentry.handleErrorWithSentry(myErrorHandler); +// not logging anything to console to avoid noise in the test output +export const handleError = Sentry.handleErrorWithSentry(() => {}); export const handle = Sentry.sentryHandle(); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+layout.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+layout.svelte new file mode 100644 index 000000000000..08c4b6468a93 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+layout.svelte @@ -0,0 +1,13 @@ + + +

Sveltekit E2E Test app

+
+ +
diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte index 5982b0ae37dd..aeb12d58603f 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte @@ -1,2 +1,26 @@

Welcome to SvelteKit

Visit kit.svelte.dev to read the documentation

+ + diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts new file mode 100644 index 000000000000..dcfdc8ace297 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts @@ -0,0 +1,3 @@ +export const GET = () => { + return new Response(JSON.stringify({ users: ["alice", "bob", "carol"] })); +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/client-error/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/client-error/+page.svelte new file mode 100644 index 000000000000..ba6b464e9324 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/client-error/+page.svelte @@ -0,0 +1,9 @@ + + +

Client error

+ + diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts new file mode 100644 index 000000000000..706aa73ab3bb --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts @@ -0,0 +1,6 @@ +export const load = async () => { + throw new Error("Server Load Error"); + return { + msg: "Hello World", + }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.svelte new file mode 100644 index 000000000000..3a0942971d06 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.svelte @@ -0,0 +1,9 @@ + + +

Server load error

+ +

+ Message: {data.msg} +

diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.svelte new file mode 100644 index 000000000000..3d682e7e3462 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.svelte @@ -0,0 +1,9 @@ + + +

Server Route error

+ +

+ Message: {data.msg} +

diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts new file mode 100644 index 000000000000..d7b7e36fca91 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts @@ -0,0 +1,7 @@ +export const load = async ({ fetch }) => { + const res = await fetch("/server-route-error"); + const data = await res.json(); + return { + msg: data, + }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts new file mode 100644 index 000000000000..2c9aa3602633 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts @@ -0,0 +1,6 @@ +export const GET = async () => { + throw new Error("Server Route Error"); + return { + msg: "Hello World", + }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.svelte new file mode 100644 index 000000000000..dc2d311a0ece --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.svelte @@ -0,0 +1,17 @@ + + +

Universal load error

+ +

+ To trigger from client: Load on another route, then navigate to this route. +

+ +

+ To trigger from server: Load on this route +

+ +

+ Message: {data.msg} +

diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts new file mode 100644 index 000000000000..f77c42f766df --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts @@ -0,0 +1,8 @@ +import { browser } from "$app/environment"; + +export const load = async () => { + throw new Error(`Universal Load Error (${browser ? "browser" : "server"})`); + return { + msg: "Hello World", + }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.svelte new file mode 100644 index 000000000000..563c51e8c850 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.svelte @@ -0,0 +1,14 @@ + + +

Fetching in universal load

+ +

Here's a list of a few users:

+ +
    + {#each data.users as user} +
  • {user}
  • + {/each} +
diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts new file mode 100644 index 000000000000..18bcecabbf06 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts @@ -0,0 +1,5 @@ +export const load = async ({ fetch }) => { + const usersRes = await fetch("/api/users"); + const data = await usersRes.json(); + return { users: data.users }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts new file mode 100644 index 000000000000..786c4c0858b1 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts @@ -0,0 +1,5 @@ +export const load = async () => { + return { + msg: "Hi everyone!", + }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.svelte new file mode 100644 index 000000000000..aa804a4518fa --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.svelte @@ -0,0 +1,10 @@ + +

+ All Users: +

+ +

+ message: {data.msg} +

diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.server.ts new file mode 100644 index 000000000000..9388f3927018 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.server.ts @@ -0,0 +1,5 @@ +export const load = async ({ params }) => { + return { + msg: `This is a special message for user ${params.id}`, + }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.svelte new file mode 100644 index 000000000000..d348a8c57dad --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/[id]/+page.svelte @@ -0,0 +1,14 @@ + + +

Route with dynamic params

+ +

+ User id: {$page.params.id} +

+ +

+ Secret message for user: {data.msg} +

diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts index 3af64eb5960a..236066c73e3c 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts @@ -1,6 +1,6 @@ -import { startEventProxyServer } from './event-proxy-server'; +import { startEventProxyServer } from "./event-proxy-server"; startEventProxyServer({ port: 3031, - proxyServerName: 'sveltekit-2', + proxyServerName: "sveltekit-2", }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts new file mode 100644 index 000000000000..4c4cefc7dd44 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts @@ -0,0 +1,64 @@ +import { expect, test } from "@playwright/test"; +import { waitForError } from "../event-proxy-server"; +import { waitForInitialPageload } from "./utils"; + +test.describe("capturing client side errors", () => { + test("should capture error thrown on click", async ({ page }) => { + await page.goto("/client-error"); + + await expect(page.getByText("Client error")).toBeVisible(); + + const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { + return errorEvent?.exception?.values?.[0]?.value === "Click Error"; + }); + + const clickPromise = page.getByText("Throw error").click(); + + const [errorEvent, _] = await Promise.all([ + errorEventPromise, + clickPromise, + ]); + + const errorEventFrames = + errorEvent.exception?.values?.[0]?.stacktrace?.frames; + + expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( + expect.objectContaining({ + function: expect.stringContaining("HTMLButtonElement"), + lineno: 1, + in_app: true, + }), + ); + + expect(errorEvent.tags).toMatchObject({ runtime: "browser" }); + }); + + test("should capture universal load error", async ({ page }) => { + await waitForInitialPageload(page); + await page.reload(); + + const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { + return ( + errorEvent?.exception?.values?.[0]?.value === + "Universal Load Error (browser)" + ); + }); + + // navigating triggers the error on the client + await page.getByText("Universal Load error").click(); + + const errorEvent = await errorEventPromise; + const errorEventFrames = + errorEvent.exception?.values?.[0]?.stacktrace?.frames; + + const lastFrame = errorEventFrames?.[errorEventFrames?.length - 1]; + expect(lastFrame).toEqual( + expect.objectContaining({ + lineno: 1, + in_app: true, + }), + ); + + expect(errorEvent.tags).toMatchObject({ runtime: "browser" }); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts new file mode 100644 index 000000000000..cf7b6b8392c0 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts @@ -0,0 +1,77 @@ +import { expect, test } from "@playwright/test"; +import { waitForError } from "../event-proxy-server"; + +test.describe("capturing server side errors", () => { + test("should capture universal load error", async ({ page }) => { + const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { + return ( + errorEvent?.exception?.values?.[0]?.value === + "Universal Load Error (server)" + ); + }); + + await page.goto("/universal-load-error"); + + const errorEvent = await errorEventPromise; + const errorEventFrames = + errorEvent.exception?.values?.[0]?.stacktrace?.frames; + + expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( + expect.objectContaining({ + function: "load$1", + lineno: 3, + in_app: true, + }), + ); + + expect(errorEvent.tags).toMatchObject({ runtime: "node" }); + }); + + test("should capture server load error", async ({ page }) => { + const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { + return errorEvent?.exception?.values?.[0]?.value === "Server Load Error"; + }); + + await page.goto("/server-load-error"); + + const errorEvent = await errorEventPromise; + const errorEventFrames = + errorEvent.exception?.values?.[0]?.stacktrace?.frames; + + expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( + expect.objectContaining({ + function: "load$1", + lineno: 3, + in_app: true, + }), + ); + + expect(errorEvent.tags).toMatchObject({ runtime: "node" }); + }); + + test("should capture server route (GET) error", async ({ page }) => { + const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { + return errorEvent?.exception?.values?.[0]?.value === "Server Route Error"; + }); + + await page.goto("/server-route-error"); + + const errorEvent = await errorEventPromise; + const errorEventFrames = + errorEvent.exception?.values?.[0]?.stacktrace?.frames; + + expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( + expect.objectContaining({ + filename: "app:///_server.ts.js", + function: "GET", + lineno: 2, + in_app: true, + }), + ); + + expect(errorEvent.tags).toMatchObject({ + runtime: "node", + transaction: "GET /server-route-error", + }); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts new file mode 100644 index 000000000000..80e99d7b8e19 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts @@ -0,0 +1,225 @@ +import { expect, test } from "@playwright/test"; +import { waitForTransaction } from "../event-proxy-server"; +import { waitForInitialPageload } from "./utils"; + +test.describe("performance events", () => { + test("capture a distributed pageload trace", async ({ page }) => { + await page.goto("/users/123xyz"); + + const clientTxnEventPromise = waitForTransaction( + "sveltekit-2", + (txnEvent) => { + return txnEvent?.transaction === "/users/[id]"; + }, + ); + + const serverTxnEventPromise = waitForTransaction( + "sveltekit-2", + (txnEvent) => { + return txnEvent?.transaction === "GET /users/[id]"; + }, + ); + + const [clientTxnEvent, serverTxnEvent, _] = await Promise.all([ + clientTxnEventPromise, + serverTxnEventPromise, + expect(page.getByText("User id: 123xyz")).toBeVisible(), + ]); + + expect(clientTxnEvent).toMatchObject({ + transaction: "/users/[id]", + tags: { runtime: "browser" }, + transaction_info: { source: "route" }, + type: "transaction", + contexts: { + trace: { + op: "pageload", + origin: "auto.pageload.sveltekit", + }, + }, + }); + + expect(serverTxnEvent).toMatchObject({ + transaction: "GET /users/[id]", + tags: { runtime: "node" }, + transaction_info: { source: "route" }, + type: "transaction", + contexts: { + trace: { + op: "http.server", + origin: "auto.http.sveltekit", + }, + }, + }); + + expect(clientTxnEvent.spans?.length).toBeGreaterThan(5); + + // connected trace + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe( + serverTxnEvent.contexts?.trace?.trace_id, + ); + + // weird but server txn is parent of client txn + expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe( + serverTxnEvent.contexts?.trace?.span_id, + ); + }); + + test("capture a distributed navigation trace", async ({ page }) => { + await waitForInitialPageload(page); + + const clientNavigationTxnEventPromise = waitForTransaction( + "sveltekit-2", + (txnEvent) => { + return ( + txnEvent?.transaction === "/users" && + txnEvent.contexts?.trace?.op === "navigation" + ); + }, + ); + + const serverTxnEventPromise = waitForTransaction( + "sveltekit-2", + (txnEvent) => { + return txnEvent?.transaction === "GET /users"; + }, + ); + + // navigation to page + const clickPromise = page.getByText("Route with Server Load").click(); + + const [clientTxnEvent, serverTxnEvent, _1, _2] = await Promise.all([ + clientNavigationTxnEventPromise, + serverTxnEventPromise, + clickPromise, + expect(page.getByText("Hi everyone")).toBeVisible(), + ]); + + expect(clientTxnEvent).toMatchObject({ + transaction: "/users", + tags: { runtime: "browser" }, + transaction_info: { source: "route" }, + type: "transaction", + contexts: { + trace: { + op: "navigation", + origin: "auto.navigation.sveltekit", + }, + }, + }); + + expect(serverTxnEvent).toMatchObject({ + transaction: "GET /users", + tags: { runtime: "node" }, + transaction_info: { source: "route" }, + type: "transaction", + contexts: { + trace: { + op: "http.server", + origin: "auto.http.sveltekit", + }, + }, + }); + + // trace is connected + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe( + serverTxnEvent.contexts?.trace?.trace_id, + ); + }); + + test("record client-side universal load fetch span and trace", async ({ + page, + }) => { + await waitForInitialPageload(page); + + const clientNavigationTxnEventPromise = waitForTransaction( + "sveltekit-2", + (txnEvent) => { + return ( + txnEvent?.transaction === "/universal-load-fetch" && + txnEvent.contexts?.trace?.op === "navigation" + ); + }, + ); + + // this transaction should be created because of the fetch call + // it should also be part of the trace + const serverTxnEventPromise = waitForTransaction( + "sveltekit-2", + (txnEvent) => { + return txnEvent?.transaction === "GET /api/users"; + }, + ); + + // navigation to page + const clickPromise = page + .getByText("Route with fetch in universal load") + .click(); + + const [clientTxnEvent, serverTxnEvent, _1, _2] = await Promise.all([ + clientNavigationTxnEventPromise, + serverTxnEventPromise, + clickPromise, + expect(page.getByText("alice")).toBeVisible(), + ]); + + expect(clientTxnEvent).toMatchObject({ + transaction: "/universal-load-fetch", + tags: { runtime: "browser" }, + transaction_info: { source: "route" }, + type: "transaction", + contexts: { + trace: { + op: "navigation", + origin: "auto.navigation.sveltekit", + }, + }, + }); + + expect(serverTxnEvent).toMatchObject({ + transaction: "GET /api/users", + tags: { runtime: "node" }, + transaction_info: { source: "route" }, + type: "transaction", + contexts: { + trace: { + op: "http.server", + origin: "auto.http.sveltekit", + }, + }, + }); + + // trace is connected + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe( + serverTxnEvent.contexts?.trace?.trace_id, + ); + + const clientFetchSpan = clientTxnEvent.spans?.find( + (s) => s.op === "http.client", + ); + + expect(clientFetchSpan).toMatchObject({ + description: expect.stringMatching(/^GET.*\/api\/users/), + op: "http.client", + origin: "auto.http.browser", + data: { + url: expect.stringContaining("/api/users"), + type: "fetch", + "http.method": "GET", + "http.response.status_code": 200, + "network.protocol.version": "1.1", + "network.protocol.name": "http", + "http.request.redirect_start": expect.any(Number), + "http.request.fetch_start": expect.any(Number), + "http.request.domain_lookup_start": expect.any(Number), + "http.request.domain_lookup_end": expect.any(Number), + "http.request.connect_start": expect.any(Number), + "http.request.secure_connection_start": expect.any(Number), + "http.request.connection_end": expect.any(Number), + "http.request.request_start": expect.any(Number), + "http.request.response_start": expect.any(Number), + "http.request.response_end": expect.any(Number), + }, + }); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts new file mode 100644 index 000000000000..5c8470d4a5d2 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts @@ -0,0 +1,59 @@ +import { Page } from "@playwright/test"; +import { waitForTransaction } from "../event-proxy-server"; + +/** + * Helper function that waits for the initial pageload to complete. + * + * This function + * - loads the given route ("/" by default) + * - waits for SvelteKit's hydration + * - waits for the pageload transaction to be sent (doesn't assert on it though) + * + * Useful for tests that test outcomes of _navigations_ after an initial pageload. + * Waiting on the pageload transaction excludes edge cases where navigations occur + * so quickly that the pageload idle transaction is still active. This might lead + * to cases where the routing span would be attached to the pageload transaction + * and hence eliminates a lot of flakiness. + * + */ +export async function waitForInitialPageload( + page: Page, + opts?: { route?: string; parameterizedRoute?: string; debug: boolean }, +) { + const route = opts?.route ?? "/"; + const txnName = opts?.parameterizedRoute ?? route; + const debug = opts?.debug ?? false; + + const clientPageloadTxnEventPromise = waitForTransaction( + "sveltekit-2", + (txnEvent) => { + debug && + console.log({ + txn: txnEvent?.transaction, + op: txnEvent.contexts?.trace?.op, + trace: txnEvent.contexts?.trace?.trace_id, + span: txnEvent.contexts?.trace?.span_id, + parent: txnEvent.contexts?.trace?.parent_span_id, + }); + + return ( + txnEvent?.transaction === txnName && + txnEvent.contexts?.trace?.op === "pageload" + ); + }, + ); + + await Promise.all([ + page.goto(route), + // the test app adds the "hydrated" class to the body when hydrating + page.waitForSelector("body.hydrated"), + // also waiting for the initial pageload txn so that later navigations don't interfere + clientPageloadTxnEventPromise, + ]); + + // let's add a buffer because it seems like the hydrated flag isn't enough :( + // guess: The layout finishes hydration/mounting before the components within finish + await page.waitForTimeout(3000); + + debug && console.log("hydrated"); +} From be98a1bd2a18b3821291def9cd75b8039acfc548 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 21 Dec 2023 10:47:04 +0100 Subject: [PATCH 2/4] apply biome formatting --- .../sveltekit-2/playwright.config.ts | 26 +- .../sveltekit-2/src/hooks.server.ts | 6 +- .../src/routes/api/users/+server.ts | 2 +- .../src/routes/building/+page.svelte | 15 ++ .../routes/server-load-error/+page.server.ts | 4 +- .../src/routes/server-route-error/+page.ts | 2 +- .../src/routes/server-route-error/+server.ts | 4 +- .../src/routes/universal-load-error/+page.ts | 6 +- .../src/routes/universal-load-fetch/+page.ts | 2 +- .../src/routes/users/+page.server.ts | 2 +- .../sveltekit-2/start-event-proxy.ts | 4 +- .../sveltekit-2/test/errors.client.test.ts | 48 ++-- .../sveltekit-2/test/errors.server.test.ts | 58 ++--- .../sveltekit-2/test/performance.test.ts | 222 ++++++++---------- .../sveltekit-2/test/utils.ts | 38 ++- 15 files changed, 198 insertions(+), 241 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts index 05a7c48f0a9b..621102b6e479 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts @@ -1,15 +1,15 @@ -import type { PlaywrightTestConfig } from "@playwright/test"; -import { devices } from "@playwright/test"; +import type { PlaywrightTestConfig } from '@playwright/test'; +import { devices } from '@playwright/test'; // Fix urls not resolving to localhost on Node v17+ // See: https://github.com/axios/axios/issues/3821#issuecomment-1413727575 -import { setDefaultResultOrder } from "dns"; -setDefaultResultOrder("ipv4first"); +import { setDefaultResultOrder } from 'dns'; +setDefaultResultOrder('ipv4first'); const testEnv = process.env.TEST_ENV; if (!testEnv) { - throw new Error("No test env defined"); + throw new Error('No test env defined'); } const svelteKitPort = 3030; @@ -19,7 +19,7 @@ const eventProxyPort = 3031; * See https://playwright.dev/docs/test-configuration. */ const config: PlaywrightTestConfig = { - testDir: "./test", + testDir: './test', /* Maximum time one test can run for. */ timeout: 150_000, expect: { @@ -34,9 +34,9 @@ const config: PlaywrightTestConfig = { /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* `next dev` is incredibly buggy with the app dir */ - retries: testEnv === "development" ? 3 : 0, + retries: testEnv === 'development' ? 3 : 0, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: "list", + reporter: 'list', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ @@ -45,15 +45,15 @@ const config: PlaywrightTestConfig = { baseURL: `http://localhost:${svelteKitPort}`, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", + trace: 'on-first-retry', }, /* Configure projects for major browsers */ projects: [ { - name: "chromium", + name: 'chromium', use: { - ...devices["Desktop Chrome"], + ...devices['Desktop Chrome'], }, }, ], @@ -61,13 +61,13 @@ const config: PlaywrightTestConfig = { /* Run your local dev server before starting the tests */ webServer: [ { - command: "pnpm ts-node-script start-event-proxy.ts", + command: 'pnpm ts-node-script start-event-proxy.ts', port: eventProxyPort, reuseExistingServer: false, }, { command: - testEnv === "development" + testEnv === 'development' ? `pnpm wait-port ${eventProxyPort} && pnpm dev --port ${svelteKitPort}` : `pnpm wait-port ${eventProxyPort} && pnpm preview --port ${svelteKitPort}`, port: svelteKitPort, diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts index 89336221fb07..2a2abbb870dd 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts @@ -1,8 +1,8 @@ -import { E2E_TEST_DSN } from "$env/static/private"; -import * as Sentry from "@sentry/sveltekit"; +import { E2E_TEST_DSN } from '$env/static/private'; +import * as Sentry from '@sentry/sveltekit'; Sentry.init({ - environment: "qa", // dynamic sampling bias to keep transactions + environment: 'qa', // dynamic sampling bias to keep transactions dsn: E2E_TEST_DSN, debug: true, tunnel: `http://localhost:3031/`, // proxy server diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts index dcfdc8ace297..d0e4371c594b 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/api/users/+server.ts @@ -1,3 +1,3 @@ export const GET = () => { - return new Response(JSON.stringify({ users: ["alice", "bob", "carol"] })); + return new Response(JSON.stringify({ users: ['alice', 'bob', 'carol'] })); }; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/building/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/building/+page.svelte index fde274c60705..b27edb70053d 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/building/+page.svelte +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/building/+page.svelte @@ -1,3 +1,18 @@ + +

Check Build

diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts index 706aa73ab3bb..17dd53fb5bbb 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-error/+page.server.ts @@ -1,6 +1,6 @@ export const load = async () => { - throw new Error("Server Load Error"); + throw new Error('Server Load Error'); return { - msg: "Hello World", + msg: 'Hello World', }; }; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts index d7b7e36fca91..298240827714 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+page.ts @@ -1,5 +1,5 @@ export const load = async ({ fetch }) => { - const res = await fetch("/server-route-error"); + const res = await fetch('/server-route-error'); const data = await res.json(); return { msg: data, diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts index 2c9aa3602633..f1a4b94b7706 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-route-error/+server.ts @@ -1,6 +1,6 @@ export const GET = async () => { - throw new Error("Server Route Error"); + throw new Error('Server Route Error'); return { - msg: "Hello World", + msg: 'Hello World', }; }; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts index f77c42f766df..3d72bf4a890f 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-error/+page.ts @@ -1,8 +1,8 @@ -import { browser } from "$app/environment"; +import { browser } from '$app/environment'; export const load = async () => { - throw new Error(`Universal Load Error (${browser ? "browser" : "server"})`); + throw new Error(`Universal Load Error (${browser ? 'browser' : 'server'})`); return { - msg: "Hello World", + msg: 'Hello World', }; }; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts index 18bcecabbf06..63c1ee68e1cb 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/universal-load-fetch/+page.ts @@ -1,5 +1,5 @@ export const load = async ({ fetch }) => { - const usersRes = await fetch("/api/users"); + const usersRes = await fetch('/api/users'); const data = await usersRes.json(); return { users: data.users }; }; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts index 786c4c0858b1..a34c5450f682 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/users/+page.server.ts @@ -1,5 +1,5 @@ export const load = async () => { return { - msg: "Hi everyone!", + msg: 'Hi everyone!', }; }; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts index 236066c73e3c..3af64eb5960a 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/start-event-proxy.ts @@ -1,6 +1,6 @@ -import { startEventProxyServer } from "./event-proxy-server"; +import { startEventProxyServer } from './event-proxy-server'; startEventProxyServer({ port: 3031, - proxyServerName: "sveltekit-2", + proxyServerName: 'sveltekit-2', }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts index 4c4cefc7dd44..85b3c0b6ffd0 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts @@ -1,55 +1,47 @@ -import { expect, test } from "@playwright/test"; -import { waitForError } from "../event-proxy-server"; -import { waitForInitialPageload } from "./utils"; +import { expect, test } from '@playwright/test'; +import { waitForError } from '../event-proxy-server'; +import { waitForInitialPageload } from './utils'; -test.describe("capturing client side errors", () => { - test("should capture error thrown on click", async ({ page }) => { - await page.goto("/client-error"); +test.describe('capturing client side errors', () => { + test('should capture error thrown on click', async ({ page }) => { + await page.goto('/client-error'); - await expect(page.getByText("Client error")).toBeVisible(); + await expect(page.getByText('Client error')).toBeVisible(); - const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { - return errorEvent?.exception?.values?.[0]?.value === "Click Error"; + const errorEventPromise = waitForError('sveltekit-2', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Click Error'; }); - const clickPromise = page.getByText("Throw error").click(); + const clickPromise = page.getByText('Throw error').click(); - const [errorEvent, _] = await Promise.all([ - errorEventPromise, - clickPromise, - ]); + const [errorEvent, _] = await Promise.all([errorEventPromise, clickPromise]); - const errorEventFrames = - errorEvent.exception?.values?.[0]?.stacktrace?.frames; + const errorEventFrames = errorEvent.exception?.values?.[0]?.stacktrace?.frames; expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ - function: expect.stringContaining("HTMLButtonElement"), + function: expect.stringContaining('HTMLButtonElement'), lineno: 1, in_app: true, }), ); - expect(errorEvent.tags).toMatchObject({ runtime: "browser" }); + expect(errorEvent.tags).toMatchObject({ runtime: 'browser' }); }); - test("should capture universal load error", async ({ page }) => { + test('should capture universal load error', async ({ page }) => { await waitForInitialPageload(page); await page.reload(); - const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { - return ( - errorEvent?.exception?.values?.[0]?.value === - "Universal Load Error (browser)" - ); + const errorEventPromise = waitForError('sveltekit-2', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Universal Load Error (browser)'; }); // navigating triggers the error on the client - await page.getByText("Universal Load error").click(); + await page.getByText('Universal Load error').click(); const errorEvent = await errorEventPromise; - const errorEventFrames = - errorEvent.exception?.values?.[0]?.stacktrace?.frames; + const errorEventFrames = errorEvent.exception?.values?.[0]?.stacktrace?.frames; const lastFrame = errorEventFrames?.[errorEventFrames?.length - 1]; expect(lastFrame).toEqual( @@ -59,6 +51,6 @@ test.describe("capturing client side errors", () => { }), ); - expect(errorEvent.tags).toMatchObject({ runtime: "browser" }); + expect(errorEvent.tags).toMatchObject({ runtime: 'browser' }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts index cf7b6b8392c0..813057b2907a 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts @@ -1,77 +1,71 @@ -import { expect, test } from "@playwright/test"; -import { waitForError } from "../event-proxy-server"; +import { expect, test } from '@playwright/test'; +import { waitForError } from '../event-proxy-server'; -test.describe("capturing server side errors", () => { - test("should capture universal load error", async ({ page }) => { - const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { - return ( - errorEvent?.exception?.values?.[0]?.value === - "Universal Load Error (server)" - ); +test.describe('capturing server side errors', () => { + test('should capture universal load error', async ({ page }) => { + const errorEventPromise = waitForError('sveltekit-2', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Universal Load Error (server)'; }); - await page.goto("/universal-load-error"); + await page.goto('/universal-load-error'); const errorEvent = await errorEventPromise; - const errorEventFrames = - errorEvent.exception?.values?.[0]?.stacktrace?.frames; + const errorEventFrames = errorEvent.exception?.values?.[0]?.stacktrace?.frames; expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ - function: "load$1", + function: 'load$1', lineno: 3, in_app: true, }), ); - expect(errorEvent.tags).toMatchObject({ runtime: "node" }); + expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); }); - test("should capture server load error", async ({ page }) => { - const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { - return errorEvent?.exception?.values?.[0]?.value === "Server Load Error"; + test('should capture server load error', async ({ page }) => { + const errorEventPromise = waitForError('sveltekit-2', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Server Load Error'; }); - await page.goto("/server-load-error"); + await page.goto('/server-load-error'); const errorEvent = await errorEventPromise; - const errorEventFrames = - errorEvent.exception?.values?.[0]?.stacktrace?.frames; + const errorEventFrames = errorEvent.exception?.values?.[0]?.stacktrace?.frames; expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ - function: "load$1", + function: 'load$1', lineno: 3, in_app: true, }), ); - expect(errorEvent.tags).toMatchObject({ runtime: "node" }); + expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); }); - test("should capture server route (GET) error", async ({ page }) => { - const errorEventPromise = waitForError("sveltekit-2", (errorEvent) => { - return errorEvent?.exception?.values?.[0]?.value === "Server Route Error"; + test('should capture server route (GET) error', async ({ page }) => { + const errorEventPromise = waitForError('sveltekit-2', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Server Route Error'; }); - await page.goto("/server-route-error"); + await page.goto('/server-route-error'); const errorEvent = await errorEventPromise; - const errorEventFrames = - errorEvent.exception?.values?.[0]?.stacktrace?.frames; + const errorEventFrames = errorEvent.exception?.values?.[0]?.stacktrace?.frames; expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ - filename: "app:///_server.ts.js", - function: "GET", + filename: 'app:///_server.ts.js', + function: 'GET', lineno: 2, in_app: true, }), ); expect(errorEvent.tags).toMatchObject({ - runtime: "node", - transaction: "GET /server-route-error", + runtime: 'node', + transaction: 'GET /server-route-error', }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts index 80e99d7b8e19..aed2040392e7 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.test.ts @@ -1,53 +1,47 @@ -import { expect, test } from "@playwright/test"; -import { waitForTransaction } from "../event-proxy-server"; -import { waitForInitialPageload } from "./utils"; - -test.describe("performance events", () => { - test("capture a distributed pageload trace", async ({ page }) => { - await page.goto("/users/123xyz"); - - const clientTxnEventPromise = waitForTransaction( - "sveltekit-2", - (txnEvent) => { - return txnEvent?.transaction === "/users/[id]"; - }, - ); +import { expect, test } from '@playwright/test'; +import { waitForTransaction } from '../event-proxy-server'; +import { waitForInitialPageload } from './utils'; - const serverTxnEventPromise = waitForTransaction( - "sveltekit-2", - (txnEvent) => { - return txnEvent?.transaction === "GET /users/[id]"; - }, - ); +test.describe('performance events', () => { + test('capture a distributed pageload trace', async ({ page }) => { + await page.goto('/users/123xyz'); + + const clientTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + return txnEvent?.transaction === '/users/[id]'; + }); + + const serverTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + return txnEvent?.transaction === 'GET /users/[id]'; + }); const [clientTxnEvent, serverTxnEvent, _] = await Promise.all([ clientTxnEventPromise, serverTxnEventPromise, - expect(page.getByText("User id: 123xyz")).toBeVisible(), + expect(page.getByText('User id: 123xyz')).toBeVisible(), ]); expect(clientTxnEvent).toMatchObject({ - transaction: "/users/[id]", - tags: { runtime: "browser" }, - transaction_info: { source: "route" }, - type: "transaction", + transaction: '/users/[id]', + tags: { runtime: 'browser' }, + transaction_info: { source: 'route' }, + type: 'transaction', contexts: { trace: { - op: "pageload", - origin: "auto.pageload.sveltekit", + op: 'pageload', + origin: 'auto.pageload.sveltekit', }, }, }); expect(serverTxnEvent).toMatchObject({ - transaction: "GET /users/[id]", - tags: { runtime: "node" }, - transaction_info: { source: "route" }, - type: "transaction", + transaction: 'GET /users/[id]', + tags: { runtime: 'node' }, + transaction_info: { source: 'route' }, + type: 'transaction', contexts: { trace: { - op: "http.server", - origin: "auto.http.sveltekit", + op: 'http.server', + origin: 'auto.http.sveltekit', }, }, }); @@ -55,170 +49,138 @@ test.describe("performance events", () => { expect(clientTxnEvent.spans?.length).toBeGreaterThan(5); // connected trace - expect(clientTxnEvent.contexts?.trace?.trace_id).toBe( - serverTxnEvent.contexts?.trace?.trace_id, - ); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverTxnEvent.contexts?.trace?.trace_id); // weird but server txn is parent of client txn - expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe( - serverTxnEvent.contexts?.trace?.span_id, - ); + expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id); }); - test("capture a distributed navigation trace", async ({ page }) => { + test('capture a distributed navigation trace', async ({ page }) => { await waitForInitialPageload(page); - const clientNavigationTxnEventPromise = waitForTransaction( - "sveltekit-2", - (txnEvent) => { - return ( - txnEvent?.transaction === "/users" && - txnEvent.contexts?.trace?.op === "navigation" - ); - }, - ); + const clientNavigationTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + return txnEvent?.transaction === '/users' && txnEvent.contexts?.trace?.op === 'navigation'; + }); - const serverTxnEventPromise = waitForTransaction( - "sveltekit-2", - (txnEvent) => { - return txnEvent?.transaction === "GET /users"; - }, - ); + const serverTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + return txnEvent?.transaction === 'GET /users'; + }); // navigation to page - const clickPromise = page.getByText("Route with Server Load").click(); + const clickPromise = page.getByText('Route with Server Load').click(); const [clientTxnEvent, serverTxnEvent, _1, _2] = await Promise.all([ clientNavigationTxnEventPromise, serverTxnEventPromise, clickPromise, - expect(page.getByText("Hi everyone")).toBeVisible(), + expect(page.getByText('Hi everyone')).toBeVisible(), ]); expect(clientTxnEvent).toMatchObject({ - transaction: "/users", - tags: { runtime: "browser" }, - transaction_info: { source: "route" }, - type: "transaction", + transaction: '/users', + tags: { runtime: 'browser' }, + transaction_info: { source: 'route' }, + type: 'transaction', contexts: { trace: { - op: "navigation", - origin: "auto.navigation.sveltekit", + op: 'navigation', + origin: 'auto.navigation.sveltekit', }, }, }); expect(serverTxnEvent).toMatchObject({ - transaction: "GET /users", - tags: { runtime: "node" }, - transaction_info: { source: "route" }, - type: "transaction", + transaction: 'GET /users', + tags: { runtime: 'node' }, + transaction_info: { source: 'route' }, + type: 'transaction', contexts: { trace: { - op: "http.server", - origin: "auto.http.sveltekit", + op: 'http.server', + origin: 'auto.http.sveltekit', }, }, }); // trace is connected - expect(clientTxnEvent.contexts?.trace?.trace_id).toBe( - serverTxnEvent.contexts?.trace?.trace_id, - ); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverTxnEvent.contexts?.trace?.trace_id); }); - test("record client-side universal load fetch span and trace", async ({ - page, - }) => { + test('record client-side universal load fetch span and trace', async ({ page }) => { await waitForInitialPageload(page); - const clientNavigationTxnEventPromise = waitForTransaction( - "sveltekit-2", - (txnEvent) => { - return ( - txnEvent?.transaction === "/universal-load-fetch" && - txnEvent.contexts?.trace?.op === "navigation" - ); - }, - ); + const clientNavigationTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + return txnEvent?.transaction === '/universal-load-fetch' && txnEvent.contexts?.trace?.op === 'navigation'; + }); // this transaction should be created because of the fetch call // it should also be part of the trace - const serverTxnEventPromise = waitForTransaction( - "sveltekit-2", - (txnEvent) => { - return txnEvent?.transaction === "GET /api/users"; - }, - ); + const serverTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + return txnEvent?.transaction === 'GET /api/users'; + }); // navigation to page - const clickPromise = page - .getByText("Route with fetch in universal load") - .click(); + const clickPromise = page.getByText('Route with fetch in universal load').click(); const [clientTxnEvent, serverTxnEvent, _1, _2] = await Promise.all([ clientNavigationTxnEventPromise, serverTxnEventPromise, clickPromise, - expect(page.getByText("alice")).toBeVisible(), + expect(page.getByText('alice')).toBeVisible(), ]); expect(clientTxnEvent).toMatchObject({ - transaction: "/universal-load-fetch", - tags: { runtime: "browser" }, - transaction_info: { source: "route" }, - type: "transaction", + transaction: '/universal-load-fetch', + tags: { runtime: 'browser' }, + transaction_info: { source: 'route' }, + type: 'transaction', contexts: { trace: { - op: "navigation", - origin: "auto.navigation.sveltekit", + op: 'navigation', + origin: 'auto.navigation.sveltekit', }, }, }); expect(serverTxnEvent).toMatchObject({ - transaction: "GET /api/users", - tags: { runtime: "node" }, - transaction_info: { source: "route" }, - type: "transaction", + transaction: 'GET /api/users', + tags: { runtime: 'node' }, + transaction_info: { source: 'route' }, + type: 'transaction', contexts: { trace: { - op: "http.server", - origin: "auto.http.sveltekit", + op: 'http.server', + origin: 'auto.http.sveltekit', }, }, }); // trace is connected - expect(clientTxnEvent.contexts?.trace?.trace_id).toBe( - serverTxnEvent.contexts?.trace?.trace_id, - ); + expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverTxnEvent.contexts?.trace?.trace_id); - const clientFetchSpan = clientTxnEvent.spans?.find( - (s) => s.op === "http.client", - ); + const clientFetchSpan = clientTxnEvent.spans?.find(s => s.op === 'http.client'); expect(clientFetchSpan).toMatchObject({ description: expect.stringMatching(/^GET.*\/api\/users/), - op: "http.client", - origin: "auto.http.browser", + op: 'http.client', + origin: 'auto.http.browser', data: { - url: expect.stringContaining("/api/users"), - type: "fetch", - "http.method": "GET", - "http.response.status_code": 200, - "network.protocol.version": "1.1", - "network.protocol.name": "http", - "http.request.redirect_start": expect.any(Number), - "http.request.fetch_start": expect.any(Number), - "http.request.domain_lookup_start": expect.any(Number), - "http.request.domain_lookup_end": expect.any(Number), - "http.request.connect_start": expect.any(Number), - "http.request.secure_connection_start": expect.any(Number), - "http.request.connection_end": expect.any(Number), - "http.request.request_start": expect.any(Number), - "http.request.response_start": expect.any(Number), - "http.request.response_end": expect.any(Number), + url: expect.stringContaining('/api/users'), + type: 'fetch', + 'http.method': 'GET', + 'http.response.status_code': 200, + 'network.protocol.version': '1.1', + 'network.protocol.name': 'http', + 'http.request.redirect_start': expect.any(Number), + 'http.request.fetch_start': expect.any(Number), + 'http.request.domain_lookup_start': expect.any(Number), + 'http.request.domain_lookup_end': expect.any(Number), + 'http.request.connect_start': expect.any(Number), + 'http.request.secure_connection_start': expect.any(Number), + 'http.request.connection_end': expect.any(Number), + 'http.request.request_start': expect.any(Number), + 'http.request.response_start': expect.any(Number), + 'http.request.response_end': expect.any(Number), }, }); }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts index 5c8470d4a5d2..8c84b547b279 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts @@ -1,5 +1,5 @@ -import { Page } from "@playwright/test"; -import { waitForTransaction } from "../event-proxy-server"; +import { Page } from '@playwright/test'; +import { waitForTransaction } from '../event-proxy-server'; /** * Helper function that waits for the initial pageload to complete. @@ -20,33 +20,27 @@ export async function waitForInitialPageload( page: Page, opts?: { route?: string; parameterizedRoute?: string; debug: boolean }, ) { - const route = opts?.route ?? "/"; + const route = opts?.route ?? '/'; const txnName = opts?.parameterizedRoute ?? route; const debug = opts?.debug ?? false; - const clientPageloadTxnEventPromise = waitForTransaction( - "sveltekit-2", - (txnEvent) => { - debug && - console.log({ - txn: txnEvent?.transaction, - op: txnEvent.contexts?.trace?.op, - trace: txnEvent.contexts?.trace?.trace_id, - span: txnEvent.contexts?.trace?.span_id, - parent: txnEvent.contexts?.trace?.parent_span_id, - }); + const clientPageloadTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + debug && + console.log({ + txn: txnEvent?.transaction, + op: txnEvent.contexts?.trace?.op, + trace: txnEvent.contexts?.trace?.trace_id, + span: txnEvent.contexts?.trace?.span_id, + parent: txnEvent.contexts?.trace?.parent_span_id, + }); - return ( - txnEvent?.transaction === txnName && - txnEvent.contexts?.trace?.op === "pageload" - ); - }, - ); + return txnEvent?.transaction === txnName && txnEvent.contexts?.trace?.op === 'pageload'; + }); await Promise.all([ page.goto(route), // the test app adds the "hydrated" class to the body when hydrating - page.waitForSelector("body.hydrated"), + page.waitForSelector('body.hydrated'), // also waiting for the initial pageload txn so that later navigations don't interfere clientPageloadTxnEventPromise, ]); @@ -55,5 +49,5 @@ export async function waitForInitialPageload( // guess: The layout finishes hydration/mounting before the components within finish await page.waitForTimeout(3000); - debug && console.log("hydrated"); + debug && console.log('hydrated'); } From eb328eaa0be48265f6ac7f4cf24d1bd9256d9c73 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 21 Dec 2023 10:53:05 +0100 Subject: [PATCH 3/4] adjust build cmd --- .../e2e-tests/test-applications/sveltekit-2/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json index 9d35aecf3278..8f75f5b53d37 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json @@ -10,7 +10,7 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "test:prod": "TEST_ENV=production playwright test", - "test:build": "pnpm install && pnpm build", + "test:build": "pnpm install && npx playwright install && pnpm build", "test:assert": "pnpm test:prod" }, "dependencies": { From 8d436c8f7ce1485faa6389c556500144fb66b0b1 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 31 Jan 2024 15:39:10 +0100 Subject: [PATCH 4/4] finalize tests and config --- .../sveltekit-2/event-proxy-server.ts | 18 +++---- .../sveltekit-2/package.json | 2 +- .../sveltekit-2/playwright.config.ts | 5 +- .../sveltekit-2/src/app.html | 2 +- .../sveltekit-2/test/errors.client.test.ts | 6 +-- .../sveltekit-2/test/errors.server.test.ts | 13 ++--- .../sveltekit-2/test/transaction.test.ts | 48 ------------------- .../sveltekit-2/test/utils.ts | 4 -- 8 files changed, 22 insertions(+), 76 deletions(-) delete mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/test/transaction.test.ts diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts index 9dee679c71e4..4c2df32399f0 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/event-proxy-server.ts @@ -6,7 +6,7 @@ import * as os from 'os'; import * as path from 'path'; import * as util from 'util'; import * as zlib from 'zlib'; -import type { Envelope, EnvelopeItem, Event } from '@sentry/types'; +import type { Envelope, EnvelopeItem, SerializedEvent } from '@sentry/types'; import { parseEnvelope } from '@sentry/utils'; const readFile = util.promisify(fs.readFile); @@ -210,13 +210,13 @@ export function waitForEnvelopeItem( export function waitForError( proxyServerName: string, - callback: (transactionEvent: Event) => Promise | boolean, -): Promise { + callback: (transactionEvent: SerializedEvent) => Promise | boolean, +): Promise { return new Promise((resolve, reject) => { waitForEnvelopeItem(proxyServerName, async envelopeItem => { const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'event' && (await callback(envelopeItemBody as Event))) { - resolve(envelopeItemBody as Event); + if (envelopeItemHeader.type === 'event' && (await callback(envelopeItemBody as SerializedEvent))) { + resolve(envelopeItemBody as SerializedEvent); return true; } return false; @@ -226,13 +226,13 @@ export function waitForError( export function waitForTransaction( proxyServerName: string, - callback: (transactionEvent: Event) => Promise | boolean, -): Promise { + callback: (transactionEvent: SerializedEvent) => Promise | boolean, +): Promise { return new Promise((resolve, reject) => { waitForEnvelopeItem(proxyServerName, async envelopeItem => { const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'transaction' && (await callback(envelopeItemBody as Event))) { - resolve(envelopeItemBody as Event); + if (envelopeItemHeader.type === 'transaction' && (await callback(envelopeItemBody as SerializedEvent))) { + resolve(envelopeItemBody as SerializedEvent); return true; } return false; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json index 8f75f5b53d37..a323c3c415be 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json @@ -22,7 +22,7 @@ "@sentry/utils": "latest || *", "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-node": "^2.0.0", - "@sveltejs/kit": "^2.0.0", + "@sveltejs/kit": "^2.5.0", "@sveltejs/vite-plugin-svelte": "^3.0.0", "svelte": "^4.2.8", "svelte-check": "^3.6.0", diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts index 621102b6e479..5e028dc2e29a 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/playwright.config.ts @@ -30,7 +30,8 @@ const config: PlaywrightTestConfig = { timeout: 10000, }, /* Run tests in files in parallel */ - fullyParallel: true, + fullyParallel: false, + workers: 1, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* `next dev` is incredibly buggy with the app dir */ @@ -69,7 +70,7 @@ const config: PlaywrightTestConfig = { command: testEnv === 'development' ? `pnpm wait-port ${eventProxyPort} && pnpm dev --port ${svelteKitPort}` - : `pnpm wait-port ${eventProxyPort} && pnpm preview --port ${svelteKitPort}`, + : `pnpm wait-port ${eventProxyPort} && PORT=${svelteKitPort} node build`, port: svelteKitPort, reuseExistingServer: false, }, diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/app.html b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/app.html index 117bd026151a..435cf39f2268 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/app.html +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/app.html @@ -6,7 +6,7 @@ %sveltekit.head% - +

%sveltekit.body%
diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts index 85b3c0b6ffd0..7942b96b41b0 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.client.test.ts @@ -2,8 +2,8 @@ import { expect, test } from '@playwright/test'; import { waitForError } from '../event-proxy-server'; import { waitForInitialPageload } from './utils'; -test.describe('capturing client side errors', () => { - test('should capture error thrown on click', async ({ page }) => { +test.describe('client-side errors', () => { + test('captures error thrown on click', async ({ page }) => { await page.goto('/client-error'); await expect(page.getByText('Client error')).toBeVisible(); @@ -29,7 +29,7 @@ test.describe('capturing client side errors', () => { expect(errorEvent.tags).toMatchObject({ runtime: 'browser' }); }); - test('should capture universal load error', async ({ page }) => { + test('captures universal load error', async ({ page }) => { await waitForInitialPageload(page); await page.reload(); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts index 813057b2907a..b7966325560a 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts @@ -1,8 +1,8 @@ import { expect, test } from '@playwright/test'; import { waitForError } from '../event-proxy-server'; -test.describe('capturing server side errors', () => { - test('should capture universal load error', async ({ page }) => { +test.describe('server-side errors', () => { + test('captures universal load error', async ({ page }) => { const errorEventPromise = waitForError('sveltekit-2', errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Universal Load Error (server)'; }); @@ -15,7 +15,6 @@ test.describe('capturing server side errors', () => { expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ function: 'load$1', - lineno: 3, in_app: true, }), ); @@ -23,7 +22,7 @@ test.describe('capturing server side errors', () => { expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); }); - test('should capture server load error', async ({ page }) => { + test('captures server load error', async ({ page }) => { const errorEventPromise = waitForError('sveltekit-2', errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Server Load Error'; }); @@ -36,7 +35,6 @@ test.describe('capturing server side errors', () => { expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ function: 'load$1', - lineno: 3, in_app: true, }), ); @@ -44,7 +42,7 @@ test.describe('capturing server side errors', () => { expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); }); - test('should capture server route (GET) error', async ({ page }) => { + test('captures server route (GET) error', async ({ page }) => { const errorEventPromise = waitForError('sveltekit-2', errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Server Route Error'; }); @@ -56,9 +54,8 @@ test.describe('capturing server side errors', () => { expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ - filename: 'app:///_server.ts.js', + filename: expect.stringContaining('app:///_server.ts'), function: 'GET', - lineno: 2, in_app: true, }), ); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/transaction.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/transaction.test.ts deleted file mode 100644 index 7d621af34dcf..000000000000 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/transaction.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { expect, test } from '@playwright/test'; -import axios, { AxiosError } from 'axios'; -// @ts-expect-error ok ok -import { waitForTransaction } from '../event-proxy-server.ts'; - -const authToken = process.env.E2E_TEST_AUTH_TOKEN; -const sentryTestOrgSlug = process.env.E2E_TEST_SENTRY_ORG_SLUG; -const sentryTestProject = process.env.E2E_TEST_SENTRY_TEST_PROJECT; -const EVENT_POLLING_TIMEOUT = 90_000; - -test('Sends a pageload transaction', async ({ page }) => { - const pageloadTransactionEventPromise = waitForTransaction('sveltekit', (transactionEvent: any) => { - return transactionEvent?.contexts?.trace?.op === 'pageload' && transactionEvent?.transaction === '/'; - }); - - await page.goto('/'); - - const transactionEvent = await pageloadTransactionEventPromise; - const transactionEventId = transactionEvent.event_id; - - await expect - .poll( - async () => { - try { - const response = await axios.get( - `https://sentry.io/api/0/projects/${sentryTestOrgSlug}/${sentryTestProject}/events/${transactionEventId}/`, - { headers: { Authorization: `Bearer ${authToken}` } }, - ); - - return response.status; - } catch (e) { - if (e instanceof AxiosError && e.response) { - if (e.response.status !== 404) { - throw e; - } else { - return e.response.status; - } - } else { - throw e; - } - } - }, - { - timeout: EVENT_POLLING_TIMEOUT, - }, - ) - .toBe(200); -}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts index 8c84b547b279..b48b949abdd5 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/utils.ts @@ -45,9 +45,5 @@ export async function waitForInitialPageload( clientPageloadTxnEventPromise, ]); - // let's add a buffer because it seems like the hydrated flag isn't enough :( - // guess: The layout finishes hydration/mounting before the components within finish - await page.waitForTimeout(3000); - debug && console.log('hydrated'); }