Răsfoiți Sursa

feat(story): 创建 Story 12.6 - 人才小程序 Page Object

创建人才小程序 Page Object Story,为后续小程序登录测试做准备。

Co-Authored-By: Claude <noreply@anthropic.com>
yourname 4 zile în urmă
părinte
comite
61af303a5f

+ 374 - 0
_bmad-output/implementation-artifacts/12-6-talent-mini-page-object.md

@@ -0,0 +1,374 @@
+# Story 12.6: 人才小程序 Page Object
+
+Status: ready-for-dev
+
+<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
+
+## Story
+
+作为测试开发者,
+我想要创建人才小程序的 Page Object,
+以便组织人才小程序相关的页面元素和操作。
+
+## Acceptance Criteria
+
+### AC1: Page Object 基础结构
+**Given** Playwright E2E 测试框架已配置
+**When** 创建人才小程序 Page Object
+**Then** 测试应满足以下要求:
+- 创建 `web/tests/e2e/pages/mini/talent-mini.page.ts` 文件
+- 定义 `TalentMiniPage` 类,继承 Playwright 的 Page 对象模式
+- 实现基础选择器定义(登录表单、主页元素等)
+- 所有选择器使用 `data-testid` 属性(优先级高于文本选择器)
+- 遵循项目 Page Object 设计模式
+
+### AC2: 小程序页面导航
+**Given** 人才小程序 Page Object 已创建
+**When** 实现页面导航方法
+**Then** 测试应满足以下要求:
+- 实现 `goto()` 方法导航到人才小程序 H5 页面 (`/talent-mini`)
+- 实现 `expectToBeVisible()` 方法验证页面可见性
+- 验证页面正确加载(检查关键元素存在)
+- 处理页面加载超时情况
+
+### AC3: 登录功能封装
+**Given** 人才小程序 Page Object 已创建
+**When** 实现登录相关方法
+**Then** 测试应满足以下要求:
+- 实现 `login(username, password)` 方法执行登录操作
+- 实现填写用户名方法 `fillUsername(username)`
+- 实现填写密码方法 `fillPassword(password)`
+- 实现点击登录按钮方法 `clickLoginButton()`
+- 实现验证登录成功方法 `expectLoginSuccess()`
+- 处理登录失败场景(错误提示显示)
+
+### AC4: Token 存储和管理
+**Given** 小程序登录后需要存储 token 用于后续操作
+**When** 实现 token 管理方法
+**Then** 测试应满足以下要求:
+- 实现 `getToken()` 方法获取当前存储的 token
+- 实现 `setToken(token)` 方法设置 token(用于测试前置条件)
+- 使用 localStorage 或 sessionStorage 存储 token
+- 验证 token 在页面刷新后仍然有效
+
+### AC5: 主页元素选择器
+**Given** 人才小程序登录后进入主页
+**When** 定义主页元素选择器
+**Then** 测试应满足以下要求:
+- 定义工作列表选择器(如适用)
+- 定义导航菜单选择器
+- 定义用户信息显示选择器
+- 所有选择器使用 `data-testid` 属性
+- 提供清晰的类型定义
+
+### AC6: 代码质量标准
+**Given** 遵循项目测试规范
+**When** 编写 Page Object 代码
+**Then** 代码应符合以下标准:
+- TypeScript 类型安全,无 `any` 类型
+- 所有公共方法有完整的 JSDoc 注释
+- 使用 TIMEOUTS 常量定义超时
+- 遵循项目命名约定(类名 PascalCase,方法名 camelCase)
+- 通过 `pnpm typecheck` 类型检查
+
+## Tasks / Subtasks
+
+- [ ] 任务 1: 创建 Page Object 基础结构 (AC: #1, #6)
+  - [ ] 1.1 确认 `web/tests/e2e/pages/mini/` 目录存在
+  - [ ] 1.2 创建 `talent-mini.page.ts` 文件
+  - [ ] 1.3 定义 `TalentMiniPage` 类
+  - [ ] 1.4 定义基础选择器(使用 `data-testid`)
+
+- [ ] 任务 2: 实现页面导航功能 (AC: #2)
+  - [ ] 2.1 实现 `goto()` 方法(导航到 `/talent-mini`)
+  - [ ] 2.2 实现 `expectToBeVisible()` 方法
+  - [ ] 2.3 添加页面加载验证逻辑
+
+- [ ] 任务 3: 实现登录功能封装 (AC: #3)
+  - [ ] 3.1 实现 `fillUsername()` 方法(使用手机号或用户名)
+  - [ ] 3.2 实现 `fillPassword()` 方法
+  - [ ] 3.3 实现 `clickLoginButton()` 方法
+  - [ ] 3.4 实现 `login()` 完整登录方法
+  - [ ] 3.5 实现 `expectLoginSuccess()` 验证方法
+  - [ ] 3.6 实现 `expectLoginError()` 错误验证方法
+
+- [ ] 任务 4: 实现 Token 管理 (AC: #4)
+  - [ ] 4.1 实现 `getToken()` 方法
+  - [ ] 4.2 实现 `setToken()` 方法
+  - [ ] 4.3 实现 `clearAuth()` 清除认证方法
+
+- [ ] 任务 5: 定义主页元素选择器 (AC: #5)
+  - [ ] 5.1 定义工作列表选择器(待主页实现后添加对应 testid)
+  - [ ] 5.2 定义导航菜单选择器(待主页实现后添加对应 testid)
+  - [ ] 5.3 定义用户信息选择器(待主页实现后添加对应 testid)
+
+- [ ] 任务 6: 代码质量验证 (AC: #6)
+  - [ ] 6.1 运行 `pnpm typecheck` 验证类型检查
+  - [ ] 6.2 添加完整的 JSDoc 注释
+  - [ ] 6.3 验证选择器使用 data-testid
+
+- [ ] 任务 7: 更新 fixtures 文件 (AC: #6)
+  - [ ] 7.1 在 `web/tests/e2e/fixtures.ts` 中添加 `talentMiniPage` fixture
+  - [ ] 7.2 验证 fixture 正确初始化(类型检查通过)
+
+- [ ] 任务 8: 添加 data-testid 属性 (AC: #1)
+  - [ ] 8.1 在人才小程序登录页面添加 `data-testid` 属性
+  - [ ] 8.2 确保所有关键元素都有对应的 testid
+
+## Dev Notes
+
+### Epic 12 背景和依赖
+
+**Epic 12 目标:** 为用户管理和小程序登录编写 E2E 测试,解锁小程序端的测试能力
+
+**小程序技术要点(来自 Epic 12 文档):**
+- 企业小程序 H5 URL: `http://localhost:8080/mini`
+- 人才小程序 H5 URL: `http://localhost:8080/talent-mini`
+- 登录后存储 token 进行后续操作
+- 使用 Playwright 测试 H5 页面
+- 小程序只读,无写操作
+
+**Epic 12 Story 依赖关系:**
+```
+Story 12.1: 用户管理 Page Object ✅ (已完成)
+Story 12.2: 后台创建企业用户测试 ✅ (已完成)
+Story 12.3: 后台创建人才用户测试 ✅ (已完成)
+Story 12.4: 企业小程序 Page Object ✅ (已完成)
+Story 12.5: 企业小程序登录测试 🔄 (进行中)
+Story 12.6: 人才小程序 Page Object ← 当前 Story
+Story 12.7: 人才小程序登录测试
+Story 12.8: 用户权限验证测试
+```
+
+### Story 12.4 关键经验
+
+从已完成的 Story 12.4(企业小程序 Page Object)中学习到的模式:
+
+**企业小程序登录页面选择器模式:**
+```typescript
+private readonly selectors = {
+  // 页面级选择器
+  loginPage: '[data-testid="mini-login-page"]',
+  pageTitle: '[data-testid="mini-page-title"]',
+
+  // 登录表单选择器
+  phoneInput: '[data-testid="mini-phone-input"]',
+  passwordInput: '[data-testid="mini-password-input"]',
+  loginButton: '[data-testid="mini-login-button"]',
+
+  // 主页选择器(登录后)
+  userInfo: '[data-testid="mini-user-info"]',
+};
+```
+
+**人才小程序选择器命名建议:**
+- 使用 `talent-` 前缀区分与企业小程序
+- 例如:`talent-login-page`, `talent-phone-input`, `talent-password-input`
+
+**Taro Input 组件处理方式:**
+```typescript
+// Taro 的 Input 组件使用自定义元素,使用 type() 代替 fill()
+async fillPhone(phone: string): Promise<void> {
+  await this.phoneInput.click();
+  await this.page.keyboard.press('Control+A');
+  await this.phoneInput.type(phone, { delay: 10 });
+}
+```
+
+### 小程序登录流程
+
+**预期登录流程:**
+1. 导航到 `/talent-mini` 页面
+2. 填写用户名(在测试中创建的人才用户)
+3. 填写密码
+4. 点击登录按钮
+5. 验证登录成功(跳转到主页或显示用户信息)
+6. 存储 token 用于后续请求
+
+**测试用户创建(参考 Story 12.3):**
+```typescript
+// Story 12.3 创建的人才用户
+const talentUserData = {
+  username: `test_talent_${Date.now()}`,
+  password: 'password123',
+  nickname: '测试人才用户',
+  userType: UserType.TALENT,
+  disabilityPersonId: 1,  // 关联残疾人
+};
+```
+
+### Token 管理策略
+
+**存储位置:** localStorage 或 sessionStorage(根据实际小程序实现)
+
+**Token 操作方法(参考 Story 12.4):**
+```typescript
+// 获取 token
+async getToken(): Promise<string | null> {
+  return await this.page.evaluate(() => {
+    return localStorage.getItem('token') || sessionStorage.getItem('token');
+  });
+}
+
+// 设置 token(用于测试前置条件)
+async setToken(token: string): Promise<void> {
+  await this.page.evaluate((t) => {
+    localStorage.setItem('token', t);
+  }, token);
+}
+
+// 清除所有认证存储
+async clearAuth(): Promise<void> {
+  await this.page.evaluate(() => {
+    localStorage.removeItem('token');
+    localStorage.removeItem('auth_token');
+    sessionStorage.removeItem('token');
+    sessionStorage.removeItem('auth_token');
+  });
+}
+```
+
+### Playwright Fixture 集成
+
+**在 `web/tests/e2e/fixtures.ts` 中添加 fixture:**
+```typescript
+import { test as base } from '@playwright/test';
+import { TalentMiniPage } from './pages/mini/talent-mini.page';
+
+type TalentMiniFixtures = {
+  talentMiniPage: TalentMiniPage;
+};
+
+export const test = base.extend<TalentMiniFixtures>({
+  talentMiniPage: async ({ page }, use) => {
+    const talentMiniPage = new TalentMiniPage(page);
+    await use(talentMiniPage);
+  },
+});
+```
+
+### 项目结构
+
+**新建文件:**
+- `web/tests/e2e/pages/mini/talent-mini.page.ts`
+
+**相关参考文件:**
+- `web/tests/e2e/pages/mini/enterprise-mini.page.ts` (Story 12.4) - 企业小程序 Page Object
+- `web/tests/e2e/pages/admin/user-management.page.ts` (Story 12.1) - 用户管理 Page Object
+- `web/tests/e2e/utils/timeouts.ts` - TIMEOUTS 常量
+
+### 小程序只读特性
+
+根据 Epic 12 文档:
+- 小程序只读,无写操作
+- 这意味着 Page Object 不需要包含创建、编辑、删除等操作方法
+- 主要关注登录、查看、验证等只读操作
+
+### E2E 测试和主页实现的关联
+
+**E2E 测试计划:**
+- Story 12.6:人才小程序 Page Object 基础结构(当前 Story)
+- Story 12.7:人才小程序登录 E2E 测试(将在该 Story 中实现完整的登录测试)
+
+**主页元素选择器状态:**
+- 任务 5.1(工作列表选择器):待小程序主页实现后添加对应 testid
+- 任务 5.2(导航菜单选择器):待小程序主页实现后添加对应 testid
+- 任务 5.3(用户信息选择器):待主页实现后添加对应 testid
+
+**原因说明:**
+主页元素(工作列表、导航菜单、用户信息)的选择器需要在实际主页实现时才能确定对应的 testid。当前 Story 12.6 专注于 Page Object 的基础结构设计和登录功能,主页相关元素的选择器将在主页实现时同步添加,并在 Story 12.7 的 E2E 测试中验证。
+
+**Token 持久性验证:**
+Token 在页面刷新后的持久性验证将在 Story 12.7 的 E2E 测试中实现,包括:
+- 验证 token 在 localStorage 中的存储
+- 验证页面刷新后 token 仍然有效
+- 验证使用已存储 token 可以继续访问需要认证的页面
+
+### 选择器策略
+
+**优先级(遵循项目标准):**
+1. `data-testid` 属性(最高优先级)
+2. ARIA 属性 + role
+3. 文本内容(最低优先级,避免使用)
+
+**示例:**
+```typescript
+private readonly selectors = {
+  // ✅ 优先:data-testid(使用 talent- 前缀)
+  usernameInput: '[data-testid="talent-username-input"]',
+  passwordInput: '[data-testid="talent-password-input"]',
+  loginButton: '[data-testid="talent-login-button"]',
+
+  // ⚠️ 备选:ARIA + role(如 data-testid 不可用)
+  // usernameInput: '[aria-label="用户名"]',
+
+  // ❌ 避免:纯文本选择器
+  // usernameInput: 'text=用户名',
+};
+```
+
+### TypeScript 类型定义
+
+**Page Object 类类型:**
+```typescript
+export class TalentMiniPage {
+  readonly page: Page;
+
+  constructor(page: Page) {
+    this.page = page;
+  }
+
+  // 所有方法应有明确的返回类型
+  async goto(): Promise<void> { }
+  async login(username: string, password: string): Promise<void> { }
+  async expectLoginSuccess(): Promise<void> { }
+}
+```
+
+### 测试超时配置
+
+**使用 TIMEOUTS 常量:**
+```typescript
+import { TIMEOUTS } from '../utils/timeouts';
+
+await expect(this.page.locator(this.selectors.loginButton)).toBeVisible({
+  timeout: TIMEOUTS.default,
+});
+```
+
+### 参考文档
+
+**架构文档:**
+- `_bmad-output/planning-artifacts/architecture.md`
+- `docs/standards/e2e-radix-testing.md` (Radix UI 测试标准)
+
+**相关 Story 文档:**
+- `12-1-user-page-object.md` (用户管理 Page Object)
+- `12-3-create-talent-user.md` (后台创建人才用户测试)
+- `12-4-enterprise-mini-page-object.md` (企业小程序 Page Object)
+
+## Dev Agent Record
+
+### Agent Model Used
+
+Claude (d8d-model)
+
+### Debug Log References
+
+_N/A - 无需调试_
+
+### Completion Notes List
+
+_待开发完成后填写_
+
+### File List
+
+_待开发完成后填写_
+
+## Change Log
+
+- 2026-01-14: Story 12.6 创建完成
+  - 人才小程序 Page Object 基础结构设计
+  - 登录功能封装需求
+  - Token 管理策略
+  - 状态:ready-for-dev

+ 10 - 9
_bmad-output/implementation-artifacts/sprint-status.yaml

@@ -145,7 +145,8 @@ development_status:
   # 背景: 订单管理是招聘系统的核心业务功能,涉及复杂表单、状态流转、人员关联等场景
   # 依赖: Epic 1 和 Epic 2 完成(Select 工具基础)
   # 详情参见: _bmad-output/planning-artifacts/epics.md (Epic 10)
-  epic-10: in-progress
+  # 回顾文档: _bmad-output/implementation-artifacts/epic-10-retrospective-2026-01-13.md
+  epic-10: done
   10-1-order-page-object: done                  # 创建订单管理 Page Object
   10-2-order-list-tests: done                  # 编写订单列表查看测试(代码审查完成,所有HIGH和MEDIUM问题已修复)
   10-3-order-filter-tests: done           # 编写订单搜索和筛选测试(代码审查完成,所有HIGH和MEDIUM问题已修复)
@@ -157,10 +158,10 @@ development_status:
   10-9-order-person-tests: done               # 编写人员关联功能测试 - 2026-01-13 完成:6/6 测试通过,代码审查完成
   10-10-order-attachment-tests: done         # 编写附件管理测试 - ✅ 完成 (2026-01-13) 代码审查完成,所有问题已修复
   10-11-order-complete-tests: done          # 编写订单完整流程测试 ✅ 2/2 测试通过,所有问题已修复 (2026-01-13)
-  10-12-run-tests-collect-issues: review  # 运行测试并收集问题和改进建议 ✅ 完成 (2026-01-13) - 发现4个问题,工具扩展需求少于3个
+  10-12-run-tests-collect-issues: done  # 运行测试并收集问题和改进建议 ✅ 完成 (2026-01-13) - 发现4个问题,工具扩展需求少于3个
   10-13-extend-utils-if-needed: n/a   # 扩展工具包(如需要)⏭️ 跳过 - 工具扩展需求评估结果:无需扩展,直接进入 Story 10.14
   10-14-order-stability-test: done     # 订单管理稳定性验证 ✅ 完成 (2026-01-13) - 稳定性测试完成,成功率 97.9%,问题已修复
-  epic-10-retrospective: optional
+  epic-10-retrospective: done              # 回顾完成于 2026-01-13,文档: epic-10-retrospective-2026-01-13.md
 
   # Epic 11: 基础配置管理测试 (Epic F - 业务测试 Epic)
   # 目标: 为平台、公司、渠道配置管理编写 E2E 测试
@@ -195,7 +196,7 @@ development_status:
   12-3-create-talent-user: done            # 后台创建人才用户测试 - 14 passed, 2 skipped (2026-01-13)
   12-4-enterprise-mini-page-object: done  # 企业小程序 Page Object ✅ 完成 (2026-01-13)
   12-5-enterprise-mini-login: in-progress      # 企业小程序登录测试 🚀 开发中 (2026-01-13)
-  12-6-talent-mini-page-object: backlog    # 人才小程序 Page Object
+  12-6-talent-mini-page-object: ready-for-dev    # 人才小程序 Page Object ✅ Story 创建完成 (2026-01-14)
   12-7-talent-mini-login: backlog          # 人才小程序登录测试
   12-8-user-permission-test: backlog       # 用户权限验证(小程序无写操作)
   epic-12-retrospective: optional
@@ -223,14 +224,14 @@ development_status:
 #   - Epic 3: 文件上传工具开发与验证 ✅
 #   - Epic 9: 残疾人管理完整 E2E 测试覆盖(含并行隔离)✅
 #
-# Epic B: 区域管理 E2E 测试 🔄 进行中
-#   - Epic 8: 区域管理 E2E 测试 (6/7 Stories done)
+# Epic B: 区域管理 E2E 测试 ✅ 完成
+#   - Epic 8: 区域管理 E2E 测试 
 #
-# Epic C: 订单管理 E2E 测试 🔄 进行中
-#   - Epic 10: 订单管理 E2E 测试 (14/14 Stories done) - 稳定性验证完成,成功率 97.9%
+# Epic C: 订单管理 E2E 测试 ✅ 完成
+#   - Epic 10: 订单管理 E2E 测试 (14/14 Stories done) - 稳定性 97.9%
 #
 # Epic D: 用户管理与小程序登录测试 🔄 进行中
-#   - Epic 12: 用户管理与小程序登录测试 (0/8 Stories, 1 ready-for-dev)
+#   - Epic 12: 用户管理与小程序登录测试 (4/8 Stories done)
 #
 # Epic E: 跨端数据同步测试 🆕 新增
 #   - Epic 13: 跨端数据同步测试 (0/5 Stories)