Docs
Storybook Docs

交互

Storybook 中的 play 函数允许你模拟用户交互以在故事渲染后运行。使用 交互 插件,你可以可视化和调试这些交互。

¥The play function in Storybook allows you to simulate user interactions to run after a story renders. With the Interactions addon, you have a way to visualize and debug these interactions.

互动的播放函数

¥Play function for interactions

故事以结构化的方式隔离和捕获组件状态。在开发组件时,你可以快速循环浏览故事以验证外观。每个故事都指定了重现特定状态所需的所有输入。你甚至可以模拟上下文和 API 调用,从而让你能够处理组件的大多数用例。但是那些需要用户交互的状态怎么办?

¥Stories isolate and capture component states in a structured manner. While developing a component, you can quickly cycle through the stories to verify the look and feel. Each story specifies all the inputs required to reproduce a specific state. You can even mock context and API calls, allowing you to handle most use cases of a component. But what about states that require user interaction?

例如,单击按钮打开/关闭对话框,拖动列表项以重新排序,或填写表单以检查验证错误。要测试这些行为,你必须像用户一样与组件进行交互。交互式故事使你能够使用播放函数自动执行这些交互。它们是故事完成渲染后运行的小代码片段,模拟用户与组件交互的确切步骤。

¥For example, clicking a button to open/close a dialog box, dragging a list item to reorder it, or filling out a form to check for validation errors. To test those behaviors, you have to interact with the components as a user would. Interactive stories enable you to automate these interactions using a play function. They are small snippets of code that run once the story finishes rendering, emulating the exact steps a user would take to interact with the component.

由 Testing Library 和 Vitest 提供支持

¥Powered by Testing Library and Vitest

交互是使用名为 @storybook/test 的包编写的。它提供 Storybook 仪表版本的 测试库Vitest。这为你提供了一个熟悉的、开发者友好的语法,用于与 DOM 交互并做出断言,但带有额外的遥测以帮助调试。

¥The interactions are written using a package called @storybook/test. It provides Storybook-instrumented versions of Testing Library and Vitest. That gives you a familiar developer-friendly syntax to interact with the DOM and make assertions, but with extra telemetry to help with debugging.

设置交互插件

¥Set up the interactions addon

默认情况下,如果你要为新项目添加 Storybook,则 @storybook/addon-interactions 已默认安装和配置。如果你要从以前版本的 Storybook 迁移,则需要手动安装它。

¥By default, the @storybook/addon-interactions is already installed and configured if you're adding Storybook for new projects. If you're migrating from a previous version of Storybook, you'll need to install it manually.

运行以下命令安装交互插件和相关依赖。

¥Run the following command to install the interactions addon and related dependencies.

npm install @storybook/test @storybook/addon-interactions --save-dev

接下来,将 .storybook/main.js|ts 更新为以下内容:

¥Next, update .storybook/main.js|ts to the following:

.storybook/main.ts
// Replace your-framework with the framework you are using (e.g., react-webpack5, vue3-vite)
import type { StorybookConfig } from '@storybook/your-framework';
 
const config: StorybookConfig = {
  framework: '@storybook/your-framework',
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    // Other Storybook addons
    '@storybook/addon-interactions', // 👈 Register the addon
  ],
};
 
export default config;

确保在 @storybook/addon-essentials 插件之后列出 @storybook/addon-interactions(如果你单独安装了 @storybook/addon-actions,则列出 @storybook/addon-interactions)。

¥Make sure to list @storybook/addon-interactions after the @storybook/addon-essentials addon (or the @storybook/addon-actions if you've installed it individually).

现在当你运行 Storybook 时,Interactions 插件将被启用。

¥Now when you run Storybook, the Interactions addon will be enabled.

Storybook Interactions installed and registered

编写组件测试

¥Write a component test

交互作为故事的 play 功能的一部分运行。我们依靠测试库来完成繁重的工作。

¥Interactions run as part of the play function of your stories. We rely on Testing Library to do the heavy lifting.

确保通过 @storybook/test 导入 Vitest 和测试库的 Storybook 封装器,而不是直接导入原始包。

¥Make sure to import the Storybook wrappers for Vitest and Testing Library via @storybook/test rather than importing the original packages directly.

Form.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { userEvent, waitFor, within, expect, fn } from '@storybook/test';
 
import { Form } from './Form';
 
const meta: Meta<typeof Form> = {
  component: Form,
  args: {
    // 👇 Use `fn` to spy on the onSubmit arg
    onSubmit: fn(),
  },
};
 
export default meta;
type Story = StoryObj<typeof Form>;
 
/*
 * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas
 * to learn more about using the canvasElement to query the DOM
 */
export const Submitted: Story = {
  play: async ({ args, canvasElement, step }) => {
    const canvas = within(canvasElement);
 
    await step('Enter credentials', async () => {
      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');
      await userEvent.type(canvas.getByTestId('password'), 'supersecret');
    });
 
    await step('Submit form', async () => {
      await userEvent.click(canvas.getByRole('button'));
    });
 
    // 👇 Now we can assert that the onSubmit arg was called
    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());
  },
};

上面的示例使用 canvasElement 将元素查询的范围限定在当前故事中。如果你希望你的 play 函数最终与 Storybook Docs 兼容,它是必不可少的,Storybook Docs 会在同一页面上渲染多个组件。此外,step 函数可用于创建带标签的交互组。

¥The above example uses the canvasElement to scope your element queries to the current story. It's essential if you want your play functions to eventually be compatible with Storybook Docs, which renders multiple components on the same page. Additionally, the step function can be used to create labeled groups of interactions.

虽然你可以参考 测试库文档 了解如何使用它的详细信息,但使用 Storybook 封装器时有一个重要的细节有所不同:方法调用必须是 await-ed。它允许你使用调试器来回移动交互。

¥While you can refer to the Testing Library documentation for details on how to use it, there's an important detail that's different when using the Storybook wrapper: method invocations must be await-ed. It allows you to step back and forth through your interactions using the debugger.

任何已标记为操作的 args(使用 argTypes 注释argTypesRegex)都将自动转换为 Jest 模拟函数(间谍)。这允许你对这些函数的调用做出断言。

¥Any args that have been marked as an Action, either using the argTypes annotation or the argTypesRegex, will be automatically converted to a Jest mock function (spy). This allows you to make assertions about calls to these functions.

要模拟 Storybook 故事中的函数以进行可靠且独立的组件测试,请使用 @storybook/test 中的命名 fn 导入。

¥To mock functions in your Storybook stories for reliable and isolated component testing, use the named fn import from @storybook/test.

API

参数

¥Parameters

此插件将以下 参数 贡献给 Storybook,位于 interactions 命名空间下:

¥This addon contributes the following parameters to Storybook, under the interactions namespace:

disable

类型:boolean

¥Type: boolean

禁用此插件的行为。如果你希望为整个 Storybook 禁用此插件,你应该在注册 addon-essentials 时这样做。有关更多信息,请参阅 必备插件文档

¥Disable this addon's behavior. If you wish to disable this addon for the entire Storybook, you should do so when registering addon-essentials. See the essential addon's docs for more information.

此参数最有用,允许在更具体的级别进行覆盖。例如,如果此参数在项目级别设置为 true,则可以通过在元(组件)或故事级别将其设置为 false 来重新启用它。

¥This parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to true at the project level, it could then be re-enabled by setting it to false at the meta (component) or story level.