Storybook Test Runner 辅助函数与测试钩子实战指南:getStoryContext 与 waitForPageReady 的完整用法

发布时间:2026/9/10 23:11:36
Storybook Test Runner 辅助函数与测试钩子实战指南:getStoryContext 与 waitForPageReady 的完整用法 Storybook Test Runner 辅助函数与测试钩子实战指南getStoryContext 与 waitForPageReady 的完整用法【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybookStorybook 的官方 Test Runnerstorybook/test-runner把每一个 story 都变成可在真实浏览器中运行的自动化测试而要让这些测试具备读取 story 内部数据、等待页面资源完全加载等高级能力就需要借助它导出的测试钩子Test Hook API与辅助函数Helpers。本文基于仓库中 test-runner-helper-function.md 配置片段结合完整文档 test-runner.mdx系统讲解setup/preVisit/postVisit钩子以及getStoryContext、waitForPageReady两个辅助函数的原理、配置与实战用法读完即可在自己的项目中写出可复制的测试定制方案。Test Runner 与辅助函数在 Storybook 测试体系中的位置Storybook Test Runner 是一个框架无关、与 Storybook 并行运行的独立工具底层由 Jest 和 Playwright 驱动对于没有 play function 的 story它验证 story 是否能无错误地渲染对于带有 play function 的 story它额外检查 play function 中的错误并确认所有断言均通过。这些测试在真实的浏览器中运行可通过命令行CLI或 CI 服务器执行。文档明确指出在基于 Vite 的 Storybook 框架中官方推荐使用更快、更现代的 Vitest 插件Vitest addon 替代 Test Runner但 Test Runner 仍适用于 Webpack 等场景且其钩子与辅助函数的设计思路在测试扩展中通用。# 安装 Test Runner开发依赖 npm install storybook/test-runner --save-dev # pnpm: pnpm add --save-dev storybook/test-runner # yarn: yarn add --dev storybook/test-runner安装后在package.json中添加脚本{ scripts: { test-storybook: test-storybook } }Test Runner 需要一个本地运行中或已发布的 Storybook 实例先启动 Storybook再在另一个终端窗口执行yarn test-storybook即可运行全部 story 测试。若需更细粒度的控制可运行test-storybook --eject它会在项目根目录生成可修改的test-runner-jest.config.js文件Test Runner 底层使用 jest-playwright。Test Hook API钩子与生命周期的完整清单许多行为无法通过运行在浏览器内的 play function 实现——例如让 Test Runner 代为截取视觉快照这类操作必须在 Node 进程中执行。为此 Test Runner 导出了可在全局覆写的测试钩子让你能在 story 渲染的之前与之后接入测试生命周期。可用钩子如下钩子说明签名prepare为测试准备浏览器async prepare({ page, browserContext, testRunnerConfig }) {}setup在所有测试运行前执行一次setup() {}preVisit在 story 首次被访问、渲染于浏览器之前执行async preVisit(page, context) {}postVisit在 story 被访问并完全渲染之后执行async postVisit(page, context) {}这些测试钩子目前属于实验性 API可能发生破坏性变更官方建议尽可能在 story 的 play function 内完成测试逻辑。要启用钩子 API需要在 Storybook 目录默认为.storybook/下新建配置文件test-runner.js或test-runner.ts。除setup外其余钩子均为异步函数preVisit与postVisit额外接收两个参数一个 Playwright 的page对象以及一个包含 story 的id、title、name的 context 对象。Test Runner 执行时测试会经历如下生命周期setup函数在所有测试运行前执行生成包含必要信息的 context 对象Playwright 导航到 story 页面执行preVisit函数story 被渲染存在的 play function 被执行执行postVisit函数。辅助函数全景getStoryContext 与 waitForPageReadyTest Runner 导出了若干辅助函数Helpers用于访问 Storybook 内部数据如args、parameters让测试更可读、更易维护。核心配置片段 test-runner-helper-function.md 给出了完整的 JavaScript 与 TypeScript 两种写法这里完整继承如下。JavaScript 版本.storybook/test-runner.jsconst { getStoryContext, waitForPageReady } require(storybook/test-runner); module.exports { // Hook that is executed before the test runner starts running tests setup() { // Add your configuration here. }, /* Hook to execute before a story is initially visited before being rendered in the browser. * The page argument is the Playwrights page object for the story. * The context argument is a Storybook object containing the storys id, title, and name. */ async preVisit(page, context) { // Add your configuration here. }, /* Hook to execute after a story is visited and fully rendered. * The page argument is the Playwrights page object for the story * The context argument is a Storybook object containing the storys id, title, and name. */ async postVisit(page, context) { // Get the entire context of a story, including parameters, args, argTypes, etc. const storyContext await getStoryContext(page, context); // This utility function is designed for image snapshot testing. It will wait for the page to be fully loaded, including all the async items (e.g., images, fonts, etc.). await waitForPageReady(page); // Add your configuration here. }, };TypeScript 版本.storybook/test-runner.tsimport type { TestRunnerConfig } from storybook/test-runner; import { getStoryContext, waitForPageReady } from storybook/test-runner; const config: TestRunnerConfig { // Hook that is executed before the test runner starts running tests setup() { // Add your configuration here. }, /* Hook to execute before a story is initially visited before being rendered in the browser. * The page argument is the Playwrights page object for the story. * The context argument is a Storybook object containing the storys id, title, and name. */ async preVisit(page, context) { // Add your configuration here. }, /* Hook to execute after a story is visited and fully rendered. * The page argument is the Playwrights page object for the story * The context argument is a Storybook object containing the storys id, title, and name. */ async postVisit(page, context) { // Get the entire context of a story, including parameters, args, argTypes, etc. const storyContext await getStoryContext(page, context); // This utility function is designed for image snapshot testing. It will wait for the page to be fully loaded, including all the async items (e.g., images, fonts, etc.). await waitForPageReady(page); // Add your configuration here. }, }; export default config;两个辅助函数的分工如下getStoryContext(page, context)读取某个 story 的完整上下文包括parameters、args、argTypes等全部信息返回值为 Promise需await。它接收两个参数当前 story 对应的 Playwrightpage对象以及钩子传入的 context 对象。它常用于在preVisit阶段根据 story 的参数调整测试环境或在postVisit阶段按 story 元数据生成自定义断言。waitForPageReady(page)专为图像快照image snapshot测试设计。它会等待页面完全加载就绪包括所有异步资源如图片、字体等。由于页面中字体、图片等资源加载完成前截图会得到不稳定的结果该函数能显著提升快照测试的稳定性。实战一用 getStoryContext 让 Playwright 视口跟随 story 参数在preVisit钩子中调用getStoryContext即可在渲染前读取 story 的parameters.viewport.defaultViewport并据此调整 Playwright 页面的视口尺寸。完整示例见 test-runner-custom-page-viewport.mdconst { getStoryContext } require(storybook/test-runner); const { MINIMAL_VIEWPORTS } require(storybook/viewport); const DEFAULT_VIEWPORT_SIZE { width: 1280, height: 720 }; module.exports { async preVisit(page, story) { // Accesses the storys parameters and retrieves the viewport used to render it const context await getStoryContext(page, story); const viewportName context.parameters?.viewport?.defaultViewport; const viewportParameter MINIMAL_VIEWPORTS[viewportName]; if (viewportParameter) { const viewportSize Object.entries(viewportParameter.styles).reduce( (acc, [screen, size]) ({ ...acc, // Converts the viewport size from percentages to numbers [screen]: parseInt(size), }), {}, ); // Configures the Playwright page to use the viewport size page.setViewportSize(viewportSize); } else { page.setViewportSize(DEFAULT_VIEWPORT_SIZE); } }, };这个示例的关键点在于MINIMAL_VIEWPORTS中定义的 viewport 尺寸以百分比字符串形式存储因此需要通过parseInt转换为数字后才能传给page.setViewportSize。如果该 story 未定义defaultViewport则回退到默认的1280 × 720。同理你也可以基于context.parameters中的其他配置如主题、语言环境在preVisit阶段做任意环境定制。实战二用 waitForPageReady 打造稳定的图像快照测试waitForPageReady最常见的应用场景是图像快照测试。在setup钩子中通过expect.extend注册toMatchImageSnapshot匹配器再在postVisit中等待页面资源就绪后截图。完整示例见 test-runner-waitpageready.mdconst { waitForPageReady } require(storybook/test-runner); const { toMatchImageSnapshot } require(jest-image-snapshot); const customSnapshotsDir ${process.cwd()}/__snapshots__; module.exports { setup() { expect.extend({ toMatchImageSnapshot }); }, async postVisit(page, context) { // Awaits for the page to be loaded and available including assets (e.g., fonts) await waitForPageReady(page); // Generates a snapshot file based on the story identifier const image await page.screenshot(); expect(image).toMatchImageSnapshot({ customSnapshotsDir, customSnapshotIdentifier: context.id, }); }, };这里用context.id作为快照标识符保证每个 story 生成唯一命名的快照文件。快照默认存放于项目根目录的__snapshots__目录如需自定义快照目录可编写自定义的snapshot-resolver.js并在test-runner-jest.config.js中启用snapshotResolver选项。若你的项目使用了 Emotion、Angular 的ng属性等会生成基于哈希的 CSS 类名的 CSS-in-JS 方案还可通过snapshotSerializers配置自定义快照序列化器默认使用jest-serializer-html在快照前将动态生成的属性替换为稳定的静态值确保跨测试运行的一致性。延伸配置钩子之外的高频能力除钩子与辅助函数外Test Runner 还支持通过.storybook/test-runner.js导出的其他配置函数扩展行为getHttpHeaders(url)对需要认证托管的 Storybook 设置 HTTP 请求头。该函数接收 fetch 请求与页面访问的 URL返回需要附加的 headers 对象。完整示例见 test-runner-auth.md例如根据 URL 是否包含prod返回不同的Authorization: Bearer token。CLI 常用参数--url 地址指定测试目标默认本机 6006 端口也可用TARGET_URL环境变量--maxWorkers 数量控制并行 worker 数--failOnConsole令浏览器控制台报错时测试失败--updateSnapshot/-u重录失败的快照--eject生成本地配置文件。标签过滤通过--includeTags、--excludeTags、--skipTags或配置文件中的include/exclude/skip选项按 story 的 tags 精确控制测试范围需 Test Runner 0.15 及以上。CLI 标志优先于配置文件中的同名选项。index.json 模式对远端 StorybookTest Runner 使用其index.json原stories.json静态索引运行测试可通过--index-json强制开启、--no-index-json关闭该模式与 watch 模式不兼容。常见问题与排障建议测试超时若出现Timeout - Async callback was not invoked within the 15000 ms timeout通常意味着 Playwright 无法并行处理过多 story可在 CI 脚本中限制并行度如yarn test-storybook --maxWorkers2。CLI 错误输出过短默认错误输出截断于 1000 字符可通过DEBUG_PRINT_LIMIT5000 yarn test-storybook调整上限。Yarn PnP 兼容性Test Runner 依赖社区维护的jest-playwright-preset尚不完全支持 Yarn PlugnPlay。可切换nodeLinker为node-modules或将 Playwright 作为直接依赖安装并执行playwright install下载浏览器二进制。标签过滤冲突若include与exclude提供了相同 tagsTest Runner 将按exclude执行并忽略include请确保两者 tags 不重叠。总结getStoryContext与waitForPageReady是扩展 Storybook Test Runner 时最核心的两个辅助函数前者打通了 Node 测试进程与 Storybook 内部数据parameters、args、argTypes之间的桥梁让测试可以依据每个 story 的元数据动态定制后者为图像快照类测试提供了可靠的资源加载等待保障。配合setup/preVisit/postVisit钩子与getHttpHeaders等配置项你可以将 Test Runner 扩展为覆盖交互、视口、图像快照、认证访问等各类场景的通用测试框架。相关完整配置片段与文档可继续查阅 test-runner.mdx 及 test-runner-custom-page-viewport.md、test-runner-waitpageready.md 等配套示例。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考