# Story 1.1: 创建包基础结构和配置

Status: done

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

## Story

作为测试开发者，
我想要可以安装 `@d8d/e2e-test-utils` 包，
以便在项目中使用测试工具函数。

## Acceptance Criteria

**Given** 项目是 Monorepo 结构
**When** 创建 `packages/e2e-test-utils/` 目录
**Then** 目录结构包含 `src/`, `tests/`, `package.json`, `tsconfig.json`, `vitest.config.ts`
**And** `package.json` 包含正确的包名、版本、peer dependencies（`@playwright/test`）
**And** `tsconfig.json` 启用严格模式，目标 ES2020+
**And** 可以通过 `pnpm add -D @d8d/e2e-test-utils@workspace:*` 安装

## Tasks / Subtasks

- [x] 创建目录结构 (AC: 1)
  - [x] 创建 `packages/e2e-test-utils/` 根目录
  - [x] 创建 `src/` 源代码目录
  - [x] 创建 `tests/` 测试目录
  - [x] 创建 `tests/fixtures/` 测试资源目录
  - [x] 创建 `tests/unit/` 单元测试目录
  - [x] 创建 `tests/integration/` 集成测试目录
  - [x] 创建 `tests/stability/` 稳定性测试目录
- [x] 配置 package.json (AC: 2, 4)
  - [x] 设置包名 `@d8d/e2e-test-utils`
  - [x] 设置版本号 `1.0.0`
  - [x] 配置 peer dependency `@playwright/test`
  - [x] 配置开发依赖（TypeScript, Vitest）
  - [x] 添加必要的 scripts（build, dev, test, typecheck）
  - [x] 配置 exports 用于 tree-shaking
- [x] 配置 tsconfig.json (AC: 3)
  - [x] 启用严格模式（`strict: true`）
  - [x] 设置目标 ES2020+（`target: "ES2020"`）
  - [x] 配置模块系统（`module: "ESNext"`）
  - [x] 配置路径解析（`baseUrl: "."`, `paths`）
- [x] 配置 vitest.config.ts (AC: 1)
  - [x] 设置测试目录为 `tests/unit`
  - [x] 配置覆盖率目标 ≥80%
  - [x] 配置测试超时时间
- [x] 创建基础占位文件
  - [x] 创建 `src/index.ts` 导出入口
  - [x] 创建 `src/types.ts` 类型定义占位
  - [x] 创建 `src/errors.ts` 错误类占位
  - [x] 创建 `src/constants.ts` 常量占位
  - [x] 创建 `README.md` 基础文档
- [x] 验证包可被安装 (AC: 4)
  - [x] 在 monorepo 根目录运行 `pnpm install`
  - [x] 验证包可以被引用 `@d8d/e2e-test-utils@workspace:*`
  - [x] 运行 `pnpm typecheck` 验证类型检查通过

### Review Follow-ups (AI)

- [x] [AI-Review][HIGH] 在实际项目中验证 workspace 安装：在 `web/` 或其他包中运行 `pnpm add -D @d8d/e2e-test-utils@workspace:*` 并验证可以正常导入 [1-1-create-package-structure.md:56]
- [x] [AI-Review][HIGH] 添加占位测试文件：在 `tests/unit/` 中创建占位测试文件以验证 Vitest 配置正常工作 [packages/e2e-test-utils/tests/unit/]
- [x] [AI-Review][HIGH] 添加 fixtures 示例文件：创建 `test-users.json` 和 README 说明在 `tests/fixtures/` 目录中 [packages/e2e-test-utils/tests/fixtures/]
- [x] [AI-Review][MEDIUM] 完善 README.md：添加快速入门示例、API 文档、完整使用示例 [packages/e2e-test-utils/README.md]
- [x] [AI-Review][MEDIUM] 更新 package.json：修复 exports 警告并创建 PACKAGING.md 说明源码模式配置 [packages/e2e-test-utils/package.json:6-14]
- [x] [AI-Review][MEDIUM] 移除无意义的 paths 配置：删除 tsconfig.json 中指向自身的 `@d8d/e2e-test-utils` 路径配置 [packages/e2e-test-utils/tsconfig.json:26-28]
- [x] [AI-Review][MEDIUM] 更新 File List：将所有变更文件记录到 File List 中 [1-1-create-package-structure.md:503]
- [x] [AI-Review][LOW] 添加文件级 JSDoc：为 `src/index.ts` 添加文件级别的 JSDoc 注释 [packages/e2e-test-utils/src/index.ts:1]
- [x] [AI-Review][LOW] 提交代码：将所有创建的文件提交到 git（提交 9bac4a4）[git status]

### 代码审查后续处理 (2026-01-08)

**审查发现：** 9 个问题（3 HIGH, 3 MEDIUM, 2 LOW）
**修复状态：** 所有 HIGH 和 MEDIUM 问题已自动修复（6/6）

**已修复的问题：**

- [x] [HIGH] package.json exports 添加 types 字段 - 改善工具兼容性 [packages/e2e-test-utils/package.json:12]
- [x] [HIGH] 提升测试覆盖率到 100% - 添加 5 个额外的错误类测试用例 [packages/e2e-test-utils/tests/unit/index.test.ts:50-113]
- [x] [HIGH] 为空测试目录添加 README 说明 - integration/ 和 stability/ 目录添加说明文档 [packages/e2e-test-utils/tests/integration/README.md, packages/e2e-test-utils/tests/stability/README.md]
- [x] [MEDIUM] 修复 README.md 导入示例路径 - 更正测试数据导入方式说明 [packages/e2e-test-utils/README.md:101-128]
- [x] [MEDIUM] 添加测试图片占位文件 - 创建 sample-id-card.jpg 和 sample-disability-card.jpg [packages/e2e-test-utils/tests/fixtures/images/]
- [x] [MEDIUM] 添加 tsconfig.json baseUrl - 添加 "baseUrl": "." 配置 [packages/e2e-test-utils/tsconfig.json:7]
- [x] [MEDIUM] 更新 PACKAGING.md - 同步 exports 配置示例 [packages/e2e-test-utils/PACKAGING.md:17]

**未修复的 LOW 问题（可后续处理）：**

- [ ] [LOW] Story Change Log 信息重复 - Review Follow-ups 和 Change Log 有重复内容
- [ ] [LOW] PACKAGING.md 中源码模式说明已同步 - 问题已解决

**测试验证结果：**
- ✅ 所有单元测试通过（13 个测试）
- ✅ TypeScript 类型检查通过
- ✅ 测试覆盖率：100%（源代码，排除仅类型定义文件）

## Dev Notes

### Epic 1 背景

**Epic 1 目标：** 测试开发者可以安装 `@d8d/e2e-test-utils` 包，立即使用 Select 工具测试 Radix UI Select 组件（最常用、最关键的测试场景）。

**本故事在 Epic 中的位置：** 第一个故事，建立包基础设施，为后续所有工具函数提供基础。

### 相关架构决策

从架构文档中提取的关键架构决策：

**包结构决策（按功能分组）：**
```
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
```

**API 设计模式：** 3个必需参数 + 可选配置对象
- 必需参数 ≤ 3 个
- 复杂配置通过可选对象传递
- 类型推断友好
- JSDoc 完整

**类型系统策略：** 分层类型（共享+特定）
- `types.ts` 存放共享类型（`BaseOptions`）
- 各模块文件存放特定类型（如 `AsyncSelectOptions`）

**选择器策略：** 混合策略（testid → ARIA → 文本）
1. `data-testid` - 最高优先级
2. `aria-label` + role - 无障碍标准
3. Text content + role - 兜底方案

**错误处理策略：** 结构化错误类 + 友好消息
```typescript
export class E2ETestError extends Error {
  constructor(
    public readonly context: ErrorContext,
    message?: string
  ) { ... }
}
```

### 技术栈约束

**语言与类型系统：**
- 纯 TypeScript 实现，目标 ES2020+
- 严格类型检查，无 `any` 类型
- 完整的 JSDoc 注释用于 IDE 提示

**依赖管理：**
- **Peer dependency**: `@playwright/test`（由测试项目提供）
- **无运行时依赖**，保持轻量
- **开发依赖**: TypeScript, Vitest（用于自测）

### package.json 配置要求

**参考现有的 `@d8d/shared-test-util` 包结构：**

```json
{
  "name": "@d8d/e2e-test-utils",
  "version": "1.0.0",
  "description": "E2E testing utilities for Radix UI components",
  "type": "module",
  "main": "src/index.ts",
  "types": "src/index.ts",
  "exports": {
    ".": {
      "import": "./src/index.ts",
      "require": "./src/index.ts",
      "types": "./src/index.ts"
    }
  },
  "files": [
    "src"
  ],
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "test": "vitest",
    "test:unit": "vitest run tests/unit/**/*.test.ts",
    "test:coverage": "vitest --coverage",
    "typecheck": "tsc --noEmit"
  },
  "peerDependencies": {
    "@playwright/test": "^1.40.0"
  },
  "devDependencies": {
    "typescript": "^5.8.3",
    "vitest": "^3.2.4",
    "@vitest/coverage-v8": "^3.2.4"
  },
  "keywords": [
    "e2e",
    "testing",
    "playwright",
    "radix-ui",
    "test-utilities"
  ]
}
```

**关键点：**
1. 使用 `type: "module"` 启用 ES 模块
2. `main` 和 `types` 都指向 `src/index.ts`（源代码直接使用）
3. `exports` 配置支持 tree-shaking
4. `peerDependencies` 指定 Playwright 版本范围（兼容最新稳定版和上一个 LTS 版本）
5. 添加测试脚本（单元测试、覆盖率）

### tsconfig.json 配置要求

**参考项目 TypeScript 严格模式配置：**

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020"],
    "moduleResolution": "bundler",
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "baseUrl": ".",
    "paths": {
      "@d8d/e2e-test-utils": ["./src/index.ts"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "tests"]
}
```

**关键点：**
1. 启用所有严格模式选项（`strict: true` + 额外检查）
2. 目标 ES2020+（`target: "ES2020"`）
3. 启用声明文件生成（`declaration: true`）
4. 配置正确的 `rootDir` 和 `outDir`

### vitest.config.ts 配置要求

```typescript
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    dir: './tests/unit',
    environment: 'node',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      statements: 80,
      branches: 80,
      functions: 80,
      lines: 80,
      exclude: [
        'node_modules/',
        'tests/',
        '**/*.test.ts',
        '**/*.spec.ts',
        'src/index.ts'
      ]
    },
    testTimeout: 10000,
    globals: false
  }
});
```

**关键点：**
1. 测试目录指向 `tests/unit`
2. 覆盖率目标 ≥80%（所有指标）
3. 测试超时 10 秒
4. 排除 `src/index.ts` 从覆盖率（主导出文件）

### 源代码文件结构

**`src/index.ts` - 主导出文件（tree-shakeable）：**

```typescript
// 导出类型定义
export * from './types';

// 导出错误类
export * from './errors';

// 导出常量
export * from './constants';

// Radix UI Select 工具（后续故事实现）
// export * from './radix-select';
```

**`src/types.ts` - 共享类型定义：**

```typescript
import type { Page } from '@playwright/test';

/**
 * 基础配置选项，所有配置对象的基类
 */
export interface BaseOptions {
  /** 超时时间（毫秒）*/
  timeout?: number;
}

/**
 * 错误上下文接口
 */
export interface ErrorContext {
  /** 操作类型（如 'selectRadixOption'）*/
  operation: string;
  /** 目标（如下拉框标签）*/
  target: string;
  /** 期望值 */
  expected?: string;
  /** 实际值 */
  actual?: string;
  /** 可用选项列表 */
  available?: string[];
  /** 修复建议 */
  suggestion?: string;
}

// 重新导出 Playwright 类型以便使用者使用
export type { Page } from '@playwright/test';
```

**`src/errors.ts` - 错误处理：**

```typescript
import type { ErrorContext } from './types';

/**
 * E2E 测试专用错误类
 * 提供结构化的错误上下文信息
 */
export class E2ETestError extends Error {
  constructor(
    public readonly context: ErrorContext,
    message?: string
  ) {
    super(message || formatErrorMessage(context));
    this.name = 'E2ETestError';
  }
}

/**
 * 格式化错误消息
 */
function formatErrorMessage(context: ErrorContext): string {
  const parts = [
    `❌ ${context.operation} failed`,
    `Target: ${context.target}`
  ];

  if (context.expected) {
    parts.push(`Expected: ${context.expected}`);
  }

  if (context.actual) {
    parts.push(`Actual: ${context.actual}`);
  }

  if (context.available && context.available.length > 0) {
    parts.push(`Available: ${context.available.join(', ')}`);
  }

  if (context.suggestion) {
    parts.push(`\n💡 ${context.suggestion}`);
  }

  return parts.join('\n');
}
```

**`src/constants.ts` - 常量定义：**

```typescript
/**
 * 默认超时配置（毫秒）
 */
export const DEFAULT_TIMEOUTS = {
  /** 静态选项超时 */
  static: 2000,
  /** 异步选项超时 */
  async: 5000,
  /** 网络空闲超时 */
  networkIdle: 10000
} as const;

/**
 * 选择器策略常量
 */
export const SELECTOR_STRATEGIES = [
  'data-testid',
  'aria-label + role',
  'text content + role'
] as const;
```

### 目录创建命令参考

```bash
# 在项目根目录执行
mkdir -p packages/e2e-test-utils/src
mkdir -p packages/e2e-test-utils/tests/fixtures/images
mkdir -p packages/e2e-test-utils/tests/fixtures/data
mkdir -p packages/e2e-test-utils/tests/unit
mkdir -p packages/e2e-test-utils/tests/integration
mkdir -p packages/e2e-test-utils/tests/stability
```

### 验证步骤

**1. 验证目录结构：**
```bash
ls -la packages/e2e-test-utils/
# 应显示：src/, tests/, package.json, tsconfig.json, vitest.config.ts, README.md

ls -la packages/e2e-test-utils/src/
# 应显示：index.ts, types.ts, errors.ts, constants.ts

ls -la packages/e2e-test-utils/tests/
# 应显示：fixtures/, unit/, integration/, stability/
```

**2. 验证 TypeScript 配置：**
```bash
cd packages/e2e-test-utils
pnpm typecheck
# 应无错误输出
```

**3. 验证包可以被安装：**
```bash
# 在 monorepo 根目录
pnpm install
# 检查是否成功注册 workspace 包

# 验证可以被引用（在 web/ 目录）
pnpm add -D @d8d/e2e-test-utils@workspace:*
```

**4. 验证 Vitest 配置：**
```bash
cd packages/e2e-test-utils
pnpm test:unit
# 应显示 Vitest 成功启动（即使没有测试）
```

### Project Structure Notes

**对齐项目 Monorepo 架构：**
- 使用 `pnpm workspace` 协议
- 包命名遵循 `@d8d/` 命名空间
- 与现有 `@d8d/shared-test-util`（后端集成测试）分离
- `@d8d/e2e-test-utils` 专门用于 Playwright E2E 测试

**与项目标准对齐：**
- 遵循 `docs/standards/testing-standards.md` 中的测试规范
- 遵循 `docs/standards/coding-standards.md` 中的编码标准
- 遵循 `docs/standards/e2e-radix-testing.md` 中的 Radix UI E2E 测试标准（核心标准文档）

### References

**PRD 来源：**
- [PRD - E2E测试工具包](_bmad-output/planning-artifacts/prd.md) - 项目需求概述
- [PRD - 包结构需求](_bmad-output/planning-artifacts/prd.md#包结构需求) - 详细的包结构设计

**Architecture 来源：**
- [Architecture - 包结构决策](_bmad-output/planning-artifacts/architecture.md#package-structure) - 按功能分组的决策
- [Architecture - API 设计模式](_bmad-output/planning-artifacts/architecture.md#api-design-pattern) - 3参数+配置对象模式
- [Architecture - 类型系统策略](_bmad-output/planning-artifacts/architecture.md#type-system-strategy) - 分层类型设计
- [Architecture - 项目目录结构](_bmad-output/planning-artifacts/architecture.md#complete-project-directory-structure) - 完整目录结构

**标准文档来源：**
- [E2E Radix UI 测试标准](docs/standards/e2e-radix-testing.md) - 核心测试标准文档
- [测试规范](docs/standards/testing-standards.md) - 项目测试规范
- [编码标准](docs/standards/coding-standards.md) - 编码标准

**Epic 来源：**
- [Epic 1 - Story 1.1](_bmad-output/planning-artifacts/epics.md#story-11-创建包基础结构和配置) - 原始用户故事和验收标准

**参考包：**
- [@d8d/shared-test-util](packages/shared-test-util/package.json) - 现有的共享测试工具包（后端集成测试）

## Dev Agent Record

### Agent Model Used

Claude (d8d-model) via dev-story workflow

### Debug Log References

### Completion Notes List

- 故事创建时间: 2026-01-08
- 基于 PRD、Architecture、E2E Radix 测试标准文档创建
- 包含完整的目录结构、配置文件模板、验证步骤
- 为后续故事提供基础设施
- **实施完成时间: 2026-01-08**
- 所有目录结构已创建：src/, tests/, tests/fixtures/, tests/unit/, tests/integration/, tests/stability/
- package.json 配置完成：包名 @d8d/e2e-test-utils, 版本 1.0.0, peer dependencies 配置正确
- tsconfig.json 配置完成：严格模式启用，目标 ES2020+
- vitest.config.ts 配置完成：测试目录 tests/unit，覆盖率目标 80%
- 基础占位文件已创建：index.ts, types.ts, errors.ts, constants.ts, README.md
- pnpm install 成功，包已被 workspace 识别
- TypeScript 类型检查通过

### File List

**创建的文件（初始实施）：**
- `packages/e2e-test-utils/package.json`
- `packages/e2e-test-utils/tsconfig.json`
- `packages/e2e-test-utils/vitest.config.ts`
- `packages/e2e-test-utils/README.md`
- `packages/e2e-test-utils/src/index.ts`
- `packages/e2e-test-utils/src/types.ts`
- `packages/e2e-test-utils/src/errors.ts`
- `packages/e2e-test-utils/src/constants.ts`

**创建的目录（初始实施）：**
- `packages/e2e-test-utils/src/`
- `packages/e2e-test-utils/tests/fixtures/images/`
- `packages/e2e-test-utils/tests/fixtures/data/`
- `packages/e2e-test-utils/tests/unit/`
- `packages/e2e-test-utils/tests/integration/`
- `packages/e2e-test-utils/tests/stability/`

**审查后续处理新增文件：**
- `packages/e2e-test-utils/tests/unit/index.test.ts` - 单元测试文件
- `packages/e2e-test-utils/tests/fixtures/data/test-users.json` - 测试用户数据
- `packages/e2e-test-utils/tests/fixtures/data/README.md` - 数据文件说明
- `packages/e2e-test-utils/tests/fixtures/images/README.md` - 图片文件说明
- `packages/e2e-test-utils/tests/fixtures/images/sample-id-card.jpg` - 身份证占位图片
- `packages/e2e-test-utils/tests/fixtures/images/sample-disability-card.jpg` - 残疾证占位图片
- `packages/e2e-test-utils/tests/integration/README.md` - 集成测试目录说明
- `packages/e2e-test-utils/tests/stability/README.md` - 稳定性测试目录说明
- `packages/e2e-test-utils/PACKAGING.md` - 包配置策略说明

**审查后续处理修改文件：**
- `packages/e2e-test-utils/package.json` - 修复 test:unit 脚本、添加 exports types 字段
- `packages/e2e-test-utils/tsconfig.json` - 添加 baseUrl 配置
- `packages/e2e-test-utils/README.md` - 完善为完整的 API 文档、修正导入示例
- `packages/e2e-test-utils/tests/unit/index.test.ts` - 增强测试用例（13个测试，100%覆盖率）
- `packages/e2e-test-utils/PACKAGING.md` - 同步 exports 配置示例

**代码审查修复（2026-01-08）：**
- ✅ 修复 package.json exports 添加 types 字段（HIGH）
- ✅ 提升测试覆盖率到 100%（HIGH）
- ✅ 为空测试目录添加 README 说明（HIGH）
- ✅ 修复 README.md 导入示例路径（MEDIUM）
- ✅ 添加测试图片占位文件（MEDIUM）
- ✅ 添加 tsconfig.json baseUrl（MEDIUM）

**修改的项目文件：**
- `_bmad-output/implementation-artifacts/sprint-status.yaml` - 跟踪 story 状态
- `_bmad-output/implementation-artifacts/1-1-create-package-structure.md` - 本故事文件

## Change Log

- 2026-01-08: 完成包基础结构创建和配置，所有验收标准已满足
- 2026-01-08: AI 代码审查发现 9 个问题（3 HIGH, 3 MEDIUM, 2 LOW），已添加到 Review Follow-ups (AI) 待处理
- 2026-01-08: 完成所有审查后续处理任务（9/9 完成）：
  - ✅ 在实际项目中验证 workspace 安装（HIGH）
  - ✅ 添加占位测试文件验证 Vitest 配置（HIGH）
  - ✅ 添加 fixtures 示例文件（HIGH）
  - ✅ 完善 README.md 添加快速入门和 API 文档（MEDIUM）
  - ✅ 更新 package.json exports 配置并添加说明（MEDIUM）
  - ✅ 移除 tsconfig.json 中无意义的 paths 配置（MEDIUM）
  - ✅ 更新 File List 记录所有变更（MEDIUM）
  - ✅ 添加 index.ts 文件级 JSDoc 注释（LOW）
  - ✅ 提交代码到 git（LOW）
- 2026-01-08: **AI 代码审查修复完成** - 自动修复所有 HIGH 和 MEDIUM 问题（6/6）：
  - ✅ package.json exports 添加 types 字段（改善工具兼容性）
  - ✅ 测试覆盖率提升到 100%（添加 5 个错误类测试用例）
  - ✅ 为空测试目录添加 README 说明（integration/ 和 stability/）
  - ✅ 修复 README.md 导入示例路径（更正测试数据导入方式）
  - ✅ 添加测试图片占位文件（sample-id-card.jpg, sample-disability-card.jpg）
  - ✅ 添加 tsconfig.json baseUrl 配置
  - ✅ 更新 PACKAGING.md 同步 exports 配置
  - 测试验证：13 个测试全部通过，类型检查通过，覆盖率 100%
