SvelteKit 2 + Svelte 5 组合下的 Sentry E2E 测试应用:sentry-javascript 如何验证 @sentry/sveltekit SDK
可观测性【免费下载链接】sentry-javascriptOfficial Sentry SDKs for JavaScript项目地址https://gitcode.com/gh_mirrors/se/sentry-javascript点击查看免费下载本文以dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/目录下的 README 为骨架讲清这个基于 create-svelte 脚手架搭建的 SvelteKit 2 Svelte 5 项目如何创建、开发与构建并结合仓库源码深入剖析它在 Sentry JavaScript SDK 仓库中的真实角色——作为sentry/sveltekit包在最新 Svelte 大版本下的端到端E2E回归验证目标。读完本文你既能复现该应用的运行流程也能理解其 hooks 初始化、Vite 插件、Playwright 测试与事件代理服务器之间的完整链路。README 的原貌一个标准的 create-svelte 脚手架项目该应用的 README.md 本身是 create-svelte 脚手架生成的标准模板它声明了这是一个由 create-svelte 驱动的 Svelte 项目并给出三类基础操作命令。创建项目README 中保留的原始创建方式为# 在当前目录创建新项目 npm create sveltelatest # 在 my-app 目录中创建新项目 npm create sveltelatest my-app不过在本仓库中这个应用并不是每次用脚手架重新生成的而是已经以固定形态提交在test-applications/sveltekit-2-svelte-5/目录下。它的技术栈组合可以从 package.json 中精确读出依赖版本角色sveltejs/kit2.69.1SvelteKit 2 框架本体锁定的具体版本svelte^5.0.0-next.115Svelte 5next 系列预发布版sentry/sveltekitfile:../../packed/sentry-sveltekit-packed.tgz待验证的 Sentry SDK本地打包产物sveltejs/vite-plugin-svelte^3.0.0Vite 集成插件vite^5.4.11构建工具spotlightjs/spotlight2.0.0-alpha.1开发期 trace 可视化playwright/test~1.63.0E2E 测试框架值得注意的是sentry/sveltekit的依赖写法是file:../../packed/sentry-sveltekit-packed.tgz——它指向 monorepo 中预先打包好的 Sentry SvelteKit SDK tarball。这说明该应用验证的不是 npm 上发布的 SDK而是当前仓库源码构建出的打包产物是典型的打包含待测包、安装、跑真实浏览器的 E2E 回归策略。开发模式README 给出的开发流程是安装依赖后启动开发服务器npm run dev # 或启动服务器并在新浏览器标签页中打开应用 npm run dev -- --open对照 package.json 中的 scripts这里的dev实际映射为vite dev并且该仓库统一使用 pnpm 管理依赖clean脚本会删除pnpm-lock.yaml。完整的脚本清单还包括{ dev: vite dev, build: vite build, preview: vite preview, proxy: node start-event-proxy.mjs, clean: npx rimraf node_modules pnpm-lock.yaml, check: svelte-kit sync svelte-check --tsconfig ./tsconfig.json, check:watch: svelte-kit sync svelte-check --tsconfig ./tsconfig.json --watch, test:prod: TEST_ENVproduction playwright test, test:build: pnpm install pnpm build, test:assert: pnpm test:prod }其中test:build与test:assert揭示了 CI 的使用方式先在目标应用里执行pnpm install pnpm build完成安装与生产构建再以TEST_ENVproduction跑 Playwright 断言。构建与预览README 中生产构建与预览的命令同样完整继承自模板npm run build # 实际执行 vite build # 构建产物可用 preview 预览 npm run previewREADME 末尾还保留了关于部署 adapter 的提示若要部署应用可能需要为具体目标环境安装对应的 SvelteKit adapter。这一点在本应用中确实成立——svelte.config.js 使用的是sveltejs/adapter-autoimport adapter from sveltejs/adapter-auto; import { vitePreprocess } from sveltejs/vite-plugin-svelte; /** type {import(sveltejs/kit).Config} */ const config { preprocess: vitePreprocess(), kit: { // adapter-auto 只支持部分环境如果目标环境不被支持 // 需要切换为具体的 adapter adapter: adapter(), }, }; export default config;这也解释了为什么 Playwright 配置里选择vite preview而非部署到某个平台本地预览即可完整覆盖 SvelteKit 的服务端渲染与 hydration 行为。目录的真实身份Sentry SvelteKit SDK 的 Svelte 5 E2E 测试目标从目录命名sveltekit-2-svelte-5与同级目录下并列存在的sveltekit-2、sveltekit-2-static、sveltekit-3、sveltekit-3-cloudflare-workers等应用可以推断该仓库为sentry/sveltekit维护了一组覆盖不同 SvelteKit/Svelte 大版本组合的 E2E 应用而本文主角专门锁定SvelteKit 2 Svelte 5这一前沿组合用于尽早暴露 Svelte 5 新运行时runes 模式下的兼容性问题。客户端埋点hooks.client.tsSentry 在 SvelteKit 中的推荐接入点是hooks.client.ts与hooks.server.ts。本应用的 hooks.client.ts 完整展示了 SDK 初始化import { env } from $env/dynamic/public; import * as Sentry from sentry/sveltekit; import * as Spotlight from spotlightjs/spotlight; Sentry.init({ environment: qa, // 通过 dynamic sampling bias 保留事务 dsn: env.PUBLIC_E2E_TEST_DSN, debug: !!env.PUBLIC_DEBUG, tunnel: http://localhost:3031/, // 代理服务器 tracesSampleRate: 1.0, }); const myErrorHandler ({ error, event }: any) { console.error(An error occurred on the client side:, error, event); }; export const handleError Sentry.handleErrorWithSentry(myErrorHandler); if (import.meta.env.DEV) { Spotlight.init({ injectImmediately: true, }); }几个关键配置值得注意dsn来自$env/dynamic/public客户端代码只能读取PUBLIC_前缀的公开环境变量即PUBLIC_E2E_TEST_DSNtunnel指向http://localhost:3031/事件并不直接发往真实 Sentry 服务器而是经本地代理转发后文详述这使 CI 环境无需公网 DSNtracesSampleRate: 1.0全量采样保证 E2E 断言总能收到性能事件Sentry.handleErrorWithSentry把 SvelteKit 的错误处理钩子包装进 Sentry路由级错误如 load 抛错会被自动捕获并上报Spotlight仅在开发模式import.meta.env.DEV注入用于人工调试 trace与测试无关。服务端埋点hooks.server.tshooks.server.ts 与客户端对称但多了 SvelteKit 特有的请求处理钩子import { E2E_TEST_DSN } from $env/static/private; import * as Sentry from sentry/sveltekit; import { setupSidecar } from spotlightjs/spotlight/sidecar; Sentry.init({ environment: qa, dsn: E2E_TEST_DSN, debug: !!process.env.DEBUG, tunnel: http://localhost:3031/, tracesSampleRate: 1.0, spotlight: import.meta.env.DEV, }); // 不向控制台输出避免测试日志噪音 export const handleError Sentry.handleErrorWithSentry(() {}); export const handle Sentry.sentryHandle(); if (import.meta.env.DEV) { setupSidecar(); }服务端 DSN 通过$env/static/private静态读取构建期内联不会暴露到客户端export const handle Sentry.sentryHandle()是 SvelteKit 服务端请求处理钩子负责创建每个请求的 HTTP 事务并处理 trace 的跨端串联服务端handleError被有意配置为不打印日志源码注释说明是为了避免测试输出噪音错误是否上报完全由 Playwright 侧断言验证。Vite 插件sentrySvelteKitvite.config.ts 展示了 SDK 的构建期集成import { sentrySvelteKit } from sentry/sveltekit/vite; import { sveltekit } from sveltejs/kit/vite; import { defineConfig } from vite; export default defineConfig({ plugins: [ sentrySvelteKit({ autoUploadSourceMaps: false, }), sveltekit(), ], });sentrySvelteKit插件来自sentry/sveltekit/vite子导出负责 source map 处理与 release/debugId 注入这里显式设置autoUploadSourceMaps: false因为 E2E 场景不需要把 source map 上传到 Sentry 服务器。E2E 测试基础设施Playwright 本地事件代理事件代理服务器应用目录下的 start-event-proxy.mjs 只有寥寥几行却解释了tunnel: http://localhost:3031/的来历import { startEventProxyServer } from sentry-internal/test-utils; startEventProxyServer({ port: 3031, proxyServerName: sveltekit-2-svelte-5, });sentry-internal/test-utils对应仓库中的 dev-packages/test-utils 包提供了一个事件代理SDK 上报的 error/transaction 事件先打到这个本地服务器测试代码再按proxyServerName即sveltekit-2-svelte-5订阅、过滤并断言这些事件。package.json中的proxy脚本node start-event-proxy.mjs就是启动它的入口。Playwright 配置playwright.config.mjs 同样复用 test-utils 的统一工厂import { getPlaywrightConfig } from sentry-internal/test-utils; const config getPlaywrightConfig({ startCommand: pnpm preview --port 3030, port: 3030, }); export default config;startCommand: pnpm preview --port 3030与package.json中test:build的先决条件呼应E2E 断言跑在生产构建 vite preview3030 端口之上而事件代理监听 3031 端口两者互不冲突。稳定性关键waitForInitialPageloadtests/utils.ts 提供了一个消除测试抖动的核心辅助函数其注释直接说明了设计动机export async function waitForInitialPageload( page: Page, opts?: { route?: string; parameterizedRoute?: string; debug?: boolean }, ) { const route opts?.route ?? /; const spanName opts?.parameterizedRoute ?? route; const debug opts?.debug ?? false; const clientPageloadSpanPromise waitForStreamedSpan(sveltekit-2-svelte-5, span { return span.name spanName getSpanOp(span) pageload span.is_segment; }); await Promise.all([ page.goto(route), // 测试应用在 hydration 完成时会向 body 添加 hydrated class page.waitForSelector(body.hydrated), // 同时等待初始 pageload span避免后续导航与其竞争 clientPageloadSpanPromise, ]); }这里有两个协作点hydration 信号根布局 src/routes/layout.svelte 在onMount时给body添加hydratedclassscript langts import { onMount } from svelte; onMount(() { // 标记 SvelteKit 应用已完成 hydration document.body.classList.add(hydrated); }); /script测试端用page.waitForSelector(body.hydrated)精确等待客户端接管完成。等待 pageload segment span同时通过代理等待op pageload且is_segment的 span 被发送。注释指出如果导航发生得太快、pageload 空闲 span 仍处于活跃状态routing span 可能被挂到 pageload span 之下从而引入大量 flaky先等 pageload 事件落地再发起导航即可排除这类竞态。测试覆盖错误捕获与性能链路tests 目录下共有 5 个测试文件errors.client.test.ts、errors.server.test.ts、performance.client.test.ts、performance.server.test.ts、performance.test.ts与src/routes/下精心布置的故障路由一一对应client-error、server-load-error、server-route-error、universal-load-error、universal-load-fetch、users/[id]等。客户端错误errors.client.test.tserrors.client.test.ts 的第一个用例验证点击抛错的完整上报链路test(captures error thrown on click, async ({ page }) { await waitForInitialPageload(page, { route: /client-error }); const errorEventPromise waitForError(sveltekit-2-svelte-5, errorEvent { return errorEvent?.exception?.values?.[0]?.value Click Error; }); await page.getByText(Throw error).click(); await expect(errorEventPromise).resolves.toBeDefined(); const errorEvent await errorEventPromise; 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.transaction).toEqual(/client-error); });断言覆盖了三个层面异常值本身Click Error、调用栈末帧特征按钮事件处理器、in_app: true、以及事件关联的事务名/client-error。第二个用例则验证universal load中抛出的浏览器侧 load 错误Universal Load Error (browser)同样被捕获并正确关联事务。性能pageload / navigation 与分布式 traceperformance.test.ts 中的用例展示了 SDK 自动埋点应产生的 span 结构。以分布式 pageload trace 为例test(capture a distributed pageload trace, async ({ page }) { const traceSpansPromise collectStreamedSpans(sveltekit-2-svelte-5, spansOfTrace { const hasClientSegment spansOfTrace.some(span span.name /users/[id] span.is_segment); const hasServerSegment spansOfTrace.some(span span.name GET /users/[id] span.is_segment); return hasClientSegment hasServerSegment; }); const [_, traceSpans] await Promise.all([ page.goto(/users/123xyz), traceSpansPromise, expect(page.getByText(User id: 123xyz)).toBeVisible(), ]); const clientSpan traceSpans.find(span span.name /users/[id] span.is_segment)!; const serverSpan traceSpans.find(span span.name GET /users/[id] span.is_segment)!; expect(clientSpan.attributes).toMatchObject({ sentry.op: { value: pageload, type: string }, sentry.origin: { value: auto.pageload.sveltekit, type: string }, sentry.segment.name.source: { value: route, type: string }, url.path: { value: /users/123xyz, type: string }, url.template: { value: /users/[id], type: string }, }); expect(serverSpan.attributes).toMatchObject({ sentry.op: { value: http.server, type: string }, sentry.origin: { value: auto.http.sveltekit, type: string }, }); // 客户端与服务端 span 同属一条 trace expect(clientSpan.trace_id).toBe(serverSpan.trace_id); // 服务端 span 是客户端 span 的 parent expect(clientSpan.parent_span_id).toBe(serverSpan.span_id); });这个用例对sentry/sveltekit的行为提出了精确契约客户端 pageload segment 的 op 必须是pageload、origin 为auto.pageload.sveltekit且 span 名采用路由模板/users/[id]sentry.segment.name.source为route服务端 segment 的 op 为http.server、origin 为auto.http.sveltekit两端trace_id相同分布式 trace 连通且服务端 span 是客户端 span 的父节点——这是 SvelteKit 服务端渲染场景下 SDK 的 trace 组织约定。同类用例还覆盖了 SPA 导航navigationop auto.navigation.sveltekitorigin见/users路由以及 universal load 中 fetch 调用派生的服务端 spanGET /api/users说明测试同时验证了 src/routes/universal-load-fetch/page.ts 与 src/routes/api/users/server.ts 构成的跨层调用链。小结一个应用承载的完整验证矩阵层面机制关键文件脚手架与运行create-svelte 标准流程vite dev/vite build/vite previewREADME.md、package.json适配器sveltejs/adapter-auto本地vite preview验证svelte.config.js客户端埋点Sentry.inithandleErrorWithSentrytunnel 走本地代理src/hooks.client.ts服务端埋点sentryHandle()handleErrorWithSentrysrc/hooks.server.ts构建期集成sentrySvelteKitVite 插件关闭自动上传vite.config.ts事件采集3031 端口事件代理 proxyServerName过滤start-event-proxy.mjs测试驱动Playwright 启动pnpm preview --port 3030playwright.config.mjs稳定性保障等待body.hydrated pageload segment 落地tests/utils.ts、layout.svelte行为断言错误捕获、pageload/navigation/http.server span 契约、跨端 trace 连通tests 目录整体来看这个应用把 create-svelte 模板中最基础的创建—开发—构建流程扩展为一套针对 SvelteKit 2 Svelte 5 前沿组合的 SDK 回归验证装置README 描述的是脚手架通用操作而真正的工程价值在于它锁定了 Svelte 5 版本、打包安装了本地sentry/sveltekit产物并用 Playwright 事件代理对客户端错误、服务端错误、自动性能埋点与跨端 trace 串联做出了可执行的验收标准。赞分享可观测性【免费下载链接】sentry-javascriptOfficial Sentry SDKs for JavaScript项目地址https://gitcode.com/gh_mirrors/se/sentry-javascript点击查看免费下载相关推荐sentry-javascript SvelteKit 2 Tracing E2E 测试应用基于 create-svelte 的搭建、构建与 Tracing 验证指南sentry javascript SvelteKit 2 Tracing E2E 测试应用基于 create svelte 的搭建、构建与 Tracing可观测性sentry-javascript 中的 SolidStart E2E 测试应用如何用 Playwright、Vinxi 与事件隧道验证 sentry/solidstart SDKsentry javascript 中的 SolidStart E2E 测试应用如何用 Playwright、Vinxi 与事件隧道验证 sentry/so可观测性sentry-javascript 中 SolidStart 2 E2E 测试应用从标准 README 到 Sentry 集成验证的完整实操指南sentry javascript 中 SolidStart 2 E2E 测试应用从标准 README 到 Sentry 集成验证的完整实操指南 本篇以 de可观测性上一篇深入解析 Bokeh CodeRunnerBokeh 服务器应用代码编译与执行引擎下一篇KernelSU Metamodule 架构指南从模块挂载原理到自定义挂载实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →