# Story 1.5: 创建主导出和基础文档 Status: done ## Story 作为测试开发者, 我想要可以导入工具函数并查看快速入门文档, 以便快速开始使用工具包。 ## Acceptance Criteria **Given** Select 工具函数已实现(Story 1.3、1.4 完成) **When** 创建/更新 `src/index.ts` 和 `README.md` **Then** `index.ts` 导出所有公共函数和类型(tree-shakeable) **And** README 包含:安装说明、快速入门、Select 使用示例 **And** README 说明静态 Select 和异步 Select 的区别和使用场景 **And** 所有导出函数有完整的 JSDoc 注释(已在 Story 1.3、1.4 完成) **And** 可以 `import { selectRadixOption } from '@d8d/e2e-test-utils'` ## Tasks / Subtasks - [x] 审查 `src/index.ts` 导出结构 (AC: 1) - [x] 确认使用显式导出(而非通配符)支持 tree-shaking - [x] 确认导出所有公共类型和函数 - [x] 确认导出顺序合理(类型、错误、常量、工具函数) - [x] 更新 `README.md` 添加 Select 工具使用文档 (AC: 2, 3, 4) - [x] 在 API 文档章节添加 `selectRadixOption` 完整说明 - [x] 在 API 文档章节添加 `selectRadixOptionAsync` 完整说明 - [x] 添加静态 Select vs 异步 Select 对比说明 - [x] 添加快速入门示例代码 - [x] 验证导入语句可用性 (AC: 5) - [x] 验证 `import { selectRadixOption } from '@d8d/e2e-test-utils'` 可用 - [x] 验证类型提示正常工作 ## Dev Notes ### Epic 1 背景 **Epic 1 目标:** 测试开发者可以安装 `@d8d/e2e-test-utils` 包,立即使用 Select 工具测试 Radix UI Select 组件。 **本故事在 Epic 中的位置:** 第五个故事,完成主导出文档和 README,使工具包可以被外部项目使用和理解。 ### 当前包状态分析 **已完成的工作(Story 1.1-1.4):** 1. **Story 1.1 - 包基础结构** - ✅ `package.json` 配置(peer dependencies: @playwright/test) - ✅ `tsconfig.json` 严格模式配置 - ✅ `vitest.config.ts` 测试配置 2. **Story 1.2 - 类型定义和错误处理** - ✅ `src/types.ts` - BaseOptions, AsyncSelectOptions, ErrorContext - ✅ `src/errors.ts` - E2ETestError 类 - ✅ `src/constants.ts` - DEFAULT_TIMEOUTS, SELECTOR_STRATEGIES 3. **Story 1.3 - 静态 Select 工具** - ✅ `selectRadixOption(page, label, value)` 函数 - ✅ 完整 JSDoc 注释 - ✅ 三层选择器策略(testid → ARIA → text) 4. **Story 1.4 - 异步 Select 工具** - ✅ `selectRadixOptionAsync(page, label, value, options?)` 函数 - ✅ 完整 JSDoc 注释 - ✅ 网络空闲等待 + 重试机制 **当前 `src/index.ts` 状态:** ```typescript // 当前使用显式导出(正确,支持 tree-shaking) export { selectRadixOption, selectRadixOptionAsync } from './radix-select'; // 通配符导出类型(也正确) export * from './types'; export * from './errors'; export * from './constants'; ``` **当前 `README.md` 状态:** - ✅ 已有项目简介和特性说明 - ✅ 已有安装说明 - ✅ 已有类型定义和错误类文档 - ❌ **缺少 Select 工具函数使用示例** - ❌ **缺少静态 vs 异步 Select 区分说明** ### 本故事的核心任务 **任务 1:审查 index.ts 导出结构** 当前导出结构已经正确: - 使用显式命名导出支持 tree-shaking - 类型使用通配符导出(可以,因为类型不增加运行时开销) - 导出顺序合理 **可能需要的改进(可选):** - 如果未来工具函数增多,可以考虑为每个模块添加明确的 re-export - 保持当前的简洁性已经足够 **任务 2:更新 README.md 添加 Select 工具文档** 需要在 README 中添加以下内容: 1. **Select 工具使用示例**(添加到"快速入门"或"API 文档"章节) 2. **静态 vs 异步 Select 对比**(新增对比表格或说明) 3. **实际使用场景示例**(残疾人管理测试案例) ### 架构约束和模式 **从架构文档中必须遵循的决策:** **文档结构需求(Architecture - Documentation Requirements):** - README 必须包含:项目简介、安装说明、快速入门、API 文档 - 每个工具函数至少有 1 个实际使用示例 - 文档说明静态 Select 和异步 Select 的区别和使用场景 - 新测试开发者可以在 30 分钟内使用工具函数编写第一个测试(NFR37) **Tree-shaking 需求(Architecture - Bundle Optimization):** - 主导出使用命名导出(named exports),不使用默认导出 - 避免导出整个模块,而是明确指定导出的函数和类型 - 类型定义可以安全使用通配符导出(不增加运行时开销) **API 文档标准(Architecture - API Documentation):** - 所有公共 API 必须有 JSDoc 注释(已在 Story 1.3、1.4 完成) - README 中的示例应与 JSDoc 中的 @example 保持一致 - 参数说明使用表格或列表格式,清晰展示每个参数的类型和用途 ### 技术实现要求 **`src/index.ts` 审查指南:** **当前导出结构(已正确):** ```typescript /** * @d8d/e2e-test-utils * * E2E 测试工具集 - 专门用于测试 Radix UI 组件的 Playwright 工具函数 * * @packageDocumentation */ // 导出类型定义(通配符导出可以,类型不增加运行时开销) export * from './types'; // 导出错误类(通配符导出可以) export * from './errors'; // 导出常量(通配符导出可以) export * from './constants'; // Radix UI Select 工具(显式导出,支持 tree-shaking) export { selectRadixOption, selectRadixOptionAsync } from './radix-select'; ``` **审查清单:** - ✅ 使用显式命名导出(非默认导出) - ✅ 工具函数使用显式导出列表(而非 `export * from './radix-select'`) - ✅ 类型定义使用通配符导出(可接受,类型不增加运行时开销) - ✅ 包级 JSDoc 注释完整 - ✅ 导出顺序合理(类型 → 错误 → 常量 → 工具函数) **无需修改当前结构**,除非发现以下问题: - ❌ 如果有默认导出,需要改为命名导出 - ❌ 如果有 `export * from './radix-select'`,需要改为显式导出 **`README.md` 创建指南:** **必须包含的章节:** 1. **项目简介**(1-2 段话) - 说明工具包的用途 - 说明支持的组件类型(Radix UI) - 说明核心价值(简化 E2E 测试) 2. **安装说明** ```bash # 使用 pnpm workspace 协议(Monorepo 内) pnpm add -D @d8d/e2e-test-utils@workspace:* # 使用 npm(发布后) npm install --save-dev @d8d/e2e-test-utils ``` 3. **快速入门**(本故事核心任务) ```typescript import { selectRadixOption, selectRadixOptionAsync } from '@d8d/e2e-test-utils'; // 静态 Select 示例 await selectRadixOption(page, '残疾类型', '视力残疾'); // 异步 Select 示例 await selectRadixOptionAsync(page, '省份', '广东省'); ``` 4. **API 文档**(本故事核心任务) - `selectRadixOption` - 静态 Select 工具 - `selectRadixOptionAsync` - 异步 Select 工具 - 参数表格说明 - 使用示例 5. **静态 vs 异步 Select**(本故事核心任务) - 区别对比表格 - 使用场景说明 - 选择建议 6. **类型定义**(已存在,保持) 7. **错误处理**(已存在,保持) 8. **常量**(已存在,保持) ### 与前一个故事的集成 **Story 1.4 已完成的工作:** - ✅ 静态 Select 函数 `selectRadixOption()` 已实现并导出 - ✅ 异步 Select 函数 `selectRadixOptionAsync()` 已实现并导出 - ✅ 所有导出函数有完整的 JSDoc 注释 - ✅ 类型定义完整(BaseOptions, AsyncSelectOptions) **本故事需要做的:** - 审查并确认 `src/index.ts` 导出结构正确(可能无需修改) - 创建 `README.md` 添加 Select 工具使用文档和示例 - 区分静态 Select 和异步 Select 的使用场景 ### 前一个故事的关键经验 **从 Story 1.3、1.4 中学习到的经验:** 1. **JSDoc 注释标准:** - 使用 `@description` 标签添加详细描述 - 使用 `@param` 标签说明每个参数 - 使用 `@throws` 标签说明可能抛出的错误 - 使用 `@example` 标签提供实际使用示例 2. **错误处理模式:** - 使用 `E2ETestError` 类提供结构化错误信息 - 错误消息包含:操作类型、目标、期望值、可用选项、修复建议 3. **选择器策略:** - 优先级:`data-testid` → `aria-label` + `role` → `text content` - 推荐在 Radix 组件上添加 `data-testid` 属性 ### 静态 Select vs 异步 Select | 特性 | 静态 Select (`selectRadixOption`) | 异步 Select (`selectRadixOptionAsync`) | |------|----------------------------------|----------------------------------------| | **选项加载时机** | 页面加载时已存在 DOM 中 | 点击触发器后 API 加载 | | **使用场景** | 枚举类型(残疾类型、性别等) | 动态数据(省份、城市、银行等) | | **等待策略** | 立即查找选项 | 等待网络请求 + 选项出现 | | **默认超时** | 2000ms | 5000ms | | **配置对象** | 无 | `AsyncSelectOptions` | | **网络空闲等待** | 不需要 | 默认启用 | | **函数签名** | `selectRadixOption(page, label, value)` | `selectRadixOptionAsync(page, label, value, options?)` | **选择建议:** - 如果下拉框选项在页面加载时已存在 → 使用 `selectRadixOption()` - 如果下拉框选项需要从 API 动态加载 → 使用 `selectRadixOptionAsync()` - 不确定时,可以使用异步版本(会有额外等待,但更稳定) ### README 模板参考 **快速入门章节建议内容:** ```markdown ## 快速入门 ### 安装 \`\`\`bash # Monorepo 内使用 workspace 协议 pnpm add -D @d8d/e2e-test-utils@workspace:* # 或使用 npm(发布后) npm install --save-dev @d8d/e2e-test-utils \`\`\` ### 基本使用 \`\`\`typescript import { selectRadixOption, selectRadixOptionAsync } from '@d8d/e2e-test-utils'; // 选择静态下拉框选项(如残疾类型) await selectRadixOption(page, '残疾类型', '视力残疾'); // 选择异步加载的下拉框选项(如省份) await selectRadixOptionAsync(page, '省份', '广东省'); \`\`\` ### 选择器策略 工具函数按以下优先级查找下拉框触发器: 1. `data-testid="标签-trigger"` - 推荐,最稳定 2. `aria-label="标签"` + `role="combobox"` - 无障碍属性 3. `text="标签"` - 文本匹配(兜底) **推荐做法:** 在测试代码或应用中为 Radix Select 添加 `data-testid` 属性。 ``` **API 文档章节建议内容:** ```markdown ## API 文档 ### selectRadixOption() 选择静态枚举型 Radix UI Select 选项。 **函数签名:** \`\`\`typescript function selectRadixOption( page: Page, label: string, value: string ): Promise \`\`\` **参数:** | 参数 | 类型 | 说明 | |------|------|------| | `page` | `Page` | Playwright Page 对象 | | `label` | `string` | 下拉框的标签文本 | | `value` | `string` | 要选择的选项值 | **示例:** \`\`\`typescript // 选择残疾类型 await selectRadixOption(page, '残疾类型', '视力残疾'); // 选择性别 await selectRadixOption(page, '性别', '男'); \`\`\` --- ### selectRadixOptionAsync() 选择异步加载的 Radix UI Select 选项。 **函数签名:** \`\`\`typescript function selectRadixOptionAsync( page: Page, label: string, value: string, options?: AsyncSelectOptions ): Promise \`\`\` **参数:** | 参数 | 类型 | 说明 | |------|------|------| | `page` | `Page` | Playwright Page 对象 | | `label` | `string` | 下拉框的标签文本 | | `value` | `string` | 要选择的选项值 | | `options` | `AsyncSelectOptions` | 可选配置对象 | | `options.timeout` | `number` | 超时时间(毫秒),默认 5000 | | `options.waitForOption` | `boolean` | 是否等待选项加载,默认 true | | `options.waitForNetworkIdle` | `boolean` | 是否等待网络空闲,默认 true | **示例:** \`\`\`typescript // 选择省份(使用默认配置) await selectRadixOptionAsync(page, '省份', '广东省'); // 选择城市(自定义超时) await selectRadixOptionAsync(page, '城市', '深圳市', { timeout: 10000 }); // 禁用网络空闲等待(网络不稳定时) await selectRadixOptionAsync(page, '地区', '华南', { waitForNetworkIdle: false }); \`\`\` ``` ### 项目标准对齐 **与项目标准对齐:** - 遵循 `docs/standards/testing-standards.md` 中的测试规范 - 遵循 `docs/standards/e2e-radix-testing.md` 中的 Radix UI E2E 测试标准 - 遵循 `docs/standards/coding-standards.md` 中的编码标准 **文档标准:** - README 使用 Markdown 格式 - 代码示例使用 TypeScript 语法高亮 - 参数说明使用表格格式 - 添加实际可运行的示例代码 **TypeScript 配置:** - 严格模式已启用(`strict: true`) - 所有类型定义支持 IDE 自动补全 - 导入语句支持类型推导 ### 性能约束 **从 NFR 提取的性能要求:** - **NFR37**: 新测试开发者可以在 30 分钟内使用工具函数编写第一个测试 - **NFR39**: 函数命名清晰直观,不需要频繁查看文档 - **NFR40**: 错误消息对新手友好,包含问题诊断和建议修复步骤 **README 设计考虑:** - 提供简洁的快速入门章节(5 分钟内理解) - 提供完整的 API 参考文档 - 提供静态 vs 异步 Select 对比说明 - 提供实际使用场景示例 ### 文件结构约束 **必须遵循的文件结构:** ``` packages/e2e-test-utils/ ├── src/ │ ├── index.ts # 主导出(审查,可能无需修改) │ ├── types.ts # 共享类型定义 │ ├── errors.ts # 错误类 │ ├── constants.ts # 常量定义 │ └── radix-select.ts # Radix UI Select 工具 ├── README.md # 包文档(本故事创建) ├── package.json # 包配置 ├── tsconfig.json # TypeScript 配置 └── vitest.config.ts # 测试配置 ``` **禁止事项(Anti-Patterns):** - ❌ 使用默认导出(`export default`) - ❌ 在 README 中使用不准确的示例代码 - ❌ 缺少静态 vs 异步 Select 的区分说明 - ❌ 示例代码与实际 API 不匹配 ### 测试要求 **文档验证方法:** - 手动验证 README 中的示例代码可以正确运行 - 验证导入语句 `import { selectRadixOption } from '@d8d/e2e-test-utils'` 可用 - 验证类型提示在 IDE 中正常工作 - 验证快速入门章节可在 30 分钟内完成(NFR37) **集成测试(在 Epic 3 中实现):** - 本故事创建的文档将在 Epic 3 中通过实际 E2E 测试验证 - 残疾人管理测试将作为完整的使用示例 ### Project Structure Notes **对齐项目 Monorepo 架构:** - 包位于 `packages/e2e-test-utils/` - 使用 workspace 协议安装:`@d8d/e2e-test-utils@workspace:*` - 与现有 `@d8d/shared-test-util`(后端集成测试)分离 **与项目标准对齐:** - 遵循 `docs/standards/testing-standards.md` 中的测试规范 - 遵循 `docs/standards/web-ui-testing-standards.md` 中的 Web UI 测试规范 - 遵循 `docs/standards/e2e-radix-testing.md` 中的 Radix UI E2E 测试标准(核心标准文档) ### References **PRD 来源:** - [PRD - E2E测试工具包](_bmad-output/planning-artifacts/prd.md) - 项目需求概述 - [PRD - 文档和开发者支持](_bmad-output/planning-artifacts/epics.md#文档和开发者支持-fr33-fr40) - FR33-FR40 需求 **Architecture 来源:** - [Architecture - 文档需求](_bmad-output/planning-artifacts/architecture.md#documentation-requirements) - README 和 JSDoc 要求 - [Architecture - 包结构需求](_bmad-output/planning-artifacts/architecture.md#package-structure-requirements) - 导出规范 **标准文档来源:** - [E2E Radix UI 测试标准](docs/standards/e2e-radix-testing.md) - 核心测试标准文档 - [Project Context](_bmad-output/project-context.md) - 项目技术栈和规则 **Epic 来源:** - [Epic 1 - Story 1.5](_bmad-output/planning-artifacts/epics.md#story-15-创建主导出和基础文档) - 原始用户故事和验收标准 **前一个故事:** - [Story 1.1 - 创建包基础结构和配置](_bmad-output/implementation-artifacts/1-1-create-package-structure.md) - 包基础设施 - [Story 1.2 - 实现类型定义和错误处理](_bmad-output/implementation-artifacts/1-2-implement-types-errors.md) - 类型、错误、常量 - [Story 1.3 - 实现静态 Select 工具函数](_bmad-output/implementation-artifacts/1-3-static-select-tool.md) - 静态 Select 函数 - [Story 1.4 - 实现异步 Select 工具函数](_bmad-output/implementation-artifacts/1-4-async-select-tool.md) - 异步 Select 函数 ## Dev Agent Record ### Agent Model Used Claude (d8d-model) via create-story workflow ### Debug Log References ### Completion Notes List - 故事创建时间: 2026-01-09 - 基于 PRD、Architecture、E2E Radix 测试标准文档创建 - 基于 Story 1.3、1.4 的实现状态创建 - 包含完整的 README 创建指南和模板 - 区分静态和异步 Select 的使用场景 - 包含 tree-shaking 导出最佳实践 **实现完成 (2026-01-09):** - ✅ `src/index.ts` 导出结构审查完成 - 无需修改,结构已正确 - ✅ README.md 添加 Select 工具使用文档 - 快速入门章节添加 Select 工具示例 - 选择器策略说明 - API 文档添加 `selectRadixOption()` 完整说明 - API 文档添加 `selectRadixOptionAsync()` 完整说明 - 静态 vs 异步 Select 对比表格 - 选择建议和实际案例对比 - ✅ 导入语句验证通过 - TypeScript 类型检查通过 - 包构建成功 - 生成的 .d.ts 文件包含所有类型定义 - 单元测试 13/13 通过 **代码审查完成 (2026-01-09):** - 🔍 Adversarial Code Review 完成 - 发现并修复 6 个问题(0 Critical, 4 Medium, 2 Low) - 修复内容: - `src/index.ts:31` - 修复占位符 URL - `README.md:478` - 更新工具状态描述(radix-select.ts 已完成) - `README.md:145-170` - 修复 Fixtures 使用说明 - `src/types.ts:82-145` - 为未实现类型添加 `@beta` 标签 - `README.md` - 添加 TypeScript 配置说明 - `README.md:538-539` - 移除相对路径链接 **实现建议:** - `src/index.ts` 当前结构已经正确,可能无需修改 - 主要任务是创建 `README.md` 添加 Select 工具使用文档 - README 应包含:安装说明、快速入门、API 文档、静态 vs 异步 Select 对比 - 确保示例代码与实际 API 一致 - 确保文档简洁清晰,新开发者可在 30 分钟内上手 **关键检查点:** - ✅ `src/index.ts` 使用显式命名导出(支持 tree-shaking) - ✅ 所有 Select 函数有完整 JSDoc(已在 Story 1.3、1.4 完成) - ✅ README.md 已添加 Select 工具使用文档 - ✅ README.md 已添加静态 vs 异步 Select 对比说明 ### File List **本故事修改的文件:** - `packages/e2e-test-utils/README.md` - 添加 Select 工具使用文档和静态 vs 异步 Select 对比说明 **审查但未修改的文件:** - `packages/e2e-test-utils/src/index.ts` - 导出结构审查确认正确,无需修改 **相关文件(已在 Story 1.1-1.4 中完成,本故事使用):** - `packages/e2e-test-utils/src/radix-select.ts` - Select 工具函数实现 - `packages/e2e-test-utils/src/types.ts` - 类型定义 - `packages/e2e-test-utils/src/errors.ts` - 错误类 - `packages/e2e-test-utils/src/constants.ts` - 常量定义 **只读参考文件:** - `_bmad-output/implementation-artifacts/1-3-static-select-tool.md` - 静态 Select 实现 - `_bmad-output/implementation-artifacts/1-4-async-select-tool.md` - 异步 Select 实现 - `_bmad-output/planning-artifacts/epics.md` - Epic 和故事定义 - `_bmad-output/planning-artifacts/architecture.md` - 架构决策和模式 - `docs/standards/e2e-radix-testing.md` - E2E Radix UI 测试标准