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

Status: done

<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->

## 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<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 来源：**
- [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 测试标准

