# @d8d/e2e-test-utils > E2E 测试工具集 - 专门用于测试 Radix UI 组件的 Playwright 工具函数 [![TypeScript](https://img.shields.io/badge/TypeScript-5.8+-blue)](https://www.typescriptlang.org/) [![Playwright](https://img.shields.io/badge/Playwright-1.40+-green)](https://playwright.dev/) [![Vitest](https://img.shields.io/badge/Vitest-3.2+-purple)](https://vitest.dev/) ## 📋 简介 `@d8d/e2e-test-utils` 是一个专为 Radix UI 组件设计的 E2E 测试工具集。它提供了一组强大且易于使用的函数,帮助你更高效地编写和维护端到端测试。 ### 核心特性 - 🎯 **Radix UI 专用** - 针对无障碍组件优化的选择器策略 - 🔒 **TypeScript 全支持** - 完整的类型定义和 JSDoc 注释 - 📦 **零运行时依赖** - 仅依赖 Playwright 作为 peer dependency - 🧪 **开箱即用的测试数据** - 包含常用测试场景的 fixtures - 🌳 **Tree-shakeable** - 按需导入,只打包使用的代码 - ⚡ **严格模式** - 启用 TypeScript 严格类型检查 ## 📦 安装 ### Monorepo 项目(Workspace) ```bash pnpm add -D @d8d/e2e-test-utils@workspace:* ``` ### 独立项目 ```bash pnpm add -D @d8d/e2e-test-utils ``` ### Peer Dependencies 确保你的项目已安装 `@playwright/test`: ```bash pnpm add -D @playwright/test ``` ## 🚀 快速入门 ### 基础使用 ```typescript import { test, expect } from '@playwright/test'; import { BaseOptions, E2ETestError, DEFAULT_TIMEOUTS } from '@d8d/e2e-test-utils'; test('示例测试', async ({ page }) => { // 使用工具函数进行测试 const options: BaseOptions = { timeout: DEFAULT_TIMEOUTS.static }; // 测试逻辑... }); ``` ### 使用类型定义 ```typescript import type { BaseOptions, ErrorContext } from '@d8d/e2e-test-utils'; // 定义自定义选项 const options: BaseOptions = { timeout: 5000 }; // 构建错误上下文 const errorContext: ErrorContext = { operation: 'selectOption', target: 'dropdown', expected: 'Option A', actual: 'Option B', available: ['Option A', 'Option B', 'Option C'], suggestion: '检查选项值是否正确' }; ``` ### 使用错误类 ```typescript import { E2ETestError } from '@d8d/e2e-test-utils'; test('错误处理示例', async ({ page }) => { const selectElement = await page.$('[data-testid="my-select"]'); if (!selectElement) { throw new E2ETestError({ operation: 'findSelect', target: '[data-testid="my-select"]', suggestion: '确认 data-testid 属性是否正确设置' }); } }); ``` ### 使用测试数据 ```typescript // 导入测试用户数据 import testUsers from '@d8d/e2e-test-utils/tests/fixtures/data/test-users.json' assert { type: 'json' }; test('用户登录', async ({ page }) => { const user = testUsers.users[0]; await page.goto('/login'); await page.fill('[name="email"]', user.email); await page.fill('[name="password"]', 'test_password'); await page.click('button[type="submit"]'); await expect(page).toHaveURL('/dashboard'); }); ``` ## 📚 API 文档 ### 类型定义 #### `BaseOptions` 基础配置选项,所有工具函数配置对象的基类。 ```typescript interface BaseOptions { /** 超时时间(毫秒)*/ timeout?: number; } ``` #### `ErrorContext` 错误上下文信息,用于结构化错误报告。 ```typescript interface ErrorContext { /** 操作类型(如 'selectRadixOption')*/ operation: string; /** 目标(如下拉框标签)*/ target: string; /** 期望值 */ expected?: string; /** 实际值 */ actual?: string; /** 可用选项列表 */ available?: string[]; /** 修复建议 */ suggestion?: string; } ``` ### 错误类 #### `E2ETestError` E2E 测试专用错误类,提供结构化的错误上下文信息。 ```typescript class E2ETestError extends Error { constructor( public readonly context: ErrorContext, message?: string ) } ``` **示例:** ```typescript throw new E2ETestError({ operation: 'selectOption', target: 'Role Selector', expected: 'Admin', actual: 'User', available: ['Admin', 'User', 'Guest'], suggestion: '确认选项值是否正确拼写' }); // 输出: // ❌ selectOption failed // Target: Role Selector // Expected: Admin // Actual: User // Available: Admin, User, Guest // 💡 确认选项值是否正确拼写 ``` ### 常量 #### `DEFAULT_TIMEOUTS` 默认超时配置(毫秒)。 ```typescript const DEFAULT_TIMEOUTS = { /** 静态选项超时 */ static: 2000, /** 异步选项超时 */ async: 5000, /** 网络空闲超时 */ networkIdle: 10000 } as const; ``` **使用示例:** ```typescript import { DEFAULT_TIMEOUTS } from '@d8d/e2e-test-utils'; await page.waitForTimeout(DEFAULT_TIMEOUTS.static); ``` #### `SELECTOR_STRATEGIES` 支持的选择器策略列表。 ```typescript const SELECTOR_STRATEGIES = [ 'data-testid', 'aria-label + role', 'text content + role' ] as const; ``` **策略优先级:** 1. `data-testid` - 最高优先级,最稳定 2. `aria-label + role` - 遵循无障碍标准 3. `text content + role` - 兜底方案 ## 🧪 测试 ### 运行测试 ```bash # 运行所有单元测试 pnpm test:unit # 运行测试并生成覆盖率报告 pnpm test:coverage # 监听模式(开发时使用) pnpm test ``` ### 测试结构 ``` tests/ ├── fixtures/ # 测试资源 │ ├── data/ # 测试数据(JSON) │ └── images/ # 测试图片 ├── unit/ # 单元测试(Vitest) ├── integration/ # 集成测试(Playwright) └── stability/ # 稳定性测试 ``` ### 使用 Fixtures #### 数据文件 ```typescript // 导入测试用户数据 import testUsers from '@d8d/e2e-test-utils/tests/fixtures/data/test-users.json' assert { type: 'json' }; const user = testUsers.users[0]; console.log(user.name, user.email); ``` #### 图片文件 图片文件用于测试文件上传功能。请参考 `tests/fixtures/images/README.md` 了解如何添加测试图片。 ## 🛠️ 开发 ### 项目结构 ``` packages/e2e-test-utils/ ├── src/ │ ├── index.ts # 主导出,tree-shakeable │ ├── types.ts # 共享类型定义 │ ├── errors.ts # 错误类和错误处理 │ ├── constants.ts # 常量定义 │ ├── radix-select.ts # Radix UI Select 工具(开发中) │ ├── file-upload.ts # 文件上传工具(规划中) │ ├── form-helper.ts # 表单辅助函数(规划中) │ ├── dialog.ts # 对话框操作(规划中) │ └── dynamic-list.ts # 动态列表管理(规划中) ├── tests/ │ ├── fixtures/ # 测试资源 │ ├── unit/ # Vitest 单元测试 │ ├── integration/ # Playwright 集成测试 │ └── stability/ # 稳定性测试 ├── package.json ├── tsconfig.json ├── vitest.config.ts └── README.md ``` ### 可用脚本 ```bash # 类型检查 pnpm typecheck # 构建包 pnpm build # 开发模式(监听文件变化) pnpm dev # 运行测试 pnpm test:unit # 生成覆盖率报告 pnpm test:coverage ``` ## 🤝 贡献 欢迎贡献!请遵循以下步骤: 1. Fork 本仓库 2. 创建特性分支 (`git checkout -b feature/amazing-feature`) 3. 提交更改 (`git commit -m 'Add some amazing feature'`) 4. 推送到分支 (`git push origin feature/amazing-feature`) 5. 开启 Pull Request ### 代码规范 - 使用 TypeScript 严格模式 - 所有导出的函数/类型必须有完整的 JSDoc 注释 - 单元测试覆盖率 ≥ 80% - 遵循项目的 ESLint 和 Prettier 配置 ## 📝 License MIT ## 🔗 相关资源 - [Radix UI](https://www.radix-ui.com/) - [Playwright](https://playwright.dev/) - [E2E Radix UI 测试标准](../../docs/standards/e2e-radix-testing.md) - [项目测试规范](../../docs/standards/testing-standards.md)