--- stepsCompleted: ['step-01-init', 'step-02-context', 'step-03-starter', 'step-04-decisions', 'step-05-patterns', 'step-06-structure', 'step-07-validation', 'step-08-complete'] inputDocuments: - name: PRD - E2E测试工具包 path: _bmad-output/planning-artifacts/prd.md type: prd loadedAt: '2026-01-08T02:10:00.000Z' - name: 项目文档索引 path: docs/index.md type: project-knowledge loadedAt: '2026-01-08T02:10:00.000Z' - name: Monorepo架构 path: docs/architecture/monorepo.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' - name: 模块组织结构 path: docs/architecture/module-structure.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' - name: 数据模型 path: docs/architecture/data-models.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' - name: API设计 path: docs/architecture/api-design.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' - name: 编码标准 path: docs/standards/coding-standards.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' - name: 后端模块开发规范 path: docs/standards/backend-module-standards.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' - name: UI包开发规范 path: docs/standards/ui-package-standards.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' - name: 测试规范 path: docs/standards/testing-standards.md type: project-doc loadedAt: '2026-01-08T02:10:00.000Z' workflowType: 'architecture' project_name: '188-179-template-6' user_name: 'Root' date: '2026-01-08T02:10:00.000Z' lastStep: 8 status: 'complete' completedAt: '2026-01-08' --- # Architecture Decision Document _This document builds collaboratively through step-by-step discovery. Sections are appended as we work through each architectural decision together._ --- ## Project Context Analysis ### Requirements Overview **Functional Requirements (50 total):** | 类别 | FR范围 | 架构含义 | |------|--------|----------| | Radix UI Select 测试 | FR1-FR6 | 需封装复杂的 Radix UI DOM 操作,区分静态/异步场景 | | 文件上传测试 | FR7-FR10 | 需处理 fixtures 文件管理和多文件上传场景 | | 表单交互测试 | FR11-FR15 | 需支持多步骤表单流程和滚动操作 | | 动态列表测试 | FR16-FR20 | 需处理动态 DOM 更新和异步状态管理 | | 对话框操作 | FR21-FR24 | 需统一的对话框打开/关闭/等待模式 | | 工具包基础设施 | FR25-FR32 | 需 npm workspace 集成、TypeScript 类型安全 | | 文档和开发支持 | FR33-FR40 | 需完整示例、迁移指南、快速入门 | | 质量保障 | FR41-FR45 | 需稳定性保障(20次连续运行100%通过) | | 可扩展性 | FR46-FR50 | 需配置化设计和版本升级兼容 | **Non-Functional Requirements (46 total):** | 类别 | NFR范围 | 架构驱动因素 | |------|--------|-------------| | 可靠性 | NFR1-NFR7 | 测试稳定性是核心,错误处理必须清晰 | | 性能 | NFR8-NFR14 | 静态Select 2秒、异步Select 5秒的性能约束 | | 集成性 | NFR15-NFR24 | Playwright 兼容、Monorepo workspace 集成 | | 代码质量 | NFR25-NFR40 | 无 any 类型、≥80% 覆盖率、JSDoc 完整 | | 兼容性 | NFR41-NFR46 | 跨浏览器、CI/CD 环境、版本升级兼容 | **Scale & Complexity:** - **Primary domain**: 开发者工具 / 测试基础设施 - **Complexity level**: Low(相对独立的工具函数 + 文档) - **Estimated architectural components**: 6个核心工具函数 + 1个共享包 ### Technical Constraints & Dependencies **技术栈约束:** - 纯 TypeScript 实现,目标 ES2020+ - 使用 pnpm workspace 协议进行本地开发 - Peer dependency: `@playwright/test`(由测试项目提供) - 无运行时依赖,保持轻量 **架构约束:** - 必须与现有 Page Object 模式集成 - 必须遵循 Monorepo 架构规范 - 必须兼容现有的测试基础设施(Vitest + Playwright) **外部依赖:** - Radix UI 组件库(DOM 结构变化风险) - Playwright 框架版本兼容性 - 现有 `@d8d/shared-test-util`(后端集成测试,独立于本工具包) ### Cross-Cutting Concerns Identified 1. **测试稳定性**: 统一等待策略、错误处理、重试逻辑 2. **开发体验**: 简洁 API、清晰错误提示、完整文档 3. **可扩展性**: 支持配置对象、预留钩子函数 4. **版本兼容性**: 使用 stable selectors(role、data-testid)应对 Radix UI 升级 5. **Monorepo 集成**: 通过 workspace 协议安装,支持本地开发迭代 --- ## Starter Template Evaluation ### Primary Technology Domain 开发者工具 / 测试基础设施包 ### Starter Options Considered **不适用**:本项目是在现有 Monorepo 中创建的内部测试工具包(`packages/e2e-test-utils`),而非独立应用项目。 **技术栈已由现有项目确定:** - 纯 TypeScript,目标 ES2020+ - Playwright 作为 peer dependency - Vitest 用于工具函数自测 - 遵循现有 Monorepo 架构规范 **包结构需要遵循:** - pnpm workspace 协议集成 - 与现有测试基础设施兼容 - 与现有包结构保持一致 --- ## Core Architectural Decisions ### Decision Priority Analysis **Critical Decisions (Block Implementation):** - ✅ 包内部结构:按功能分组 - ✅ API 设计模式:3个必需参数 + 可选配置对象 - ✅ 类型系统策略:分层类型(共享+特定) - ✅ 选择器策略:混合策略(testid → ARIA → 文本) **Important Decisions (Shape Architecture):** - ✅ 错误处理策略:结构化错误类 + 友好消息 - ✅ 测试配置:三层测试策略 **Deferred Decisions (Post-MVP):** - VS Code snippets - CLI 测试生成器 - AI 辅助测试生成 --- ### Package Structure **决策**: 按功能分组(选项B) **目录结构**: ``` packages/e2e-test-utils/ ├── src/ │ ├── index.ts # 主导出 │ ├── types.ts # 共享类型定义 │ ├── radix-select.ts # Radix UI Select 工具 │ ├── file-upload.ts # 文件上传工具 │ ├── form-helper.ts # 表单辅助函数 │ ├── dialog.ts # 对话框操作 │ └── dynamic-list.ts # 动态列表管理 ├── tests/ │ ├── unit/ # 单元测试 │ ├── integration/ # 集成测试 │ └── stability/ # 稳定性测试 ├── package.json └── README.md ``` **理由**: 清晰的职责分离,便于测试和维护 --- ### API Design Pattern **决策**: 3个必需参数 + 可选配置对象 **核心原则**: - 必需参数 ≤ 3 个 - 复杂配置通过可选对象传递 - 类型推断友好 - JSDoc 完整 **示例**: ```typescript // 静态 Select - 简洁场景 export async function selectRadixOption( page: Page, label: string, value: string ): Promise // 异步 Select - 需要配置 export async function selectRadixOptionAsync( page: Page, label: string, value: string, options?: AsyncSelectOptions ): Promise ``` --- ### Type System Strategy **决策**: 分层类型(选项C) **类型分层**: ``` types.ts (共享/基础类型) ├── BaseOptions (超时等通用配置) └── 导出 Playwright 类型 各模块文件 (特定类型) ├── radix-select.ts → AsyncSelectOptions ├── file-upload.ts → FileUploadOptions └── ... ``` **优势**: - 共享类型统一管理 - 特定类型就近定义 - 支持类型复用和扩展 --- ### Selector Strategy **决策**: 混合策略(testid → ARIA → 文本) **优先级**: 1. `data-testid` - 最高优先级,需开发团队配合 2. `aria-label` + role - 无障碍标准 3. Text content + role - 兜底方案 **配套措施**: - 推荐在 Radix 组件上添加 `data-testid` - 提供迁移指南 --- ### Error Handling Strategy **决策**: 结构化错误类 + 友好消息 **错误结构**: ```typescript export class E2ETestError extends Error { constructor( public readonly context: ErrorContext, message?: string ) { ... } } export interface ErrorContext { operation: string; // 操作类型 target: string; // 目标 expected?: string; // 期望值 actual?: string; // 实际值 available?: string[]; // 可用选项 suggestion?: string; // 修复建议 } ``` **示例输出**: ``` ❌ selectOption failed Target: 残疾类型 Expected: 视力残疾 Available: 听力残疾, 言语残疾, 肢体残疾 💡 Suggestion: Check if the option value matches exactly ``` --- ### Testing Configuration **决策**: 三层测试策略 | 测试类型 | 范围 | 工具 | 目标 | |----------|------|------|------| | 单元测试 | 单个函数逻辑 | **Vitest** | ≥80% 覆盖率 | | 集成测试 | 与真实组件交互 | **Playwright** | 验证实际 DOM 结构 | | 稳定性测试 | 20次连续运行 | **Playwright** | 100% 通过率 | **⚠️ Epic 2 关键发现:** 单元测试**无法**发现真实 DOM 结构问题: - 单元测试使用模拟 DOM,覆盖率 93.65% 仍然无法发现 DOM 问题 - Epic 2 的 listbox → option 问题只在真实 E2E 测试中暴露 - **必须添加集成测试级别,使用真实 Radix UI 组件验证** **集成测试基础设施**: - 创建独立的测试应用 `tests/test-app/` - 使用 Vite + React - **导入真实的 Radix UI 组件**(而非模拟) - Playwright 配置自动启动测试应用服务器 **配置文件**: ```typescript // vitest.config.ts - 单元测试 { coverage: { statements: 80, branches: 80, functions: 80, lines: 80 }, testTimeout: 10000, } // playwright.config.ts - 集成/稳定性测试 { testDir: './tests/integration', webServer: { command: 'pnpm --filter @d8d/e2e-test-utils-test-app dev', url: 'http://localhost:5173', reuseExistingServer: !process.env.CI, }, } ``` --- ### Decision Impact Analysis **Implementation Sequence:** 1. 创建包结构 + package.json 2. 实现 types.ts + index.ts 3. 实现各工具函数(从简单到复杂) 4. 编写单元测试 5. 编写集成测试 6. 编写稳定性测试 7. 在残疾人管理中验证 **Cross-Component Dependencies:** - 所有工具函数依赖 `types.ts` - index.ts 依赖所有模块(tree-shakeable 导出) - 测试依赖完整的函数实现 --- ## Implementation Patterns & Consistency Rules ### Pattern Categories Defined **Critical Conflict Points Identified:** 4 个类别,每个类别都可能导致 AI Agent 实现不一致 ### Naming Patterns **函数命名约定**: - 风格:动词+名词,camelCase - 示例:`selectRadixOption`、`uploadFileToField`、`fillMultiStepForm` - 异步函数:添加 `Async` 后缀(如 `selectRadixOptionAsync`) **类型命名约定**: - 接口:PascalCase,`Options` 后缀 - 示例:`AsyncSelectOptions`、`FileUploadOptions` - 基础类型:`BaseOptions` 作为所有配置的基类 **测试文件命名**: - 单元测试:与源文件同名,`.test.ts` 后缀 - 集成测试:描述性名称,如 `select-scenarios.test.ts` - 稳定性测试:`stability.test.ts` ### Structure Patterns **测试目录结构**: ``` tests/ ├── fixtures/ # 集中管理测试资源 │ ├── images/ # 测试图片 │ └── data/ # 测试数据 ├── unit/ # 单元测试(无 Playwright) ├── integration/ # 集成测试(需要 Playwright) └── stability/ # 稳定性测试 ``` **源文件组织**: - 每个工具函数独立文件 - `types.ts` 存放共享类型 - `index.ts` 作为主导出(tree-shakeable) ### Format Patterns **JSDoc 格式**: ```typescript /** * 函数描述(简洁说明) * * @param paramName - 参数描述 * @param paramTwo - 参数描述 * @throws {E2ETestError} 错误条件 * @example * ```ts * await functionName(page, 'arg', 'value'); * ``` */ ``` **配置对象格式**: ```typescript // 所有可选配置都继承 BaseOptions export interface XxxOptions extends BaseOptions { /** 特定选项描述 */ specificOption?: boolean; } export interface BaseOptions { /** 超时时间(毫秒)*/ timeout?: number; } ``` **错误消息格式**: - 标题:❌ 操作失败 - 上下文:目标、期望值、实际值 - 建议:💡 修复建议 ### Process Patterns **选择器查找流程**: ```typescript const SELECTOR_STRATEGIES = [ findByTestId, // 1. data-testid findByAria, // 2. aria-label + role findByText, // 3. text content + role ] as const; // 按优先级尝试,找到即返回 ``` **等待策略常量**: ```typescript export const DEFAULT_TIMEOUTS = { static: 2000, // 静态选项 async: 5000, // 异步选项 networkIdle: 10000, // 网络空闲 } as const; ``` **错误处理流程**: ```typescript // 1. 捕获底层错误 // 2. 转换为 E2ETestError // 3. 包含完整 ErrorContext export function throwError(context: ErrorContext): never { throw new E2ETestError(context, formatErrorMessage(context)); } ``` ### Enforcement Guidelines **所有 AI Agent 必须:** 1. **遵循命名约定**:函数、类型、文件名按规范命名 2. **使用完整 JSDoc**:每个导出函数必须有完整文档 3. **统一错误处理**:使用 `E2ETestError` 和 `ErrorContext` 4. **按优先级查找选择器**:testid → ARIA → 文本 5. **使用常量定义超时**:从 `DEFAULT_TIMEOUTS` 获取 6. **配置对象继承 BaseOptions**:确保一致性 **强制执行方式:** - ESLint 规则检查命名 - TypeScript 严格类型检查 - 测试覆盖率 ≥80% - Code Review 验证模式 ### Pattern Examples **正确示例**: ```typescript // ✅ 正确:遵循命名和格式约定 /** * 选择 Radix UI 下拉框的静态选项 * * @param page - Playwright Page 对象 * @param label - 下拉框标签文本 * @param value - 要选择的选项值 * @throws {E2ETestError} 当下拉框或选项未找到时 */ export async function selectRadixOption( page: Page, label: string, value: string ): Promise { try { // 实现逻辑 } catch (error) { throwError({ operation: 'selectRadixOption', target: label, expected: value, }); } } ``` **反模式(避免)**: ```typescript // ❌ 错误:缺少 JSDoc export async function select(p: any, l: string, v: string) {} // ❌ 错误:使用 any 类型 export async function selectOption( page: Page, label: any, value: any ): Promise {} // ❌ 错误:自定义错误类型 throw new Error('Select failed'); // ❌ 错误:硬编码超时 await page.waitForTimeout(5000); ``` --- ## TypeScript + Playwright 常见陷阱 > 本部分记录从 Epic 1 和 Epic 2 回顾中总结的 TypeScript + Playwright 陷阱和最佳实践。 > 参见: _bmad-output/implementation-artifacts/epic-1-retrospective.md, epic-2-retrospective.md ### 陷阱 1: DOM 结构假设必须验证 ⚠️ 关键 **问题(Epic 2 发现):** 单元测试使用模拟 DOM 结构,无法发现真实组件的 DOM 问题。 **案例:** 工具假设 Select 组件包含 `[role="listbox"]` 元素,但 Radix UI Select v2.2.5 的实际结构是: ``` [role="combobox"] └── [role="option"] ← 选项直接在 combobox 内部 ``` **影响:** 单元测试覆盖率 93.65% 仍然无法发现此问题,因为单元测试的 DOM 是理想化的模拟结构。 **解决方案:** 1. **在真实组件上验证工具** - 使用真实的 Radix UI 组件进行集成测试 2. **添加集成测试级别** - 单元测试无法替代真实环境测试 3. **DOM 结构假设必须验证** - 不能基于理想模型开发工具 ```typescript // ❌ 假设 listbox 存在 await page.waitForSelector('[role="listbox"]', { state: 'visible' }); // ✅ 直接查找 option 元素 await page.waitForSelector('[role="option"]', { state: 'visible' }); // 或使用 getByRole const option = page.getByRole('option', { name: value }); ``` ### 陷阱 2: DOM 类型问题 **问题:** 使用 `page.evaluate()` 获取文本内容会触发 TypeScript DOM 类型错误。 **原因:** Playwright 的类型定义与浏览器 DOM 环境不完全兼容,`page.evaluate()` 中的类型推断可能出现问题。 **解决方案:** 使用 Playwright API 而非 `page.evaluate()`: ```typescript // ❌ 不推荐 - TypeScript 类型问题 const text = await page.evaluate(el => el.textContent, element); // ✅ 推荐 - 使用 Playwright API const text = await element.textContent(); // ✅ 推荐 - 使用 locator 获取多个文本 const texts = await page.locator(selector).allTextContents(); ``` ### 陷阱 2: 精确文本匹配 **问题:** 使用 `:has-text()` 选择器会进行部分匹配,可能导致误选错误选项。 **案例:** 期望选择 "广东省",实际选择了 "广东省xx市"(因为包含 "广东省")。 **解决方案:** 使用 `:text-is()` 进行精确匹配: ```typescript // ❌ 部分匹配 - 可能误选 page.locator(`.option:has-text("广东省")`) // ✅ 精确匹配 - 只匹配完全相等的文本 page.locator(`.option:text-is("广东省")`) ``` **影响:** 如果没有在代码审查中发现,测试可能会在错误选项上通过,导致假阳性 bug。 ### 陷阱 3: 网络空闲等待超时配置 **问题:** 网络空闲等待使用了固定的 `networkIdle` 超时,而非用户自定义的超时值。 **案例(Story 1.6 单元测试中发现):** ```typescript // ❌ Bug - 网络空闲等待使用了默认的 networkIdle 超时 await page.waitForLoadState('networkidle', { timeout: DEFAULT_TIMEOUTS.networkIdle }); // ✅ 修复 - 使用用户自定义的 timeout await page.waitForLoadState('networkidle', { timeout: options.timeout ?? DEFAULT_TIMEOUTS.async }); ``` **经验:** 任何使用超时的 Playwright API 都应该尊重用户的自定义配置。 ### 陷阱 4: 选择器策略优先级 **问题:** 直接使用文本选择器可能失败,因为 Radix UI 的 DOM 结构会随版本变化。 **解决方案:** 按优先级使用选择器策略: ```typescript const SELECTOR_STRATEGIES = [ findByTestId, // 1. data-testid - 最稳定 findByAria, // 2. aria-label + role - 无障碍属性 findByText, // 3. text content - 兜底方案 ] as const; ``` ### 实现检查清单 基于 Epic 1 和 Epic 2 的经验,所有开发者应遵循以下检查清单: **代码质量:** - [ ] 所有导出函数都有完整的 JSDoc(@param, @returns, @throws, @example) - [ ] 内部函数使用 `@internal` 标记 - [ ] 错误处理使用 `E2ETestError` 而非原生 `Error` **选择器策略:** - [ ] 文本选择器使用 `:text-is()` 而非 `:has-text()` - [ ] DOM 结构假设必须基于真实组件验证,不能基于理想模型 **配置和超时:** - [ ] 配置对象继承 `BaseOptions` - [ ] 超时值使用 `DEFAULT_TIMEOUTS` 常量 - [ ] 网络空闲等待使用用户自定义的超时值 **DOM 操作:** - [ ] 避免使用 `page.evaluate()` 处理 DOM 操作 **测试策略(Epic 2 关键发现):** - [ ] 单元测试无法发现真实 DOM 结构问题,必须添加集成测试 - [ ] 使用真实组件验证工具,而非仅依赖模拟 DOM --- ## Project Structure & Boundaries ### Complete Project Directory Structure ``` 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/ │ │ ├── images/ │ │ │ ├── sample-id-card.jpg │ │ │ └── sample-disability-card.jpg │ │ └── data/ │ │ └── test-users.json │ ├── test-app/ # 独立测试应用 │ │ ├── package.json │ │ ├── vite.config.ts │ │ ├── index.html │ │ ├── main.tsx │ │ └── pages/ │ │ ├── select.tsx # Select 测试页面 │ │ ├── dialog.tsx # Dialog 测试页面 │ │ ├── file-upload.tsx # 文件上传测试页面 │ │ ├── form.tsx # 表单测试页面 │ │ └── dynamic-list.tsx # 动态列表测试页面 │ ├── unit/ # Vitest 单元测试 │ │ ├── radix-select.test.ts │ │ ├── file-upload.test.ts │ │ ├── form-helper.test.ts │ │ ├── dialog.test.ts │ │ └── dynamic-list.test.ts │ ├── integration/ # Playwright 集成测试 │ │ ├── select-scenarios.spec.ts │ │ ├── upload-scenarios.spec.ts │ │ └── form-scenarios.spec.ts │ └── stability/ # Playwright 稳定性测试 │ └── repeat-run.spec.ts ├── package.json ├── tsconfig.json ├── vitest.config.ts # 单元测试配置 ├── playwright.config.ts # 集成/稳定性测试配置 ├── README.md └── CHANGELOG.md ``` ### Architectural Boundaries **包边界**: - **输入**: 接收 Playwright `Page` 对象作为参数 - **输出**: 返回 `Promise` 或抛出 `E2ETestError` - **依赖**: Peer dependency `@playwright/test`,无运行时依赖 **工具函数边界**: - 每个工具函数独立运行,无共享状态 - 不依赖其他工具函数(避免循环依赖) - 所有共享逻辑通过 `types.ts`、`errors.ts`、`constants.ts` 提供 ### Requirements to Structure Mapping **FR 类别 → 文件映射**: | FR 类别 | 文件 | 说明 | |---------|------|------| | FR1-FR6 (Radix UI Select) | `radix-select.ts` | 静态和异步 Select 工具 | | FR7-FR10 (文件上传) | `file-upload.ts` | 文件上传工具 | | FR11-FR15 (表单交互) | `form-helper.ts` | 多步骤表单、滚动 | | FR16-FR20 (动态列表) | `dynamic-list.ts` | 添加/删除列表项 | | FR21-FR24 (对话框) | `dialog.ts` | 对话框操作 | | FR25-FR32 (工具包基础设施) | `index.ts`, `package.json` | 包导出和配置 | | FR41-FR45 (质量保障) | `tests/` | 所有测试文件 | ### Integration Points **内部通信**: - 工具函数通过 `types.ts` 共享类型定义 - 通过 `errors.ts` 统一错误处理 - 通过 `constants.ts` 共享配置常量 **外部集成**: - **Playwright**: 通过 peer dependency 集成,提供 `Page` 对象 - **测试项目**: 通过 workspace 协议安装:`@d8d/e2e-test-utils@workspace:*` - **现有 Page Object**: 可与现有 Page Object 模式共存 **数据流**: ``` 测试代码 → 工具函数 → Playwright API → DOM 操作 ↓ E2ETestError (失败时) ``` ### File Organization Patterns **配置文件**: - `package.json`: 包定义、workspace 协议配置 - `tsconfig.json`: TypeScript 严格模式配置 - `vitest.config.ts`: Vitest 单元测试配置、覆盖率目标 - `playwright.config.ts`: Playwright 集成/稳定性测试配置、测试应用服务器 **源码组织**: - 按功能分组(每个工具函数一个文件) - 共享代码集中在 `types.ts`、`errors.ts`、`constants.ts` - `index.ts` 作为主导出点,支持 tree-shaking **测试组织**: - `tests/unit/`: Vitest 单元测试,测试单个函数逻辑 - `tests/integration/`: Playwright 集成测试,验证与真实 DOM 的交互 - `tests/stability/`: Playwright 稳定性测试,20次连续运行 - `tests/test-app/`: 独立测试应用,提供 @d8d/shared-ui-components 组件测试环境 - `tests/fixtures/`: 测试资源集中管理 --- ## Architecture Validation Results ### Coherence Validation ✅ **Decision Compatibility:** 所有核心技术决策相互兼容,无冲突: - ✅ TypeScript ES2020+ 与 Playwright peer dependency 兼容 - ✅ 按功能分组的包结构与分层类型系统一致 - ✅ 混合选择器策略支持错误处理中的上下文信息 - ✅ 三层测试策略与工具函数设计模式匹配 **Pattern Consistency:** 实现模式完全支持架构决策: - ✅ 命名约定与 API 设计模式一致(动词+名词,camelCase) - ✅ 配置对象继承 BaseOptions 与类型系统策略一致 - ✅ 错误处理流程使用结构化错误类 - ✅ 选择器查找流程遵循混合策略优先级 **Structure Alignment:** 项目结构完全支持所有架构决策: - ✅ 测试目录结构分离单元测试和集成测试 - ✅ test-app 提供真实的 @d8d/shared-ui-components 测试环境 - ✅ 源文件组织支持按功能分组和独立模块 - ✅ 配置文件完整覆盖所有测试工具 ### Requirements Coverage Validation ✅ **Epic/Feature Coverage:** 所有 50 个功能需求都有架构支持: | FR 类别 | 架构支持 | 验证 | |---------|----------|------| | FR1-FR6 (Radix UI Select) | `radix-select.ts` + test-app/pages/select.tsx | ✅ | | FR7-FR10 (文件上传) | `file-upload.ts` + test-app/pages/file-upload.tsx | ✅ | | FR11-FR15 (表单交互) | `form-helper.ts` + test-app/pages/form.tsx | ✅ | | FR16-FR20 (动态列表) | `dynamic-list.ts` + test-app/pages/dynamic-list.tsx | ✅ | | FR21-FR24 (对话框) | `dialog.ts` + test-app/pages/dialog.tsx | ✅ | | FR25-FR32 (工具包基础设施) | `index.ts` + `package.json` | ✅ | | FR33-FR40 (文档和开发支持) | README.md + JSDoc 完整性要求 | ✅ | | FR41-FR45 (质量保障) | 三层测试策略 + 稳定性测试 | ✅ | | FR46-FR50 (可扩展性) | 配置对象设计 + BaseOptions 扩展 | ✅ | **Functional Requirements Coverage:** 所有功能需求类别完全覆盖: - ✅ Radix UI 组件测试:6个核心工具函数 + 独立测试应用 - ✅ 文件上传测试:fixtures 管理 + Playwright 文件上传 API - ✅ 表单交互测试:多步骤表单支持 + 滚动操作常量 - ✅ 动态列表测试:添加/删除列表项工具函数 - ✅ 对话框操作:统一的打开/关闭/等待模式 - ✅ 工具包基础设施:workspace 协议 + TypeScript 类型安全 - ✅ 文档和开发支持:JSDoc 完整性 + README 模板 - ✅ 质量保障:80% 覆盖率 + 20次连续稳定性测试 - ✅ 可扩展性:配置对象 + 版本升级兼容性 **Non-Functional Requirements Coverage:** 所有 46 个非功能需求都已处理: | NFR 类别 | 架构支持 | 验证 | |---------|----------|------| | NFR1-NFR7 (可靠性) | E2ETestError + ErrorContext + 友好错误消息 | ✅ | | NFR8-NFR14 (性能) | DEFAULT_TIMEOUTS 常量 + 超时配置 | ✅ | | NFR15-NFR24 (集成性) | Playwright peer dependency + workspace 协议 | ✅ | | NFR25-NFR40 (代码质量) | 无 any 类型 + 80% 覆盖率 + JSDoc 完整 | ✅ | | NFR41-NFR46 (兼容性) | 稳定选择器策略 + 跨浏览器测试 | ✅ | ### Implementation Readiness Validation ✅ **Decision Completeness:** 所有关键决策都已记录版本和理由: - ✅ 包内部结构:按功能分组 - ✅ API 设计模式:3个必需参数 + 可选配置对象 - ✅ 类型系统策略:分层类型(共享+特定) - ✅ 选择器策略:混合策略(testid → ARIA → 文本) - ✅ 错误处理策略:结构化错误类 + 友好消息 - ✅ 测试配置:三层测试策略(Vitest + Playwright) **Structure Completeness:** 项目结构完整且具体: - ✅ 所有源文件和目录已定义 - ✅ 测试应用结构完整(test-app/) - ✅ 集成点清晰指定(Playwright、测试项目) - ✅ 组件边界明确定义 **Pattern Completeness:** 所有潜在冲突点都已解决: - ✅ 命名约定:函数、类型、文件名 - ✅ 结构模式:测试目录、源文件组织 - ✅ 格式模式:JSDoc、配置对象、错误消息 - ✅ 流程模式:选择器查找、等待策略、错误处理 ### Gap Analysis Results **Critical Gaps:** 无 **Important Gaps:** 无 **Nice-to-Have Gaps:** - 📝 VS Code snippets 代码片段(已推迟到 MVP 后) - 📝 CLI 测试生成器(已推迟到 MVP 后) - 📝 AI 辅助测试生成(已推迟到 MVP 后) ### Validation Issues Addressed **集成测试基础设施问题(已解决):** **问题描述:** 原始架构将集成测试配置为使用 Vitest 运行 Playwright,这不符合 Playwright 的最佳实践。 **解决方案:** - ✅ 分离单元测试和集成测试工具 - ✅ 单元测试使用 Vitest(测试纯函数逻辑) - ✅ 集成测试和稳定性测试使用 Playwright(测试真实浏览器交互) - ✅ 创建独立测试应用 `tests/test-app/` 提供 @d8d/shared-ui-components 测试环境 - ✅ Playwright 配置自动启动测试应用服务器 **架构影响:** - 更新 `Testing Configuration` 部分 - 更新项目目录结构,添加 `tests/test-app/` - 添加 `playwright.config.ts` 配置文件 - 更新测试文件命名约定(`.spec.ts` 用于 Playwright) ### Architecture Completeness Checklist **✅ Requirements Analysis** - [x] 项目上下文彻底分析 - [x] 规模和复杂度评估 - [x] 技术约束识别 - [x] 跨领域关注点映射 **✅ Architectural Decisions** - [x] 关键决策文档化并记录版本 - [x] 技术栈完全指定 - [x] 集成模式定义 - [x] 性能考虑已处理 **✅ Implementation Patterns** - [x] 命名约定建立 - [x] 结构模式定义 - [x] 通信模式指定 - [x] 流程模式文档化 **✅ Project Structure** - [x] 完整目录结构定义 - [x] 组件边界建立 - [x] 集成点映射 - [x] 需求到结构映射完成 **✅ Testing Strategy** - [x] 三层测试策略定义 - [x] 测试工具选择合理(Vitest + Playwright) - [x] 集成测试基础设施完整 - [x] 稳定性测试方法明确 ### Architecture Readiness Assessment **Overall Status:** READY FOR IMPLEMENTATION **Confidence Level:** HIGH **Key Strengths:** 1. ✅ 清晰的模块化设计,按功能分组 2. ✅ 完整的类型系统策略,支持类型推断 3. ✅ 结构化的错误处理,提供友好错误消息 4. ✅ 灵活的选择器策略,应对 Radix UI 版本升级 5. ✅ 合理的测试分层,单元测试与集成测试分离 6. ✅ 独立的测试应用,支持真实组件交互测试 7. ✅ 完整的一致性规则,确保 AI Agent 实现一致性 **Areas for Future Enhancement:** 1. 📝 VS Code snippets 提升开发体验 2. 📝 CLI 测试生成器加速测试编写 3. 📝 AI 辅助测试生成降低学习曲线 ### Implementation Handoff **AI Agent Guidelines:** 1. **严格遵循所有架构决策**:按文档中的定义实现,不得偏离 2. **使用实现模式保持一致性**:所有 AI Agent 必须遵循命名、结构、格式、流程模式 3. **尊重项目结构和边界**:按定义的目录结构组织代码 4. **参考架构文档解决所有问题**:遇到不确定的情况时查阅此文档 **First Implementation Priority:** ```bash # 1. 创建包基础结构 mkdir -p packages/e2e-test-utils/src mkdir -p packages/e2e-test-utils/tests/{unit,integration,stability,fixtures/{images,data}} # 2. 创建测试应用 mkdir -p packages/e2e-test-utils/tests/test-app/pages # 3. 初始化 package.json(包含正确的 peer dependencies) # 4. 实现 types.ts 和 index.ts # 5. 从简单到复杂实现各工具函数 # 6. 编写单元测试(Vitest) # 7. 编写集成测试(Playwright + test-app) # 8. 在残疾人管理功能中验证 ``` **Success Criteria:** - ✅ 所有 50 个功能需求实现 - ✅ 所有 46 个非功能需求满足 - ✅ 单元测试覆盖率 ≥80% - ✅ 稳定性测试 20 次连续运行 100% 通过 - ✅ 在残疾人管理功能中成功使用 --- ## Architecture Completion Summary ### Workflow Completion **Architecture Decision Workflow:** COMPLETED ✅ **Total Steps Completed:** 8 **Date Completed:** 2026-01-08 **Document Location:** _bmad-output/planning-artifacts/architecture.md ### Final Architecture Deliverables **📋 Complete Architecture Document** - 所有架构决策已文档化,包含明确的技术选择 - 确保一致性:AI 实现模式和规则完整定义 - 项目结构完整:所有文件和目录都已定义 - 需求映射清晰:从 FR/NFR 到具体文件的映射 - 验证通过:架构一致性和完整性已确认 **🏗️ Implementation Ready Foundation** - 6 个核心架构决策(包结构、API 设计、类型系统、选择器策略、错误处理、测试配置) - 4 个一致性规则类别(命名、结构、格式、流程) - 6 个核心工具函数 + 1 个共享测试应用 - 50 个功能需求 + 46 个非功能需求完全支持 **📚 AI Agent Implementation Guide** - 技术栈:TypeScript ES2020+、Playwright、Vitest - 一致性规则:防止 AI Agent 实现冲突 - 项目结构:清晰的边界和集成点 - 集成模式:workspace 协议、peer dependencies ### Implementation Handoff **For AI Agents:** 本架构文档是实现 E2E 测试工具包的完整指南。严格遵循所有决策、模式和结构。 **First Implementation Priority:** ```bash # 1. 创建包基础结构 mkdir -p packages/e2e-test-utils/src mkdir -p packages/e2e-test-utils/tests/{unit,integration,stability,fixtures/{images,data}} # 2. 创建测试应用 mkdir -p packages/e2e-test-utils/tests/test-app/pages # 3. 初始化 package.json { "name": "@d8d/e2e-test-utils", "version": "1.0.0", "type": "module", "peerDependencies": { "@playwright/test": "^1.40.0" }, "devDependencies": { "vitest": "^3.2.4", "vite": "^6.0.11", "react": "^19.2.0", "react-dom": "^19.2.0" } } # 4. 实现 types.ts 和 index.ts # 5. 从简单到复杂实现各工具函数 # 6. 编写单元测试(Vitest) # 7. 编写集成测试(Playwright + test-app) # 8. 在残疾人管理功能中验证 ``` **Development Sequence:** 1. 初始化包结构和配置文件 2. 实现类型定义和主导出 3. 实现核心工具函数(radix-select → dialog → file-upload → form-helper → dynamic-list) 4. 编写单元测试(Vitest) 5. 创建测试应用并编写集成测试(Playwright) 6. 编写稳定性测试(20次连续运行) 7. 在残疾人管理功能中验证 ### Quality Assurance Checklist **✅ Architecture Coherence** - [x] 所有决策无冲突,协同工作 - [x] 技术选择完全兼容 - [x] 模式支持架构决策 - [x] 结构与所有选择一致 **✅ Requirements Coverage** - [x] 所有功能需求都有支持 - [x] 所有非功能需求都已处理 - [x] 跨领域关注点已解决 - [x] 集成点已明确定义 **✅ Implementation Readiness** - [x] 决策具体且可执行 - [x] 模式防止 Agent 冲突 - [x] 结构完整且无歧义 - [x] 提供清晰示例 ### Project Success Factors **🎯 Clear Decision Framework** 每个技术选择都是协作完成的,有清晰的理由,确保所有利益相关者理解架构方向。 **🔧 Consistency Guarantee** 实现模式和规则确保多个 AI Agent 将产生兼容、一致的代码。 **📋 Complete Coverage** 所有项目需求都有架构支持,从业务需求到技术实现的清晰映射。 **🏗️ Solid Foundation** 选择的测试策略和架构模式提供了生产就绪的基础。 --- **Architecture Status:** READY FOR IMPLEMENTATION ✅ **Next Phase:** 开始实现阶段,使用文档化的架构决策和模式。 **Document Maintenance:** 当实现过程中做出重大技术决策时,更新此架构文档。 --- **🎉 架构工作流程完成!** 你的 E2E 测试工具包架构已经全面完成,经过验证,可以开始实现了。 **✅ 交付内容:** - 完整的架构文档,包含所有决策和模式 - 为 AI Agent 实现准备好的项目结构 - 验证确认所有部分协同工作 - 开发阶段的实施指导 **📍 文档位置:** `_bmad-output/planning-artifacts/architecture.md` **🚀 下一步:** 1. 查看完整的架构文档 2. 创建包结构开始实现 3. 为 AI Agent 创建实现任务,遵循架构决策 你的架构将确保所有开发工作的一致、高质量实现。恭喜完成这些重要的架构决策!