
交互式故事 (Beta 版)
使用 play 函数模拟用户行为

独立构建组件可让您对其进行压力测试以找出边缘情况。使用 Storybook,您可以为每种情况编写 story,方法是向组件提供 props。
但是并非所有组件变体都能仅通过 props 重现。某些 UI 状态只能通过用户交互到达,例如下拉菜单、模态框和隐藏的表单元素。过去,您需要手动与组件交互以检查这些状态是否看起来正确。
我很高兴地宣布交互式 story(beta 版),它允许您模拟用户行为并在 story 渲染后运行。它消除了手动处理组件的繁琐工作。
- ✅ 在真实浏览器中运行
- ⚡️ 无等待,无错误
- 🐙 由 Testing Library 提供支持
- 🛠 低维护
- 🔍 快速可视化调试
用于交互的 Play 函数
Story 以结构化的方式隔离和捕获组件状态。在开发组件时,您可以快速地在 story 之间切换以验证外观和感觉。
每个 story 指定了重现特定状态所需的所有输入。您甚至可以模拟 context 和 API 调用。这使您能够处理大多数组件用例。
但是需要用户交互的状态呢?
例如,单击按钮以打开/关闭对话框,拖动列表项以重新排序,或填写表单以检查验证错误。要测试这些行为,您需要像用户一样与组件交互。

交互式 story 使您能够使用 play 函数自动化这些交互。这些是简短的代码片段,可以脚本化人类与组件交互的确切步骤。然后,它会在 story 渲染后立即执行。
由 Testing Library 提供支持
交互是使用 Storybook 版本的 Testing Library 编写的。这为您提供了熟悉且对开发人员友好的语法来与 DOM 交互,并具有额外的遥测功能以帮助调试。这是一个演示单击按钮以打开对话框的简单示例。
import React from 'react';
import { within, fireEvent } from '@storybook/testing-library';
import { DeleteCustomerDialog } from './DeleteCustomerDialog';
export default {
component: DeleteCustomerDialog,
title: 'DeleteCustomerDialog',
};
export const OpenDialog = () => <DeleteCustomerDialog />;
OpenDialog.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await fireEvent.click(
canvas.getByRole('button', { name: 'Delete Customer' })
);
};
如果您可以在 Storybook 中渲染它,那么您可以为其编写交互式 story。
交互式 story 使用与框架无关的 DOM API。这意味着,无论您使用什么框架,都可以编写 play 函数来操作 UI 并自动化用户行为。唯一的例外是 Web Components,因为 Testing-Library 尚不支持 shadow DOM。
使用 GUI 加快调试速度
大多数团队已经使用 Testing Library 为其组件编写功能测试。这些测试是使用 Jest 等测试运行器执行的。它们在 Node 中使用 JSDOM 运行。如果测试失败,您只会得到一堆 HTML 来进行调试。
使用 CLI 调试 UI 问题就像在您的 Playstation 5 上玩文字冒险游戏一样。它奏效了,但如果您能看到一些图形,那会更好。

交互式 story 使用 Storybook 特定的 Testing Library 版本。它在浏览器中运行,并为您可视化整个 play 函数。将其视为 Testing Library 的 GUI。

如果 story 失败,交互面板将突出显示失败的步骤。然后,您可以使用所有喜欢的开发工具在浏览器中直接调试 UI。而不是在 JSDOM 中使用不透明的 CLI。能够看到和检查 UI 使调试变得轻而易举。

Storybook linter
交互式 story 和交互面板都由 Testing Library 的 instrumented 版本启用。这意味着您必须使用来自 @storybook/testing-library 的辅助函数,并确保您的 story 使用正确的语法编写。我们正在开发一个 ESLint 插件来自动强制执行这些检查。它将与 Storybook 6.4 一起发布。敬请期待!
让我们通过一个演示来查看整个工作流程。
交互式 story 示例
考虑 Taskbox 应用程序 — 一个类似于 Asana 的任务管理应用程序。它显示一个用户可以固定、存档和编辑的任务列表。

story 看起来像这样
import React from 'react';
import { rest } from 'msw';
import { within, fireEvent, findByRole } from '@storybook/testing-library';
import { InboxScreen } from './InboxScreen';
import { Default as TaskListDefault } from './components/TaskList.stories';
export default {
component: InboxScreen,
title: 'InboxScreen',
};
const Template = (args) => <InboxScreen {...args} />;
export const Default = Template.bind({});
Default.parameters = {
msw: [
rest.get('/tasks', (req, res, ctx) => {
return res(ctx.json(TaskListDefault.args));
}),
],
};
export const UpdateTasks = Template.bind({});
UpdateTasks.parameters = { ...Default.parameters };
UpdateTasks.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const getTask = (name) => canvas.findByRole('listitem', { name });
// Pin
const itemToPin = await getTask('Export logo');
const pinButton = await findByRole(itemToPin, 'button', { name: 'pin' });
await fireEvent.click(pinButton);
// Archive
const itemToArchive = await getTask('QA dropdown');
const archiveCheckbox = await findByRole(itemToArchive, 'checkbox');
await fireEvent.click(archiveCheckbox);
// Edit
const itemToEdit = await getTask('Fix bug in input error state');
const taskInput = await findByRole(itemToEdit, 'textbox');
await fireEvent.change(taskInput, {
target: { value: 'Fix bug in the textarea error state' },
});
// Delete
const itemToDelete = await getTask('Build a date picker');
const deleteButton = await findByRole(itemToDelete, 'button', {
name: 'delete',
});
await fireEvent.click(deleteButton);
};story 使用 MSW 插件来 mock /tasks API 调用。该 mock 数据用于渲染任务列表,并且交互在 play 函数内部进行。

今天就来试试并分享您的反馈
交互式 story 现在在 Storybook 6.4 beta 版中可用。此实验性版本为我们 8 月份宣布的更广泛的交互测试功能奠定了基础。Storybook 6.4 使我们有机会在 Storybook 6.5 完全发布之前测试和稳定此功能。试试看,并与我们分享您的反馈。
通过在项目根目录中运行以下命令来安装它。
npx sb@next init升级现有项目
npx sb upgrade --prerelease然后安装与交互式 story 相关的依赖项
yarn add -D @storybook/addon-interactions @storybook/testing-library并在 .storybook/main.js 中启用调试器。请注意,@storybook/addon-interactions 必须列在 @storybook/addon-actions 或 @storybook/addon-essentials 之后。
// .storybook/main.js
module.exports = {
addons: ['@storybook/addon-interactions'],
};
参与进来
交互式 story 使测试组件的功能方面变得更加容易。您可以通过 play 函数脚本化交互,Storybook 会自动为您运行它们。方便的交互面板会可视化 play 函数中的每次交互。
交互式 story 功能由Gert Hengeveld、Deen Denno、Yann Braga、Michael Shilman、Tom Coleman、Michael Arestad 和Dominic Nguyen 开发,并获得了整个 Storybook 社区的反馈。
如果 Storybook 使您的 UI 开发工作流程更轻松,请帮助 Storybook 变得更好。您可以贡献新功能、修复 bug 或改进文档。加入我们的 Discord 或直接在 Github 上参与。要获取项目更新和早期功能访问权限,请在下方订阅 Storybook 的邮件列表。
交互式 story beta 版现已推出!
— Storybook (@storybookjs) 2021 年 11 月 4 日
在您的 story 中模拟用户行为(单击、键入、悬停)。无需单独的测试文件或运行器。
✅ 在真实浏览器中运行
⚡️ 无等待,无错误
🐙 由@TestingLib提供支持
🛠 低维护
🔍 可视化调试https://#/6ZJgOeraeE pic.twitter.com/ZmlUviFz1R