12-6-talent-mini-page-object.md 18 KB

Story 12.6: 人才小程序 Page Object

Status: review

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

  • [x] 任务 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
  • [x] 任务 2: 实现页面导航功能 (AC: #2)

    • 2.1 实现 goto() 方法(导航到 /talent-mini
    • 2.2 实现 expectToBeVisible() 方法
    • 2.3 添加页面加载验证逻辑
  • [x] 任务 3: 实现登录功能封装 (AC: #3)

    • 3.1 实现 fillUsername() 方法(使用手机号或用户名)
    • 3.2 实现 fillPassword() 方法
    • 3.3 实现 clickLoginButton() 方法
    • 3.4 实现 login() 完整登录方法
    • 3.5 实现 expectLoginSuccess() 验证方法
    • 3.6 实现 expectLoginError() 错误验证方法
  • [x] 任务 4: 实现 Token 管理 (AC: #4)

    • 4.1 实现 getToken() 方法
    • 4.2 实现 setToken() 方法
    • 4.3 实现 clearAuth() 清除认证方法
  • [x] 任务 5: 定义主页元素选择器 (AC: #5)

    • 5.1 定义工作列表选择器(待主页实现后添加对应 testid)
    • 5.2 定义导航菜单选择器(待主页实现后添加对应 testid)
    • 5.3 定义用户信息选择器(待主页实现后添加对应 testid)
  • [x] 任务 6: 代码质量验证 (AC: #6)

    • 6.1 运行 pnpm typecheck 验证类型检查
    • 6.2 添加完整的 JSDoc 注释
    • 6.3 验证选择器使用 data-testid
  • [x] 任务 7: 更新 fixtures 文件 (AC: #6)

    • 7.1 在 web/tests/e2e/fixtures.ts 中添加 talentMiniPage fixture
    • 7.2 验证 fixture 正确初始化(类型检查通过)
  • [x] 任务 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)中学习到的模式:

企业小程序登录页面选择器模式:

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 组件处理方式:

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

// Story 12.3 创建的人才用户
const talentUserData = {
  username: `test_talent_${Date.now()}`,
  password: 'password123',
  nickname: '测试人才用户',
  userType: UserType.TALENT,
  disabilityPersonId: 1,  // 关联残疾人
};

Playwright MCP 探索结果

页面 URL 和路由结构:

  • H5 URL: http://localhost:8080/talent-mini (生产环境)
  • 开发环境: http://localhost:10087/talent-mini
  • 配置源: mini-talent/config/index.ts
    • publicPath: '/talent-mini/'
    • router.basename: '/talent-mini'
  • 路由配置: mini-talent/src/app.config.ts
    • 首页: pages/index/index
    • 登录页: pages/login/index

登录表单元素选择器(当前无 data-testid):

  • 源码位置: mini-ui-packages/rencai-auth-ui/src/pages/LoginPage/LoginPage.tsx
  • 重要: 当前登录页面没有添加 data-testid 属性,需要使用 role/text 选择器
  • 表单结构:

    - 导航栏标题: "人才登录" (Navbar组件)
    - 页面标题: "人才服务平台" (text)
    - 副标题: "欢迎回来" (text)
    - 账号输入标签: "手机号/身份证号/残疾证号" (text)
    - 账号输入框: placeholder="请输入手机号/身份证号/残疾证号" (Input)
    - 密码输入标签: "密码" (text)
    - 密码输入框: placeholder="请输入密码" (Input, password模式)
    - 登录按钮: "登录" (Button)
    - 忘记密码链接: "忘记密码?" (text)
    

Token 存储方式(通过源码确认):

  • Token Key: talent_token (在 rencai-auth-ui/src/hooks/useAuth.tsx 第22行)
  • User Key: talent_user (同上)
  • 存储方式: Taro.setStorageSync(TOKEN_KEY, token)
  • 在 H5 环境中,Taro.setStorageSync 会映射到 localStorage

与企业小程序对比:

特性 企业小程序 人才小程序
H5 URL /mini /talent-mini
Token Key enterprise_token talent_token
User Key enterprise_user talent_user
首页路径 /pages/yongren/dashboard/index /pages/index/index
登录页标题 "企业用户登录" "人才登录"
账号标签 "请输入手机号" "手机号/身份证号/残疾证号"
data-testid ✅ 已添加 ❌ 待添加

源码位置参考:

  • 人才小程序登录页面: mini-ui-packages/rencai-auth-ui/src/pages/LoginPage/LoginPage.tsx
  • 人才小程序桥接文件: mini-talent/src/pages/login/index.tsx
  • 人才小程序路由配置: mini-talent/src/app.config.ts
  • 人才小程序 H5 配置: mini-talent/config/index.ts
  • 企业小程序登录页面: mini-ui-packages/mini-enterprise-auth-ui/src/pages/login/Login.tsx
  • Auth Hook: mini-ui-packages/rencai-auth-ui/src/hooks/useAuth.tsx

Token 管理策略

存储位置: localStorage (H5 环境,通过 Taro.setStorageSync 映射)

Token 操作方法(使用 talent_token key):

// 获取 token
async getToken(): Promise<string | null> {
  return await this.page.evaluate(() => {
    return localStorage.getItem('talent_token');
  });
}

// 设置 token(用于测试前置条件)
async setToken(token: string): Promise<void> {
  await this.page.evaluate((t) => {
    localStorage.setItem('talent_token', t);
  }, token);
}

// 清除所有认证存储
async clearAuth(): Promise<void> {
  await this.page.evaluate(() => {
    localStorage.removeItem('talent_token');
    localStorage.removeItem('talent_user');
  });
}

Playwright Fixture 集成

web/tests/e2e/fixtures.ts 中添加 fixture:

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 可以继续访问需要认证的页面

选择器策略

重要说明:人才小程序当前没有 data-testid 属性

根据 Playwright MCP 探索结果,人才小程序登录页面 (rencai-auth-ui/src/pages/LoginPage/LoginPage.tsx) 目前没有添加 data-testid 属性。与企业小程序不同:

  • 企业小程序登录页面已在 Story 12.4 中添加 data-testid 属性
  • 人才小程序需要在任务 8 中添加这些属性

当前阶段的选择器策略:

由于页面目前没有 data-testid,在实现 Page Object 时需要:

  1. 优先使用 text 定位(临时方案)

    // 账号输入框 - 使用 placeholder
    this.page.getByPlaceholder('请输入手机号/身份证号/残疾证号')
    
    // 密码输入框 - 使用 placeholder
    this.page.getByPlaceholder('请输入密码')
    
    // 登录按钮 - 使用 text
    this.page.getByRole('button', { name: '登录' })
    
  2. 任务 8 添加 data-testid 后的最终方案

    private readonly selectors = {
    // ✅ 任务 8 完成后:data-testid(使用 talent- 前缀)
    loginPage: '[data-testid="talent-login-page"]',
    identifierInput: '[data-testid="talent-identifier-input"]',
    passwordInput: '[data-testid="talent-password-input"]',
    loginButton: '[data-testid="talent-login-button"]',
    
    // ⚠️ 当前阶段:使用 role/text 选择器(临时方案)
    // identifierInput: 'input[placeholder="请输入手机号/身份证号/残疾证号"]',
    // passwordInput: 'input[placeholder="请输入密码"]',
    // loginButton: 'button:has-text("登录")',
    };
    

标准优先级(任务 8 完成后):

  1. data-testid 属性(最高优先级)
  2. ARIA 属性 + role
  3. 文本内容(最低优先级,避免使用)

TypeScript 类型定义

Page Object 类类型:

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

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

实现完成 (2026-01-14):

  1. TalentMiniPage 类创建

    • 文件位置: web/tests/e2e/pages/mini/talent-mini.page.ts
    • 完整实现了人才小程序 Page Object,包含导航、登录、Token 管理功能
    • 所有公共方法都有完整的 JSDoc 注释
    • TypeScript 类型安全,无 any 类型
  2. 页面导航功能 (AC2)

    • goto() 方法导航到 /talent-mini
    • expectToBeVisible() 验证页面加载
    • removeDevOverlays() 移除开发覆盖层
  3. 登录功能封装 (AC3)

    • fillIdentifier() - 填写身份标识(手机号/身份证号/残疾证号)
    • fillPassword() - 填写密码
    • clickLoginButton() - 点击登录按钮
    • login() - 完整登录流程
    • expectLoginSuccess() - 验证登录成功
    • expectLoginError() - 验证登录失败
  4. Token 管理 (AC4)

    • getToken() - 获取存储的 token (talent_token)
    • setToken() - 设置 token(用于测试前置条件)
    • clearAuth() - 清除认证存储
  5. 主页元素选择器 (AC5)

    • 定义了 userInfo 选择器
    • 主页详细选择器待主页实现后添加
  6. 代码质量 (AC6)

    • 类型检查通过
    • 完整 JSDoc 注释
    • 遵循项目命名约定
  7. Fixtures 更新 (任务 7)

    • web/tests/e2e/fixtures.ts 中添加 TalentMiniFixtures 接口
    • 添加 testTalent fixture 扩展
  8. data-testid 属性添加 (任务 8)

    • 文件: mini-ui-packages/rencai-auth-ui/src/pages/LoginPage/LoginPage.tsx
    • 添加的 testid: talent-login-page, talent-page-title, talent-identifier-input, talent-password-input, talent-login-button

技术要点:

  • 使用 talent- 前缀与企业小程序区分
  • Token Key: talent_token
  • H5 URL: /talent-mini
  • 使用 data-testid 选择器(任务 8 已添加)

File List

新建文件:

  • web/tests/e2e/pages/mini/talent-mini.page.ts

修改文件:

  • web/tests/e2e/pages/mini/index.ts - 添加 TalentMiniPage 导出
  • web/tests/e2e/fixtures.ts - 添加 TalentMiniFixtures 和 testTalent
  • mini-ui-packages/rencai-auth-ui/src/pages/LoginPage/LoginPage.tsx - 添加 data-testid 属性

Change Log

  • 2026-01-14: Story 12.6 创建完成

    • 人才小程序 Page Object 基础结构设计
    • 登录功能封装需求
    • Token 管理策略
    • 状态:ready-for-dev
  • 2026-01-14: Dev Notes 更新 - 添加 Playwright MCP 探索结果

    • 页面 URL 和路由结构 (/talent-mini, 端口 10087)
    • 登录表单元素选择器(当前无 data-testid,需使用 role/text 选择器)
    • Token 存储方式确认 (talent_token in localStorage)
    • 与企业小程序对比(URL、Token Key、首页路径等区别)
    • 源码位置参考(登录页面、路由配置、H5 配置等)
    • 更新选择器策略,添加当前阶段的临时方案说明
    • 更新 Token 管理策略,使用 talent_token key
  • 2026-01-14: Story 12.6 实现完成

    • 创建 TalentMiniPage 类,实现所有导航、登录、Token 管理功能
    • 添加 data-testid 属性到登录页面
    • 更新 fixtures 文件
    • 状态:review