1-5-main-export-docs.md 20 KB

Story 1.5: 创建主导出和基础文档

Status: done

Story

作为测试开发者, 我想要可以导入工具函数并查看快速入门文档, 以便快速开始使用工具包。

Acceptance Criteria

Given Select 工具函数已实现(Story 1.3、1.4 完成) When 创建/更新 src/index.tsREADME.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

  • 审查 src/index.ts 导出结构 (AC: 1)
    • 确认使用显式导出(而非通配符)支持 tree-shaking
    • 确认导出所有公共类型和函数
    • 确认导出顺序合理(类型、错误、常量、工具函数)
  • 更新 README.md 添加 Select 工具使用文档 (AC: 2, 3, 4)
    • 在 API 文档章节添加 selectRadixOption 完整说明
    • 在 API 文档章节添加 selectRadixOptionAsync 完整说明
    • 添加静态 Select vs 异步 Select 对比说明
    • 添加快速入门示例代码
  • 验证导入语句可用性 (AC: 5)
    • 验证 import { selectRadixOption } from '@d8d/e2e-test-utils' 可用
    • 验证类型提示正常工作

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 状态:

// 当前使用显式导出(正确,支持 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 审查指南:

当前导出结构(已正确):

/**
 * @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. 安装说明

    # 使用 pnpm workspace 协议(Monorepo 内)
    pnpm add -D @d8d/e2e-test-utils@workspace:*
    
    # 使用 npm(发布后)
    npm install --save-dev @d8d/e2e-test-utils
    
  3. 快速入门(本故事核心任务)

    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-testidaria-label + roletext 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 模板参考

快速入门章节建议内容:

## 快速入门

### 安装

\`\`\`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 文档章节建议内容:

## API 文档

### selectRadixOption()

选择静态枚举型 Radix UI Select 选项。

**函数签名:**
\`\`\`typescript
function selectRadixOption(
  page: Page,
  label: string,
  value: string
): Promise<void>
\`\`\`

**参数:**
| 参数 | 类型 | 说明 |
|------|------|------|
| `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<void>
\`\`\`

**参数:**
| 参数 | 类型 | 说明 |
|------|------|------|
| `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 来源:

Architecture 来源:

标准文档来源:

Epic 来源:

前一个故事:

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 测试标准