使用 Storybook 和 Vitest 进行交互式 Angular 组件测试

发布: (2026年1月15日 GMT+8 01:36)
6 min read
原文: Dev.to

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 中运行测试:

  1. 启动 Storybook。
  2. 在侧边栏点击 Run Tests 按钮,或导航到某个 story,交互测试将在 Interactions 面板中自动运行。

结论

使用 Storybook 与 Angular 和 Vite 可以实现更快的构建速度和更好的开发者体验。添加 Vitest 进行交互测试,使您能够直接在故事中验证组件行为。

查看包含完整 Storybook 设置的示例仓库。

如果您喜欢这篇文章,请点击 ❤️ 让更多人看到。关注 AnalogJS 在 Twitter/X 上,并订阅我的 YouTube 频道 获取更多内容!

Back to Blog

相关文章

阅读更多 »

构建 Tailwind CSS 下拉菜单

构建 Tailwind CSS 下拉菜单 !用于构建 Tailwind CSS 下拉菜单的封面图片 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover...