|
@@ -0,0 +1,462 @@
|
|
|
|
|
+# Story 1.2: 实现类型定义和错误处理
|
|
|
|
|
+
|
|
|
|
|
+Status: ready-for-dev
|
|
|
|
|
+
|
|
|
|
|
+<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
|
|
|
|
+
|
|
|
|
|
+## Story
|
|
|
|
|
+
|
|
|
|
|
+作为测试开发者,
|
|
|
|
|
+我想要工具包有完整的类型支持和统一的错误处理,
|
|
|
|
|
+以便获得类型安全和清晰的错误提示。
|
|
|
|
|
+
|
|
|
|
|
+## Acceptance Criteria
|
|
|
|
|
+
|
|
|
|
|
+**Given** 包结构已创建(Story 1.1 完成)
|
|
|
|
|
+**When** 实现 `src/types.ts`, `src/errors.ts`, `src/constants.ts`
|
|
|
|
|
+**Then** `types.ts` 导出 `BaseOptions`, `AsyncSelectOptions`, `FileUploadOptions`, `FormStepOptions`, `DialogOptions` 等共享和特定类型
|
|
|
|
|
+**And** `errors.ts` 导出 `E2ETestError` 类和 `ErrorContext` 接口
|
|
|
|
|
+**And** `constants.ts` 定义 `DEFAULT_TIMEOUTS`(static: 2000, async: 5000, networkIdle: 10000)
|
|
|
|
|
+**And** 所有类型使用 TypeScript 严格模式,无 `any` 类型
|
|
|
|
|
+**And** 所有导出类型都有完整的 JSDoc 注释
|
|
|
|
|
+**And** 类型检查通过(`pnpm typecheck`)
|
|
|
|
|
+
|
|
|
|
|
+## Tasks / Subtasks
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 实现 `src/types.ts` - 共享和特定类型定义 (AC: 1, 2, 4, 5)
|
|
|
|
|
+ - [ ] 导入并重新导出 Playwright `Page` 类型
|
|
|
|
|
+ - [ ] 定义 `BaseOptions` 接口(timeout 等通用配置)
|
|
|
|
|
+ - [ ] 定义 `ErrorContext` 接口(operation, target, expected, actual, available, suggestion)
|
|
|
|
|
+ - [ ] 定义 `AsyncSelectOptions` 接口(extends BaseOptions)
|
|
|
|
|
+ - [ ] 定义 `FileUploadOptions` 接口(extends BaseOptions)
|
|
|
|
|
+ - [ ] 定义 `FormStepOptions` 接口(extends BaseOptions)
|
|
|
|
|
+ - [ ] 定义 `DialogOptions` 接口(extends BaseOptions)
|
|
|
|
|
+ - [ ] 为所有导出类型添加完整 JSDoc 注释
|
|
|
|
|
+- [ ] 实现 `src/errors.ts` - 错误类和错误处理 (AC: 2, 5)
|
|
|
|
|
+ - [ ] 实现 `E2ETestError` 类(extends Error)
|
|
|
|
|
+ - [ ] 实现 `formatErrorMessage` 私有函数(生成友好错误消息)
|
|
|
|
|
+ - [ ] 实现 `throwError` 辅助函数(抛出结构化错误)
|
|
|
|
|
+ - [ ] 为 `E2ETestError` 添加完整 JSDoc 注释
|
|
|
|
|
+- [ ] 实现 `src/constants.ts` - 超时和选择器策略常量 (AC: 3)
|
|
|
|
|
+ - [ ] 定义 `DEFAULT_TIMEOUTS` 常量(static: 2000, async: 5000, networkIdle: 10000)
|
|
|
|
|
+ - [ ] 定义 `SELECTOR_STRATEGIES` 常量(testid → ARIA → text)
|
|
|
|
|
+ - [ ] 为所有常量添加 JSDoc 注释
|
|
|
|
|
+- [ ] 更新 `src/index.ts` 导出新增类型和错误类 (AC: 1, 2, 3)
|
|
|
|
|
+ - [ ] 导出 `types.ts` 中的所有类型
|
|
|
|
|
+ - [ ] 导出 `errors.ts` 中的 `E2ETestError`
|
|
|
|
|
+ - [ ] 导出 `constants.ts` 中的所有常量
|
|
|
|
|
+- [ ] 验证类型检查通过 (AC: 6)
|
|
|
|
|
+ - [ ] 运行 `pnpm typecheck` 确保无类型错误
|
|
|
|
|
+ - [ ] 验证所有类型都有正确的 JSDoc 注释
|
|
|
|
|
+
|
|
|
|
|
+## Dev Notes
|
|
|
|
|
+
|
|
|
|
|
+### Epic 1 背景
|
|
|
|
|
+
|
|
|
|
|
+**Epic 1 目标:** 测试开发者可以安装 `@d8d/e2e-test-utils` 包,立即使用 Select 工具测试 Radix UI Select 组件。
|
|
|
|
|
+
|
|
|
|
|
+**本故事在 Epic 中的位置:** 第二个故事,在包结构(Story 1.1)建立后,实现类型定义和错误处理基础设施,为所有后续工具函数提供共享类型和统一的错误处理。
|
|
|
|
|
+
|
|
|
|
|
+### 架构约束和模式
|
|
|
|
|
+
|
|
|
|
|
+**从架构文档中必须遵循的决策:**
|
|
|
|
|
+
|
|
|
|
|
+**类型系统策略:分层类型(共享+特定)**
|
|
|
|
|
+- `types.ts` 存放共享类型(`BaseOptions`, `ErrorContext`)
|
|
|
|
|
+- 各模块文件存放特定类型(如 `AsyncSelectOptions` 在 `radix-select.ts` 中)
|
|
|
|
|
+- 所有配置对象继承 `BaseOptions`
|
|
|
|
|
+
|
|
|
|
|
+**错误处理策略:结构化错误类 + 友好消息**
|
|
|
|
|
+- 使用 `E2ETestError` 类(extends Error)
|
|
|
|
|
+- 包含结构化的 `ErrorContext` 信息
|
|
|
|
|
+- 错误消息格式:❌ 操作失败、上下文信息、💡 修复建议
|
|
|
|
|
+
|
|
|
|
|
+**常量定义策略:**
|
|
|
|
|
+- 超时使用 `DEFAULT_TIMEOUTS` 常量,不硬编码
|
|
|
|
|
+- 选择器策略使用 `SELECTOR_STRATEGIES` 常量
|
|
|
|
|
+
|
|
|
|
|
+### 技术实现要求
|
|
|
|
|
+
|
|
|
|
|
+**`src/types.ts` - 类型定义实现指南:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import type { Page } from '@playwright/test';
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 基础配置选项,所有配置对象的基类
|
|
|
|
|
+ *
|
|
|
|
|
+ * @example
|
|
|
|
|
+ * ```ts
|
|
|
|
|
+ * interface MyOptions extends BaseOptions {
|
|
|
|
|
+ * customOption?: string;
|
|
|
|
|
+ * }
|
|
|
|
|
+ * ```
|
|
|
|
|
+ */
|
|
|
|
|
+export interface BaseOptions {
|
|
|
|
|
+ /** 超时时间(毫秒)*/
|
|
|
|
|
+ timeout?: number;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 错误上下文接口,用于提供结构化的错误信息
|
|
|
|
|
+ */
|
|
|
|
|
+export interface ErrorContext {
|
|
|
|
|
+ /** 操作类型(如 'selectRadixOption')*/
|
|
|
|
|
+ operation: string;
|
|
|
|
|
+ /** 目标(如下拉框标签)*/
|
|
|
|
|
+ target: string;
|
|
|
|
|
+ /** 期望值 */
|
|
|
|
|
+ expected?: string;
|
|
|
|
|
+ /** 实际值 */
|
|
|
|
|
+ actual?: string;
|
|
|
|
|
+ /** 可用选项列表 */
|
|
|
|
|
+ available?: string[];
|
|
|
|
|
+ /** 修复建议 */
|
|
|
|
|
+ suggestion?: string;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 异步 Select 选项配置
|
|
|
|
|
+ *
|
|
|
|
|
+ * @example
|
|
|
|
|
+ * ```ts
|
|
|
|
|
+ * await selectRadixOptionAsync(page, '省份', '广东省', {
|
|
|
|
|
+ * timeout: 10000,
|
|
|
|
|
+ * waitForOption: true
|
|
|
|
|
+ * });
|
|
|
|
|
+ * ```
|
|
|
|
|
+ */
|
|
|
|
|
+export interface AsyncSelectOptions extends BaseOptions {
|
|
|
|
|
+ /** 是否等待选项加载完成(默认:true)*/
|
|
|
|
|
+ waitForOption?: boolean;
|
|
|
|
|
+ /** 等待网络空闲后再操作(默认:false)*/
|
|
|
|
|
+ waitForNetworkIdle?: boolean;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 文件上传选项配置
|
|
|
|
|
+ */
|
|
|
|
|
+export interface FileUploadOptions extends BaseOptions {
|
|
|
|
|
+ /** 验证文件是否成功上传(默认:true)*/
|
|
|
|
|
+ verifyUpload?: boolean;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 表单步骤配置
|
|
|
|
|
+ */
|
|
|
|
|
+export interface FormStepOptions extends BaseOptions {
|
|
|
|
|
+ /** 是否在填写前滚动到元素(默认:true)*/
|
|
|
|
|
+ scrollToElement?: boolean;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 对话框操作配置
|
|
|
|
|
+ */
|
|
|
|
|
+export interface DialogOptions extends BaseOptions {
|
|
|
|
|
+ /** 对话框关闭后的等待时间(毫秒,默认:500)*/
|
|
|
|
|
+ closeWaitTime?: number;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 重新导出 Playwright 类型以便使用者使用
|
|
|
|
|
+export type { Page } from '@playwright/test';
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**`src/errors.ts` - 错误处理实现指南:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import type { ErrorContext } from './types';
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * E2E 测试专用错误类
|
|
|
|
|
+ *
|
|
|
|
|
+ * 提供结构化的错误上下文信息,帮助开发者快速定位问题。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @example
|
|
|
|
|
+ * ```ts
|
|
|
|
|
+ * throw new E2ETestError({
|
|
|
|
|
+ * operation: 'selectRadixOption',
|
|
|
|
|
+ * target: '残疾类型',
|
|
|
|
|
+ * expected: '视力残疾',
|
|
|
|
|
+ * available: ['听力残疾', '言语残疾', '肢体残疾']
|
|
|
|
|
+ * });
|
|
|
|
|
+ * ```
|
|
|
|
|
+ */
|
|
|
|
|
+export class E2ETestError extends Error {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建一个 E2E 测试错误实例
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param context - 结构化的错误上下文
|
|
|
|
|
+ * @param message - 自定义错误消息(可选,默认自动生成)
|
|
|
|
|
+ */
|
|
|
|
|
+ constructor(
|
|
|
|
|
+ public readonly context: ErrorContext,
|
|
|
|
|
+ message?: string
|
|
|
|
|
+ ) {
|
|
|
|
|
+ super(message || formatErrorMessage(context));
|
|
|
|
|
+ this.name = 'E2ETestError';
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 格式化错误消息为友好格式
|
|
|
|
|
+ *
|
|
|
|
|
+ * @internal
|
|
|
|
|
+ */
|
|
|
|
|
+function formatErrorMessage(context: ErrorContext): string {
|
|
|
|
|
+ const parts: string[] = [
|
|
|
|
|
+ `❌ ${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');
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 抛出 E2E 测试错误的辅助函数
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param context - 错误上下文
|
|
|
|
|
+ * @throws {E2ETestError} 永远抛出错误
|
|
|
|
|
+ *
|
|
|
|
|
+ * @example
|
|
|
|
|
+ * ```ts
|
|
|
|
|
+ * if (!optionFound) {
|
|
|
|
|
+ * throwError({
|
|
|
|
|
+ * operation: 'selectRadixOption',
|
|
|
|
|
+ * target: label,
|
|
|
|
|
+ * expected: value,
|
|
|
|
|
+ * available: availableOptions,
|
|
|
|
|
+ * suggestion: '检查选项值是否正确'
|
|
|
|
|
+ * });
|
|
|
|
|
+ * }
|
|
|
|
|
+ * ```
|
|
|
|
|
+ */
|
|
|
|
|
+export function throwError(context: ErrorContext): never {
|
|
|
|
|
+ throw new E2ETestError(context);
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**`src/constants.ts` - 常量定义实现指南:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+/**
|
|
|
|
|
+ * 默认超时配置(毫秒)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @example
|
|
|
|
|
+ * ```ts
|
|
|
|
|
+ * const timeout = options.timeout ?? DEFAULT_TIMEOUTS.static;
|
|
|
|
|
+ * ```
|
|
|
|
|
+ */
|
|
|
|
|
+export const DEFAULT_TIMEOUTS = {
|
|
|
|
|
+ /** 静态选项超时(2秒)*/
|
|
|
|
|
+ static: 2000,
|
|
|
|
|
+ /** 异步选项超时(5秒)*/
|
|
|
|
|
+ async: 5000,
|
|
|
|
|
+ /** 网络空闲超时(10秒)*/
|
|
|
|
|
+ networkIdle: 10000
|
|
|
|
|
+} as const;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 选择器策略常量
|
|
|
|
|
+ *
|
|
|
|
|
+ * 定义选择器查找的优先级顺序,用于应对 Radix UI 版本升级。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @example
|
|
|
|
|
+ * ```ts
|
|
|
|
|
+ * // 按优先级尝试选择器
|
|
|
|
|
+ * for (const strategy of SELECTOR_STRATEGIES) {
|
|
|
|
|
+ * const element = await findByStrategy(strategy, label);
|
|
|
|
|
+ * if (element) return element;
|
|
|
|
|
+ * }
|
|
|
|
|
+ * ```
|
|
|
|
|
+ */
|
|
|
|
|
+export const SELECTOR_STRATEGIES = [
|
|
|
|
|
+ 'data-testid',
|
|
|
|
|
+ 'aria-label + role',
|
|
|
|
|
+ 'text content + role'
|
|
|
|
|
+] as const;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 选择器策略类型
|
|
|
|
|
+ */
|
|
|
|
|
+export type SelectorStrategy = typeof SELECTOR_STRATEGIES[number];
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**`src/index.ts` - 更新主导出文件:**
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 导出类型定义
|
|
|
|
|
+export * from './types';
|
|
|
|
|
+
|
|
|
|
|
+// 导出错误类
|
|
|
|
|
+export * from './errors';
|
|
|
|
|
+
|
|
|
|
|
+// 导出常量
|
|
|
|
|
+export * from './constants';
|
|
|
|
|
+
|
|
|
|
|
+// Radix UI Select 工具(后续故事实现)
|
|
|
|
|
+// export * from './radix-select';
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 项目标准对齐
|
|
|
|
|
+
|
|
|
|
|
+**与 project-context.md 对齐:**
|
|
|
|
|
+
|
|
|
|
|
+1. **TypeScript 配置**:
|
|
|
|
|
+ - 严格模式已启用(`strict: true`),禁止 `any` 类型
|
|
|
|
|
+ - 所有类型定义必须有明确类型注解
|
|
|
|
|
+
|
|
|
|
|
+2. **JSDoc 注释标准**:
|
|
|
|
|
+ - 所有导出类型、函数、类必须有完整 JSDoc
|
|
|
|
|
+ - 使用 `@param`, `@throws`, `@example` 标签
|
|
|
|
|
+ - 添加使用示例代码
|
|
|
|
|
+
|
|
|
|
|
+3. **命名约定**:
|
|
|
|
|
+ - 接口:PascalCase,`Options` 后缀(如 `BaseOptions`)
|
|
|
|
|
+ - 常量:UPPER_SNAKE_CASE(如 `DEFAULT_TIMEOUTS`)
|
|
|
|
|
+ - 类:PascalCase,无前缀(如 `E2ETestError`)
|
|
|
|
|
+ - 函数:camelCase(如 `throwError`)
|
|
|
|
|
+
|
|
|
|
|
+### 与前一个故事的集成
|
|
|
|
|
+
|
|
|
|
|
+**Story 1.1 已完成的工作:**
|
|
|
|
|
+- ✅ 包结构已创建:`packages/e2e-test-utils/`
|
|
|
|
|
+- ✅ 配置文件已就绪:`package.json`, `tsconfig.json`, `vitest.config.ts`
|
|
|
|
|
+- ✅ 占位文件已创建:`src/types.ts`, `src/errors.ts`, `src/constants.ts`
|
|
|
|
|
+- ✅ TypeScript 严格模式已启用
|
|
|
|
|
+- ✅ 目录结构已创建:`tests/unit/`, `tests/fixtures/`
|
|
|
|
|
+
|
|
|
|
|
+**本故事需要做的:**
|
|
|
|
|
+- 将占位文件替换为完整实现
|
|
|
|
|
+- 确保所有类型定义与占位接口兼容
|
|
|
|
|
+- 运行 `pnpm typecheck` 验证类型检查通过
|
|
|
|
|
+
|
|
|
|
|
+### 类型检查验证
|
|
|
|
|
+
|
|
|
|
|
+**运行命令:**
|
|
|
|
|
+```bash
|
|
|
|
|
+cd packages/e2e-test-utils
|
|
|
|
|
+pnpm typecheck
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**预期结果:**
|
|
|
|
|
+- 无类型错误输出
|
|
|
|
|
+- 所有 JSDoc 注释正确识别
|
|
|
|
|
+- 导出类型可以被正确推断
|
|
|
|
|
+
|
|
|
|
|
+### 文件结构约束
|
|
|
|
|
+
|
|
|
|
|
+**必须遵循的文件结构:**
|
|
|
|
|
+```
|
|
|
|
|
+packages/e2e-test-utils/src/
|
|
|
|
|
+├── index.ts # 主导出(更新,导出新类型和错误类)
|
|
|
|
|
+├── types.ts # 共享类型定义(完整实现)
|
|
|
|
|
+├── errors.ts # 错误类和错误处理(完整实现)
|
|
|
|
|
+└── constants.ts # 常量定义(完整实现)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**禁止事项(Anti-Patterns):**
|
|
|
|
|
+- ❌ 使用 `any` 类型
|
|
|
|
|
+- ❌ 硬编码超时值(必须使用 `DEFAULT_TIMEOUTS`)
|
|
|
|
|
+- ❌ 抛出原生 `Error`(必须使用 `E2ETestError`)
|
|
|
|
|
+- ❌ 缺少 JSDoc 注释
|
|
|
|
|
+- ❌ 配置对象不继承 `BaseOptions`
|
|
|
|
|
+
|
|
|
|
|
+### 测试要求
|
|
|
|
|
+
|
|
|
|
|
+**单元测试(在 Story 1.6 中实现):**
|
|
|
|
|
+本故事创建的类型和错误类将在 Story 1.6 中进行单元测试。
|
|
|
|
|
+
|
|
|
|
|
+**当前验证方法:**
|
|
|
|
|
+- 类型检查:`pnpm typecheck`
|
|
|
|
|
+- JSDoc 验证:手动检查所有导出都有完整注释
|
|
|
|
|
+
|
|
|
|
|
+### 性能约束
|
|
|
|
|
+
|
|
|
|
|
+**从 NFR 提取的性能要求:**
|
|
|
|
|
+- NFR8: 静态 Select 选择操作应在 2 秒内完成
|
|
|
|
|
+- NFR9: 异步 Select 选择操作应在 5 秒内完成(默认超时)
|
|
|
|
|
+- NFR10: 工具函数本身的开销不超过 100ms
|
|
|
|
|
+
|
|
|
|
|
+**本故事相关的性能约束:**
|
|
|
|
|
+- 类型定义必须是零运行时开销(TypeScript 编译后完全移除)
|
|
|
|
|
+- 错误消息格式化不应超过 10ms
|
|
|
|
|
+
|
|
|
|
|
+### 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/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/epics.md#从-architecture-文档提取的技术需求) - 分层类型设计
|
|
|
|
|
+
|
|
|
|
|
+**Architecture 来源:**
|
|
|
|
|
+- [Architecture - 类型系统策略](_bmad-output/planning-artifacts/architecture.md#type-system-strategy) - 分层类型决策
|
|
|
|
|
+- [Architecture - 错误处理策略](_bmad-output/planning-artifacts/architecture.md#error-handling-strategy) - 结构化错误类
|
|
|
|
|
+- [Architecture - 实现模式](_bmad-output/planning-artifacts/architecture.md#implementation-patterns--consistency-rules) - 命名和格式约定
|
|
|
|
|
+- [Architecture - 项目结构](_bmad-output/planning-artifacts/architecture.md#project-structure--boundaries) - 完整目录结构
|
|
|
|
|
+
|
|
|
|
|
+**标准文档来源:**
|
|
|
|
|
+- [E2E Radix UI 测试标准](docs/standards/e2e-radix-testing.md) - 核心测试标准文档
|
|
|
|
|
+- [Project Context](_bmad-output/project-context.md) - 项目技术栈和规则
|
|
|
|
|
+
|
|
|
|
|
+**Epic 来源:**
|
|
|
|
|
+- [Epic 1 - Story 1.2](_bmad-output/planning-artifacts/epics.md#story-12-实现类型定义和错误处理) - 原始用户故事和验收标准
|
|
|
|
|
+
|
|
|
|
|
+**前一个故事:**
|
|
|
|
|
+- [Story 1.1 - 创建包基础结构和配置](_bmad-output/implementation-artifacts/1-1-create-package-structure.md) - 包基础设施
|
|
|
|
|
+
|
|
|
|
|
+## Dev Agent Record
|
|
|
|
|
+
|
|
|
|
|
+### Agent Model Used
|
|
|
|
|
+
|
|
|
|
|
+Claude (d8d-model) via create-story workflow
|
|
|
|
|
+
|
|
|
|
|
+### Debug Log References
|
|
|
|
|
+
|
|
|
|
|
+### Completion Notes List
|
|
|
|
|
+
|
|
|
|
|
+- 故事创建时间: 2026-01-08
|
|
|
|
|
+- 基于 PRD、Architecture、E2E Radix 测试标准、Project Context 文档创建
|
|
|
|
|
+- 包含完整的类型定义实现指南、错误处理实现指南、常量定义实现指南
|
|
|
|
|
+- 为后续工具函数提供类型基础设施
|
|
|
|
|
+- 包含架构约束、项目标准对齐、前一个故事集成上下文
|
|
|
|
|
+
|
|
|
|
|
+### File List
|
|
|
|
|
+
|
|
|
|
|
+**本故事将创建/修改的文件:**
|
|
|
|
|
+- `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/index.ts` - 更新主导出,导出新增类型和错误类
|
|
|
|
|
+
|
|
|
|
|
+**相关文件(只读,用于参考):**
|
|
|
|
|
+- `_bmad-output/implementation-artifacts/1-1-create-package-structure.md` - 前一个故事
|
|
|
|
|
+- `_bmad-output/planning-artifacts/epics.md` - Epic 和故事定义
|
|
|
|
|
+- `_bmad-output/planning-artifacts/architecture.md` - 架构决策和模式
|
|
|
|
|
+- `_bmad-output/project-context.md` - 项目技术栈和规则
|