
Storybook 标签定向测试用 includeTags 让 Test Runner 只执行指定 Story 子集【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybookStorybook Test Runner 默认会把项目里每一个 story 都当作可执行测试跑一遍而在大型组件库中我们往往只想针对某一批「标记好」的 story 运行测试。本指南围绕 Storybook 官方代码片段 docs/_snippets/my-component-include-tags.md 展开完整演示如何在 CSF 3 与 CSF Next 两种写法下、跨 Angular / React / Vue / Web Components 等框架为 story 打上test-only标签并通过 Test Runner 的--includeTags或tags.include配置只运行这一个子集。读完你将掌握标签的定义层级、三种测试过滤语义include / exclude / skip的区别、CLI 与配置文件的优先级关系以及背后与 tags 机制对应的实现细节。这套代码要解决什么问题Test Runner 由 Jest 与 Playwright 驱动会把所有 story 变成可执行测试详见 docs/writing-tests/integrations/test-runner.mdx没有 play function 的 story验证能否无错误渲染带有 play function 的 story额外验证 play 函数中的断言是否全部通过。默认情况下它测试的是全部story。当组件库规模变大或者你希望像「每日冒烟测试」一样只跑最关键的故事例如贴了test-only标签的那部分时就需要借助 Storybook 的 tags 机制做子集过滤。在my-component-include-tags.md这段被官方文档test-runner.mdx的 “Run tests for a subset of stories” 小节引用的代码片段里做的正是这件事先在 stories 文件里把test-only标签打上随后 Test Runner 通过 include 语义命中这些 story。前置知识Storybook 的 tags 体系在使用 include 过滤前需要了解 tags 是如何产生与继承的。Storybook 将 tag 定义为任意静态字符串可在三个层级应用详见 docs/writing-stories/tags.mdx项目级.storybook/preview.*中为所有 story 统一打标签组件级CSF 文件的meta上打标签作用于该文件全部 story故事级单个 story 上打标签仅作用于该 story。内置标签包括dev、manifest、test默认隐式施加给每个 story、autodocs、play-fn、test-fn等。其中test标签正是 Test Runner / Vitest addon 判定「哪些 story 参与测试」的默认依据而自定义标签如experimental、test-only则为细粒度过滤提供灵活空间。若想移除某个标签可用!前缀如tags: [!autodocs]这里不再展开。打上test-only标签两种 CSF 写法的完整示例include-tags代码片段的核心思路分两步在meta上给整个文件打标签必要时再在具体 story 上显式声明相同标签。下面按 CSF 3 与 CSF Next 两种语法完整展开。CSF 3 语法AngularTypeScriptimport type { Meta, StoryObj } from storybook/angular; import { MyComponent } from ./my-component.component; const meta: MetaMyComponent { component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], }; export default meta; type Story StoryObjMyComponent; export const IncludeStory: Story { // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], };通用 JSMyComponent.stories.js|jsximport { MyComponent } from ./MyComponent; export default { component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], }; export const IncludeStory { // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], };通用 TSMyComponent.stories.ts|tsx将 your-framework 替换为实际框架名// Replace your-framework with the name of your framework import type { Meta, StoryObj } from storybook/your-framework; import { MyComponent } from ./MyComponent; const meta { component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], } satisfies Metatypeof MyComponent; export default meta; type Story StoryObjtypeof meta; export const IncludeStory: Story { // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], };Web ComponentsJavaScriptexport default { component: my-component, // Provides the test-only tag to all stories in this file tags: [test-only], }; export const IncludeStory { // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], };Web ComponentsTypeScriptimport type { Meta, StoryObj } from storybook/web-components-vite; const meta: Meta { component: my-component, // Provides the test-only tag to all stories in this file tags: [test-only], }; export default meta; type Story StoryObj; export const IncludeStory: Story { // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], };CSF Next 语法 实验性CSF Next 通过从.storybook/preview导入preview用preview.meta({...})与meta.story({...})声明式地组织元数据与故事标签写法和 CSF 3 完全一致。AngularTypeScriptimport preview from ../.storybook/preview; import { MyComponent } from ./my-component.component; const meta preview.meta({ component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], }); export const IncludeStory meta.story({ // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], });ReactMyComponent.stories.ts|tsximport preview from ../.storybook/preview; import { MyComponent } from ./MyComponent; const meta preview.meta({ component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], }); export const IncludeStory meta.story({ // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], });ReactMyComponent.stories.js|jsximport preview from ../.storybook/preview; import { MyComponent } from ./MyComponent; const meta preview.meta({ component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], }); export const IncludeStory meta.story({ // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], });Vue 3TypeScriptimport preview from ../.storybook/preview; import MyComponent from ./MyComponent.vue; const meta preview.meta({ component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], }); export const IncludeStory meta.story({ // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], });Vue 3JavaScriptimport preview from ../.storybook/preview; import MyComponent from ./MyComponent.vue; const meta preview.meta({ component: MyComponent, // Provides the test-only tag to all stories in this file tags: [test-only], }); export const IncludeStory meta.story({ // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], });Web ComponentsTypeScriptimport preview from ../.storybook/preview; const meta preview.meta({ component: my-component, // Provides the test-only tag to all stories in this file tags: [test-only], }); export const IncludeStory meta.story({ // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], });Web ComponentsJavaScriptimport preview from ../.storybook/preview; const meta preview.meta({ component: my-component, // Provides the test-only tag to all stories in this file tags: [test-only], }); export const IncludeStory meta.story({ // Adds the test-only tag to this story to be included in the tests when enabled in the test-runner configuration tags: [test-only], });对比可见无论采用哪种框架或 CSF 语法参与测试过滤的核心就是meta.tags作用于整个文件的全部 story与单条 story 的tags两个数组。需要特别强调的是为组件打测试标签只应发生在组件级meta或故事级story——Storybook 不支持跨 story 引入标签通过 import 把别的 story 的标签带过来不会按预期工作。让 Test Runner 命中test-onlyinclude / exclude / skip 与 CLI 参数仅给 story 打上标签还不够还需在 Test Runner 侧显式开启。官方为 Test Runner0.15 及更高版本提供了三种过滤选项选项语义说明exclude排除命中给定标签的 story 不会被测试include包含只有命中给定标签的 story 才会被测试skip跳过命中给定标签的 story 会被跳过并在结果中被标记表示暂时禁用方式一配置文件在.storybook/test-runner.js|ts中声明见 docs/_snippets/test-runner-tags-config.mdmodule.exports { tags: { include: [test-only, pages], exclude: [no-tests, tokens], skip: [skip-test, layout], }, };import type { TestRunnerConfig } from storybook/test-runner; const config: TestRunnerConfig { tags: { include: [test-only, pages], exclude: [no-tests, tokens], skip: [skip-test, layout], }, }; export default config;这样配置后Test Runner 只会运行同时满足include条件的 story 子集并剔除、跳过命中相应标签的 story。方式二CLI 标志也可以在命令行直接过滤对应上文IncludeStory的test-only标签test-storybook --includeTagstest-only, pages与之平行的还有--excludeTagsno-tests, tokens与--skipTagsskip-test, layout。其余常用的运行参数如--watch监听模式可组合使用例如npm run test-storybook -- --watch官方文档明确指出一个优先级规则通过 CLI 传入的过滤标志优先级高于配置文件中的tags选项即命令行会覆盖配置文件里的 include / exclude / skip 设置。三种语义的配套代码片段include 场景本文主题story 打test-only标签 → 用--includeTags/tags.include命中 → 只测该子集exclude 场景story 打no-tests标签 → 用--excludeTags/tags.exclude剔除 → 适合排除「尚未准备好被测试」或与测试无关的 story见 docs/_snippets/my-component-exclude-tags.mdskip 场景story 打skip-test标签 → 用--skipTags/tags.skip跳过 → 结果中会明确标记为暂时禁用见 docs/_snippets/my-component-skip-tags.md。三者的代码写法几乎相同只是标签名与用途不同区别完全体现在 Test Runner 处理它们的方式上。边界与坑位include、exclude 重叠时的行为Test Runner 的过滤逻辑有几处容易踩坑的行为官方文档的 Troubleshooting 部分做了明确说明如果你同时把某个标签放进include与exclude列表Test Runner 将以exclude为准并忽略include因此请保证两份标签集合互不重叠标签过滤属于实验性功能行为可能随版本演进调整若你的 story 尚未打任何自定义标签又没有提供过滤条件Test Runner 依旧默认跑全部 story因为内置test标签会施加到每个 story 上见 docs/writing-stories/tags.mdx。源码层面的印证标签过滤不是「文档里才有」的虚构能力。在仓库的 Vitest addon 实现 code/addons/vitest/src/vitest-plugin/test-utils.ts 中可以看到它先用composeStory把 story 级与meta组件级注解合并成一个composedStory随后执行if (composedStory undefined || skipTags?.some((tag) composedStory.tags.includes(tag))) { context.skip(); }也就是说skip 判定是对合并后的composedStory.tags与传入的skipTags做some(...includes(...))匹配一旦命中任一标签就跳过该用例。这从代码层面印证了两个关键事实标签会从meta继承/合并到最终 story 上因此include-tags示例在meta与单条 story 上同时书写tags是安全的双保险过滤器读取的是最终合并后的 tags 数组与我们在 CSF 文件中所写的meta.tags/ storytags一一对应。说明仓库内含 Vitest addon 的完整实现源码官方文档描述的storybook/test-runner亦采用同款 tags 过滤语义其过滤选项与 CLI 标志以本文引用的文档为准。小结要用includeTags实现「只测贴了test-only标签的 story 子集」路径非常清晰先在 CSF 文件的meta或具体 story 上声明tags: [test-only]CSF 3 与 CSF Next 语法均可Angular / React / Vue / Web Components 一致再在.storybook/test-runner.js|ts的tags.include里放行或直接在命令行传test-storybook --includeTagstest-only。需要注意 CLI 覆盖配置文件、include/exclude 标签集合不可重叠、标签需在 meta 或 story 层级声明等约束。若希望进一步了解测试侧的标签语义差异与更多测试策略可继续阅读 docs/writing-tests/integrations/test-runner.mdx、docs/writing-stories/tags.mdx以及 Vitest addon 的 入口索引文档。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考