用途
sfnext-testing 是面向 Salesforce Commerce Cloud 的 Storefront Next 项目的测试技能,用于为 Storefront Next 编写测试。它覆盖 Vitest 单元测试,以及 Storybook 组件故事、交互测试、快照测试和无障碍(a11y)测试。
主要能力
单元测试(Vitest)
测试文件与源文件放在一起,使用 .test.ts 或 .test.tsx 扩展名。示例:
// src/components/product-card/product-card.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import { ProductCard } from './product-card';
import { mockProduct } from '@/test-utils/mocks';
describe('ProductCard', () => {
it('renders product name', () => {
render(<ProductCard product={mockProduct} />);
expect(screen.getByText(mockProduct.productName)).toBeInTheDocument();
});
});
测试工具
共享工具位于 src/test-utils/:
config.ts— 模拟配置对象和 ConfigProvider 包装器context-provider-utils.ts— 用于测试的上下文提供者辅助函数context-provider.tsx— 测试上下文提供者
运行测试
pnpm test # 运行所有测试并生成覆盖率
pnpm test:ui # 打开交互式 Vitest UI
pnpm test:watch # 监听模式(变更时重新运行)
覆盖率要求
阈值在 vitest.thresholds.ts 中强制执行:
| 指标 | 最低值 |
|---|---|
| 行 | 73% |
| 语句 | 73% |
| 函数 | 72% |
| 分支 | 67% |
测试库
- @testing-library/react — 组件渲染与查询
- @testing-library/jest-dom — 自定义 DOM 匹配器(toBeInTheDocument 等)
- @testing-library/user-event — 用户交互模拟
- @vitest/coverage-v8 — 代码覆盖率
- @vitest/ui — 交互式测试 UI
Storybook
每个可复用组件都应有 .stories.tsx 文件。
故事结构示例:
// src/components/product-card/product-card.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-vite';
import { within, expect } from 'storybook/test';
import { waitForStorybookReady } from '@storybook/test-utils';
import { ProductCard } from './product-card';
import { ConfigProvider } from '@/config/context';
import { mockConfig } from '@/test-utils/config';
import { mockProduct } from '@/test-utils/mocks';
const meta: Meta<typeof ProductCard> = {
title: 'Components/ProductCard',
component: ProductCard,
tags: ['autodocs', 'interaction'],
decorators: [
(Story) => (
<ConfigProvider config={mockConfig}>
<Story />
</ConfigProvider>
),
],
};
export default meta;
type Story = StoryObj<typeof ProductCard>;
export const Default: Story = {
args: {
product: mockProduct,
},
play: async ({ canvasElement }) => {
await waitForStorybookReady(canvasElement);
const canvas = within(canvasElement);
await expect(canvas.getByText(mockProduct.productName)).toBeInTheDocument();
},
};
Storybook 命令
pnpm storybook # 开发服务器(端口 6006)
pnpm build-storybook # 构建静态 Storybook
pnpm test-storybook:snapshot # 快照测试
pnpm test-storybook:snapshot:update # 更新快照
pnpm test-storybook:interaction # 交互测试
pnpm test-storybook:a11y # 无障碍测试
pnpm generate:story-tests:coverage # 故事覆盖率报告
故事标签
| 标签 | 用途 |
|---|---|
| autodocs | 启用自动文档 |
| interaction | 纳入交互测试运行 |
| skip-a11y | 从 a11y 测试中排除(谨慎使用) |
路由测试
模拟 loader、action 和 React Router 上下文:
// src/routes/_app.product.$productId.test.tsx
import { describe, test, expect, vi } from 'vitest';
import { render } from '@testing-library/react';
vi.mock('@/components/product-view', () => ({
default: ({ product }: any) => (
<div data-testid="product-view">
<div data-testid="product-name">{product?.name}</div>
</div>
),
}));
使用方式
测试组织结构
src/
├── components/
│ ├── product-card/
│ │ ├── index.tsx # 组件
│ │ ├── index.test.tsx # 单元测试
│ │ └── stories/
│ │ └── index.stories.tsx # 故事
├── routes/
│ ├── _app.product.$productId.tsx
│ └── _app.product.$productId.test.tsx
└── test-utils/ # 共享工具
├── config.ts
└── context-provider-utils.ts
最佳实践
- 就近放置测试 — 将测试文件放在源文件旁边
- 使用测试工具 — 利用 @/test-utils 中的模拟和提供者
- 模拟外部依赖 — 对 API 客户端和上下文使用 vi.mock()
- 测试交互 — 使用 @testing-library/user-event 和 Storybook play 函数
- 测试无障碍 — 使用 Storybook a11y 插件
- 多个故事变体 — 为 Default、Loading、Error 状态创建故事
- 使用视口工具栏 — 通过 Storybook 内置视口工具栏测试响应式布局
适用场景
适用于为 Storefront Next 编写单元测试、组件故事、交互测试、快照测试和无障碍测试的场景,包括组件测试、路由测试以及需要模拟 loader、action 和 React Router 上下文的测试。
相关技能
- storefront-next:sfnext-components — 需要测试的组件模式
- storefront-next:sfnext-data-fetching — 在测试中模拟 loader 和 action
- storefront-next:sfnext-page-designer — 测试 Page Designer 组件
参考文档
- Storybook Patterns Reference — 高级故事模式和测试
限制
资料未提供该技能的安装方式、收费信息、支持平台或具体版本要求,暂未提供。