文档
Storybook 文档

Playwright CT 中的可移植故事

(⚠️ 实验性)

Playwright CT 的可移植故事 API 处于实验阶段。Playwright CT 本身也处于实验阶段。在即将发布的版本中,这两个库都可能出现重大变更。

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

通常,Storybook 会自动将故事与其 注释 组合在一起,作为 故事流水线 的一部分。在 Playwright CT 中使用故事时,可以使用 createTest 函数,该函数扩展了 Playwright 的测试功能以添加自定义的 mount 机制,为你处理故事流水线。

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

使用 Next.js可移植故事 API 尚未在 Next.js 与 Playwright CT 中得到支持。

createTest

(⚠️ 实验性)

不要使用 Playwright 自身的 test 函数,可以使用 Storybook 的特殊 createTest 函数 扩展 Playwright 的基础夹具 并覆盖 mount 函数以加载、渲染和播放故事。此函数是实验性的,可能会发生更改。

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 中执行,而其他部分代码在浏览器中执行。

因此,必须在与自己的测试文件不同的文件中组合故事。

// 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 测试文件中导入组合后的故事,如上面的示例所示。

类型

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);

有时,一个故事可能需要一个附加组件的 装饰器加载器 才能正确渲染。例如,一个附加组件可以应用一个装饰器,将你的故事包装在必要的路由器上下文中。在这种情况下,你必须在项目注解集中包含该附加组件的 preview 导出。参见上面的示例中的 addonAnnotations

注意:如果附加组件没有自动应用装饰器或加载器,而是导出它们供你在 .storybook/preview.js|ts 中手动应用(例如使用 withThemeFromJSXProvider 来自 @storybook/addon-themes),那么你就不需要再做其他操作。它们已经包含在上面的示例中的 previewAnnotations 中。

类型

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

参数

projectAnnotations

(必需)

类型:ProjectAnnotation | ProjectAnnotation[]

一组项目 注解(在 .storybook/preview.js|ts 中定义)或项目注解集的数组,它们将应用于所有组合的故事。

注解

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

故事管道

为了预览你的故事,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。

如果你的播放函数包含断言(例如 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 测试文件中使用这些组合的故事。