You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.0 KiB
6.0 KiB
测试策略
文档版本:v1.1
最后更新:2025-01-18
状态:⚠️ 规划中
目录
1. 测试金字塔
┌──────────┐
│ E2E │ 少量关键流程
│ Tests │
┌┴──────────┴┐
│Integration │ 主要业务流程
│ Tests │
┌┴────────────┴┐
│ Unit Tests │ 工具函数、Hooks、组件
└──────────────┘
2. 单元测试
注意:测试工具配置尚未在项目中实现,以下内容作为未来规划参考。
2.1 Vitest 配置(规划)
// vitest.config.ts
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: "jsdom",
setupFiles: ["./src/test/setup.ts"],
include: ["src/**/*.{test,spec}.{ts,tsx}"],
coverage: {
reporter: ["text", "json", "html"],
exclude: ["node_modules/", "src/test/"],
},
},
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
2.2 工具函数测试示例
// src/utils/format.test.ts
import { describe, it, expect } from "vitest";
import { formatDuration, formatFileSize } from "./format";
describe("formatDuration", () => {
it("formats seconds to mm:ss", () => {
expect(formatDuration(65)).toBe("01:05");
expect(formatDuration(3661)).toBe("01:01:01");
});
it("handles zero", () => {
expect(formatDuration(0)).toBe("00:00");
});
});
describe("formatFileSize", () => {
it("formats bytes correctly", () => {
expect(formatFileSize(1024)).toBe("1 KB");
expect(formatFileSize(1048576)).toBe("1 MB");
});
});
3. 组件测试
3.1 测试示例
// src/components/features/storyboard/StoryboardItem.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { StoryboardItem } from './StoryboardItem';
const mockStoryboard = {
id: '1',
title: 'Test Storyboard',
description: 'Test description',
thumbnailUrl: '/test.jpg',
duration: 5,
order: 0,
};
describe('StoryboardItem', () => {
it('renders storyboard info', () => {
render(
<StoryboardItem
storyboard={mockStoryboard}
isSelected={false}
onSelect={() => {}}
/>
);
expect(screen.getByText('Test Storyboard')).toBeInTheDocument();
expect(screen.getByText('Test description')).toBeInTheDocument();
});
it('calls onSelect when clicked', () => {
const onSelect = vi.fn();
render(
<StoryboardItem
storyboard={mockStoryboard}
isSelected={false}
onSelect={onSelect}
/>
);
fireEvent.click(screen.getByRole('button'));
expect(onSelect).toHaveBeenCalledWith('1');
});
it('applies selected styles', () => {
render(
<StoryboardItem
storyboard={mockStoryboard}
isSelected={true}
onSelect={() => {}}
/>
);
expect(screen.getByRole('button')).toHaveClass('border-primary');
});
});
4. Hook 测试
// src/hooks/useDebounce.test.ts
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useDebounce } from "./useDebounce";
describe("useDebounce", () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
it("returns initial value immediately", () => {
const { result } = renderHook(() => useDebounce("hello", 500));
expect(result.current).toBe("hello");
});
it("debounces value changes", () => {
const { result, rerender } = renderHook(
({ value }) => useDebounce(value, 500),
{ initialProps: { value: "hello" } },
);
rerender({ value: "world" });
expect(result.current).toBe("hello");
act(() => {
vi.advanceTimersByTime(500);
});
expect(result.current).toBe("world");
});
});
5. E2E 测试
5.1 Playwright 配置(规划)
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
testDir: "./e2e",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: "html",
use: {
baseURL: "http://localhost:5173",
trace: "on-first-retry",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
webServer: {
command: "npm run dev",
url: "http://localhost:5173",
reuseExistingServer: !process.env.CI,
},
});
5.2 E2E 测试示例
// e2e/editor.spec.ts
import { test, expect } from "@playwright/test";
test.describe("Editor Page", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/editor/project-1");
});
test("displays storyboard list", async ({ page }) => {
await expect(page.getByTestId("storyboard-panel")).toBeVisible();
await expect(page.getByTestId("storyboard-item")).toHaveCount(5);
});
test("can select a storyboard", async ({ page }) => {
const firstItem = page.getByTestId("storyboard-item").first();
await firstItem.click();
await expect(firstItem).toHaveClass(/selected/);
});
test("plays video on play button click", async ({ page }) => {
await page.getByRole("button", { name: "播放" }).click();
await expect(page.getByRole("button", { name: "暂停" })).toBeVisible();
});
});
相关文档
最后更新:2025-01-18 | 版本:v1.1