使用 Storybook 和 Vitest 进行交互式 Angular 组件测试
Source: Dev.to
Storybook 是一个前端工作坊,用于在隔离环境中构建 UI 组件和页面。将 Storybook 与 Vitest 结合使用可实现交互式组件测试。
本指南将带您使用 Vite 和 @storybook/addon-vitest 包在 Angular 中设置 Storybook,以进行交互式组件测试。
1. 设置 Storybook
如果你还没有配置 Storybook,请运行以下命令为 Angular 项目初始化它:
npx storybook@latest init --type angular
此命令会安装所需的 Storybook 依赖,并创建包含示例组件(包括一个 Button 组件)的 Storybook 配置。按照提示操作并提交生成的文件。
2. 配置 Storybook 使用 Vite 与 Analog
为 Analog 安装 Angular 集成
npm install @analogjs/storybook-angular @angular/animations zone.js --save-dev
更新 .storybook/main.ts
import { StorybookConfig } from '@analogjs/storybook-angular';
const config: StorybookConfig = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@analogjs/storybook-angular',
options: {},
},
};
export default config;
在 angular.json 中调整 Storybook 目标
{
"storybook": {
"builder": "@analogjs/storybook-angular:start-storybook",
"options": {
"configDir": ".storybook",
"styles": ["src/styles.css"],
"experimentalZoneless": true
}
},
"build-storybook": {
"builder": "@analogjs/storybook-angular:build-storybook",
"options": {
"configDir": ".storybook",
"styles": ["src/styles.css"],
"experimentalZoneless": true
}
}
}
运行 Storybook 验证设置
npm run storybook
运行后,你应该会看到 Storybook 启动并展示示例组件。
3. 为交互测试设置 Vitest
安装 Vitest 相关依赖
npm install @analogjs/vitest-angular @storybook/addon-vitest vitest @vitest/browser-playwright --save-dev
在 .storybook/main.ts 中添加 Vitest 插件
import { StorybookConfig } from '@analogjs/storybook-angular';
const config: StorybookConfig = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-vitest',
],
framework: {
name: '@analogjs/storybook-angular',
options: {},
},
};
export default config;
创建 Vitest 初始化文件
.storybook/vitest.setup.ts
import '@angular/compiler';
import { setProjectAnnotations } from '@analogjs/storybook-angular/testing';
import { beforeAll } from 'vitest';
import * as projectAnnotations from './preview';
const project = setProjectAnnotations([projectAnnotations]);
beforeAll(project.beforeAll);
更新 Storybook 的 TypeScript 配置
.storybook/tsconfig.json
{
"extends": "../tsconfig.app.json",
"compilerOptions": {
"types": ["node"],
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"exclude": ["../src/test.ts", "../src/**/*.spec.ts"],
"include": [
"../src/**/*.stories.*",
"./preview.ts",
"./vitest.setup.ts"
],
"files": ["./typings.d.ts"]
}
添加 Vitest 配置文件
vitest.config.ts
///
import { defineConfig } from 'vite';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { storybookTest } } from '@storybook/addon-vitest/vitest-plugin';
import { playwright } from '@vitest/browser-playwright';
const dirname =
typeof __dirname !== 'undefined'
? __dirname
: path.dirname(fileURLToPath(import.meta.url));
export default defineConfig({
test: {
projects: [
{
extends: true,
plugins: [
storybookTest({
configDir: path.join(dirname, '.storybook'),
}),
],
test: {
name: 'storybook',
browser: {
enabled: true,
headless: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
},
setupFiles: ['.storybook/vitest.setup.ts'],
},
},
],
},
});
安装 Playwright 浏览器二进制文件
npx playwright install chromium
在 angular.json 中添加 test-storybook 目标
{
"test-storybook": {
"builder": "@analogjs/vitest-angular:test",
"options": {
"configFile": "vitest.config.ts"
}
}
}
在 package.json 中添加脚本
{
"scripts": {
"test-storybook": "ng run your-app:test-storybook"
}
}
将 your-app 替换为实际的 Angular 项目名称。
4. 编写交互测试
Storybook 初始设置生成的 Button 组件是进行交互测试的理想候选。下面示例展示了如何添加一个使用 Storybook 测试工具的 play 函数。
import type { Meta, StoryObj } from '@storybook/angular';
import { fn, expect, userEvent, within } from '@storybook/test';
import { Button } from './button.component';
const meta: Meta = {
title: 'Example/Button',
component: Button,
argTypes: {
onClick: { action: 'clicked' },
},
};
export default meta;
type Story = StoryObj;
export const Primary: Story = {
args: {
label: 'Button',
primary: true,
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /button/i });
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalled();
},
};
运行 npm run test-storybook 将对 Storybook 实例执行交互测试。
下面是一个更完整的示例,包含了额外的 stories 并演示了在不同场景下使用 play 函数。
import type { Meta, StoryObj } from '@storybook/angular';
import { within, userEvent, expect } from '@storybook/testing-library';
import { fn } from '@storybook/addon-actions';
import { Button } from './button.component';
const meta: Meta = {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
args: { onClick: fn() },
};
export default meta;
type Story = StoryObj;
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /Button/i });
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalled();
},
};
export const Secondary: Story = {
args: {
label: 'Button',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /Button/i });
await expect(button).toBeInTheDocument();
await expect(button).toHaveClass('storybook-button--secondary');
},
};
play 函数可以帮助你:
- 使用
within(canvasElement)查询元素 - 使用
userEvent模拟用户交互 - 使用
expect进行断言 - 以及更多 …
运行测试
使用以下命令运行交互测试:
npm run test-storybook
此命令会在真实浏览器中使用 Playwright 执行所有带有 play 函数的 story,帮助你确信组件按预期工作。
你也可以直接在 Storybook UI 中运行测试:
- 启动 Storybook。
- 在侧边栏点击 Run Tests 按钮,或导航到某个 story,交互测试将在 Interactions 面板中自动运行。
结论
使用 Storybook 与 Angular 和 Vite 可以实现更快的构建速度和更好的开发者体验。添加 Vitest 进行交互测试,使您能够直接在故事中验证组件行为。
查看包含完整 Storybook 设置的示例仓库。
如果您喜欢这篇文章,请点击 ❤️ 让更多人看到。关注 AnalogJS 和 我 在 Twitter/X 上,并订阅我的 YouTube 频道 获取更多内容!