# Story 1.1: 创建包基础结构和配置 Status: done ## 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%