文档
Storybook 文档

Playwright CT 中的可移植 stories

(⚠️ 实验性功能)

Playwright CT 的可移植 stories API 是实验性的。Playwright CT 本身也是实验性的。在即将发布的版本中,这两个库都可能发生重大更改。

可移植 stories 是 Storybook stories,可以在外部环境中使用,例如 Playwright 组件测试 (CT)

通常,Storybook 会自动组合 story 及其注解,作为story 管道的一部分。在 Playwright CT 中使用 stories 时,您可以使用 createTest 函数,该函数扩展了 Playwright 的测试功能,添加了一个自定义的 mount 机制,来为您处理 story 管道。

您的项目必须使用 React 18+ 才能将可移植 stories API 与 Playwright CT 一起使用。

使用 Next.js Playwright CT 中的 Next.js 尚不支持可移植 stories API。

createTest

(⚠️ 实验性功能)

您可以不使用 Playwright 自己的 test 函数,而是使用 Storybook 特有的 createTest 函数来扩展 Playwright 的基础 fixture 并覆盖 mount 函数以加载、渲染和播放 story。此函数是实验性的,可能会发生更改。

Button.playwright.test.tsx
import { createTest } from '@storybook/react/experimental-playwright';
import { test as base } from '@playwright/experimental-ct-react';
 
// See explanation below for `.portable` stories file
import stories from './Button.stories.portable';
 
const test = createTest(base);
 
test('renders primary button', async ({ mount }) => {
  // The mount function will execute all the necessary steps in the story,
  // such as loaders, render, and play function
  await mount(<stories.Primary />);
});
 
test('renders primary button with overridden props', async ({ mount }) => {
  // You can pass custom props to your component via JSX
  const component = await mount(<stories.Primary label="label from test" />);
  await expect(component).toContainText('label from test');
  await expect(component.getByRole('button')).toHaveClass(/storybook-button--primary/);
});

您在 Playwright 测试文件中编写的代码由 Playwright 转换和编排,其中部分代码在 Node 中执行,而其他部分在浏览器中执行。

因此,您必须在与您自己的测试文件不同的文件中组合 stories

// Button.stories.portable.ts
// Replace your-renderer with the renderer you are using (e.g. react, vue3)
import { composeStories } from '@storybook/your-renderer';
 
import * as stories from './Button.stories';
 
// This function will be executed in the browser
// and compose all stories, exporting them in a single object
export default composeStories(stories);

然后,您可以像上面的示例中那样,在 Playwright 测试文件中导入组合好的 stories。

类型

createTest(
  baseTest: PlaywrightFixture
) => PlaywrightFixture

参数

baseTest

必需

类型: PlaywrightFixture

要使用的基础测试函数,例如 Playwright 中的 test

返回

类型: PlaywrightFixture

具有自定义 mount 机制的 Storybook 特定的测试函数。

setProjectAnnotations

此 API 应该在测试运行之前调用一次,在 playwright/index.ts 中。这将确保在调用 mount 时,也会考虑项目注解。

这些是在设置文件中需要的配置

  • 预览注解:在 .storybook/preview.ts 中定义的那些
  • 插件注解(可选):由插件导出的那些
  • beforeAll:在所有测试之前运行的代码(更多信息
playwright/index.tsx
import { test } from '@playwright/experimental-ct-react';
import { setProjectAnnotations } from '@storybook/react';
// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this
import * as addonAnnotations from 'my-addon/preview';
import * as previewAnnotations from './.storybook/preview';
 
const annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);
 
// Supports beforeAll hook from Storybook
test.beforeAll(annotations.beforeAll);

有时,story 可能需要插件的装饰器加载器才能正确渲染。例如,插件可以应用一个装饰器,将您的 story 包裹在必要的路由器上下文中。在这种情况下,您必须在设置的项目注解中包含该插件的 preview 导出。请参阅上面示例中的 addonAnnotations

注意:如果插件不自动应用装饰器或加载器本身,而是导出它们供您在 .storybook/preview.js|ts 中手动应用(例如,使用 @storybook/addon-themes 中的 withThemeFromJSXProvider),那么您无需执行任何其他操作。它们已经包含在上面示例中的 previewAnnotations 中。

类型

(projectAnnotations: ProjectAnnotation | ProjectAnnotation[]) => ProjectAnnotation

参数

projectAnnotations

必需

类型: ProjectAnnotation | ProjectAnnotation[]

一组项目注解(在 .storybook/preview.js|ts 中定义的那些)或一组项目注解的数组,这些注解将应用于所有组合的 stories。

注解

注解是应用于 story 的元数据,例如 args装饰器加载器Play 函数。它们可以为特定 story、组件的所有 stories 或项目中的所有 stories 定义。

故事流程

为了预览您的故事,Storybook 运行一个故事流程,其中包括应用项目注解、加载数据、渲染故事和播放交互。这是一个简化的流程版本

A flow diagram of the story pipeline. First, set project annotations. Collect annotations (decorators, args, etc) which are exported by addons and the preview file. Second, compose story. Create renderable elements based on the stories passed onto the API. Third, render story. Load, mount, and execute the play function as part of the portable stories API.

然而,当您想在不同的环境重用故事时,理解所有这些步骤构成一个故事至关重要。可移植故事 API 为您提供在外部环境中重建该故事流程的机制

1. 应用项目级注解

注解来自故事本身、故事的组件和项目。项目级注解是在您的 .storybook/preview.js 文件中以及您正在使用的插件中定义的那些。在可移植故事中,这些注解不会自动应用 —— 您必须自己应用它们。

👉 为此,您可以使用 setProjectAnnotations API。

2. 准备、加载、渲染和播放

故事流程包括准备故事、加载数据、渲染故事和播放交互。在 Playwright CT 中的可移植故事中,mount 函数会为您处理这些步骤。

👉 为此,您可以使用 createTest API。

如果您的 play 函数包含断言(例如 expect 调用),当这些断言失败时,您的测试将失败。

覆盖全局变量

如果您的故事根据全局变量(例如,以英语或西班牙语渲染文本)表现不同,您可以在组合故事时通过覆盖项目注解在可移植故事中定义这些全局值

Button.stories.portable.ts
import { composeStory } from '@storybook/react';
 
import meta, { Primary } from './Button.stories';
 
export const PrimaryEnglish = composeStory(
  Primary,
  meta,
  { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale
);
 
export const PrimarySpanish = composeStory(Primary, meta, { globals: { locale: 'es' } });

然后,您可以使用 createTest 函数在您的 Playwright 测试文件中使用这些组合的故事。