1-1-create-package-structure.md 21 KB

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/testAnd tsconfig.json 启用严格模式,目标 ES2020+ And 可以通过 pnpm add -D @d8d/e2e-test-utils@workspace:* 安装

Tasks / Subtasks

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

Review Follow-ups (AI)

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

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

审查发现: 9 个问题(3 HIGH, 3 MEDIUM, 2 LOW) 修复状态: 所有 HIGH 和 MEDIUM 问题已自动修复(6/6)

已修复的问题:

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

错误处理策略: 结构化错误类 + 友好消息

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 包结构:

{
  "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. maintypes 都指向 src/index.ts(源代码直接使用)
  3. exports 配置支持 tree-shaking
  4. peerDependencies 指定 Playwright 版本范围(兼容最新稳定版和上一个 LTS 版本)
  5. 添加测试脚本(单元测试、覆盖率)

tsconfig.json 配置要求

参考项目 TypeScript 严格模式配置:

{
  "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. 配置正确的 rootDiroutDir

vitest.config.ts 配置要求

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):

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

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

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

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

src/types.ts - 共享类型定义:

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 - 错误处理:

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 - 常量定义:

/**
 * 默认超时配置(毫秒)
 */
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;

目录创建命令参考

# 在项目根目录执行
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. 验证目录结构:

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 配置:

cd packages/e2e-test-utils
pnpm typecheck
# 应无错误输出

3. 验证包可以被安装:

# 在 monorepo 根目录
pnpm install
# 检查是否成功注册 workspace 包

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

4. 验证 Vitest 配置:

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 来源:

Architecture 来源:

标准文档来源:

Epic 来源:

参考包:

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%