Status: review
作为测试开发者, 我想要创建人才小程序的 Page Object, 以便组织人才小程序相关的页面元素和操作。
Given Playwright E2E 测试框架已配置 When 创建人才小程序 Page Object Then 测试应满足以下要求:
web/tests/e2e/pages/mini/talent-mini.page.ts 文件TalentMiniPage 类,继承 Playwright 的 Page 对象模式data-testid 属性(优先级高于文本选择器)Given 人才小程序 Page Object 已创建 When 实现页面导航方法 Then 测试应满足以下要求:
goto() 方法导航到人才小程序 H5 页面 (/talent-mini)expectToBeVisible() 方法验证页面可见性Given 人才小程序 Page Object 已创建 When 实现登录相关方法 Then 测试应满足以下要求:
login(username, password) 方法执行登录操作fillUsername(username)fillPassword(password)clickLoginButton()expectLoginSuccess()Given 小程序登录后需要存储 token 用于后续操作 When 实现 token 管理方法 Then 测试应满足以下要求:
getToken() 方法获取当前存储的 tokensetToken(token) 方法设置 token(用于测试前置条件)Given 人才小程序登录后进入主页 When 定义主页元素选择器 Then 测试应满足以下要求:
data-testid 属性Given 遵循项目测试规范 When 编写 Page Object 代码 Then 代码应符合以下标准:
any 类型pnpm typecheck 类型检查[x] 任务 1: 创建 Page Object 基础结构 (AC: #1, #6)
web/tests/e2e/pages/mini/ 目录存在talent-mini.page.ts 文件TalentMiniPage 类data-testid)[x] 任务 2: 实现页面导航功能 (AC: #2)
goto() 方法(导航到 /talent-mini)expectToBeVisible() 方法[x] 任务 3: 实现登录功能封装 (AC: #3)
fillUsername() 方法(使用手机号或用户名)fillPassword() 方法clickLoginButton() 方法login() 完整登录方法expectLoginSuccess() 验证方法expectLoginError() 错误验证方法[x] 任务 4: 实现 Token 管理 (AC: #4)
getToken() 方法setToken() 方法clearAuth() 清除认证方法[x] 任务 5: 定义主页元素选择器 (AC: #5)
[x] 任务 6: 代码质量验证 (AC: #6)
pnpm typecheck 验证类型检查[x] 任务 7: 更新 fixtures 文件 (AC: #6)
web/tests/e2e/fixtures.ts 中添加 talentMiniPage fixture[x] 任务 8: 添加 data-testid 属性 (AC: #1)
data-testid 属性Epic 12 目标: 为用户管理和小程序登录编写 E2E 测试,解锁小程序端的测试能力
小程序技术要点(来自 Epic 12 文档):
http://localhost:8080/minihttp://localhost:8080/talent-miniEpic 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(企业小程序 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-inputTaro 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 });
}
预期登录流程:
/talent-mini 页面测试用户创建(参考 Story 12.3):
// Story 12.3 创建的人才用户
const talentUserData = {
username: `test_talent_${Date.now()}`,
password: 'password123',
nickname: '测试人才用户',
userType: UserType.TALENT,
disabilityPersonId: 1, // 关联残疾人
};
页面 URL 和路由结构:
http://localhost:8080/talent-mini (生产环境)http://localhost:10087/talent-minimini-talent/config/index.ts
publicPath: '/talent-mini/'router.basename: '/talent-mini'mini-talent/src/app.config.ts
pages/index/indexpages/login/index登录表单元素选择器(当前无 data-testid):
mini-ui-packages/rencai-auth-ui/src/pages/LoginPage/LoginPage.tsxdata-testid 属性,需要使用 role/text 选择器表单结构:
- 导航栏标题: "人才登录" (Navbar组件)
- 页面标题: "人才服务平台" (text)
- 副标题: "欢迎回来" (text)
- 账号输入标签: "手机号/身份证号/残疾证号" (text)
- 账号输入框: placeholder="请输入手机号/身份证号/残疾证号" (Input)
- 密码输入标签: "密码" (text)
- 密码输入框: placeholder="请输入密码" (Input, password模式)
- 登录按钮: "登录" (Button)
- 忘记密码链接: "忘记密码?" (text)
Token 存储方式(通过源码确认):
talent_token (在 rencai-auth-ui/src/hooks/useAuth.tsx 第22行)talent_user (同上)Taro.setStorageSync(TOKEN_KEY, token)与企业小程序对比:
| 特性 | 企业小程序 | 人才小程序 |
|---|---|---|
| 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.tsxmini-talent/src/pages/login/index.tsxmini-talent/src/app.config.tsmini-talent/config/index.tsmini-ui-packages/mini-enterprise-auth-ui/src/pages/login/Login.tsxmini-ui-packages/rencai-auth-ui/src/hooks/useAuth.tsx存储位置: 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');
});
}
在 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 Objectweb/tests/e2e/pages/admin/user-management.page.ts (Story 12.1) - 用户管理 Page Objectweb/tests/e2e/utils/timeouts.ts - TIMEOUTS 常量根据 Epic 12 文档:
E2E 测试计划:
主页元素选择器状态:
原因说明: 主页元素(工作列表、导航菜单、用户信息)的选择器需要在实际主页实现时才能确定对应的 testid。当前 Story 12.6 专注于 Page Object 的基础结构设计和登录功能,主页相关元素的选择器将在主页实现时同步添加,并在 Story 12.7 的 E2E 测试中验证。
Token 持久性验证: Token 在页面刷新后的持久性验证将在 Story 12.7 的 E2E 测试中实现,包括:
重要说明:人才小程序当前没有 data-testid 属性
根据 Playwright MCP 探索结果,人才小程序登录页面 (rencai-auth-ui/src/pages/LoginPage/LoginPage.tsx) 目前没有添加 data-testid 属性。与企业小程序不同:
data-testid 属性当前阶段的选择器策略:
由于页面目前没有 data-testid,在实现 Page Object 时需要:
优先使用 text 定位(临时方案):
// 账号输入框 - 使用 placeholder
this.page.getByPlaceholder('请输入手机号/身份证号/残疾证号')
// 密码输入框 - 使用 placeholder
this.page.getByPlaceholder('请输入密码')
// 登录按钮 - 使用 text
this.page.getByRole('button', { name: '登录' })
任务 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 完成后):
data-testid 属性(最高优先级)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.mddocs/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)Claude (d8d-model)
N/A - 无需调试
实现完成 (2026-01-14):
TalentMiniPage 类创建
web/tests/e2e/pages/mini/talent-mini.page.tsany 类型页面导航功能 (AC2)
goto() 方法导航到 /talent-miniexpectToBeVisible() 验证页面加载removeDevOverlays() 移除开发覆盖层登录功能封装 (AC3)
fillIdentifier() - 填写身份标识(手机号/身份证号/残疾证号)fillPassword() - 填写密码clickLoginButton() - 点击登录按钮login() - 完整登录流程expectLoginSuccess() - 验证登录成功expectLoginError() - 验证登录失败Token 管理 (AC4)
getToken() - 获取存储的 token (talent_token)setToken() - 设置 token(用于测试前置条件)clearAuth() - 清除认证存储主页元素选择器 (AC5)
userInfo 选择器代码质量 (AC6)
Fixtures 更新 (任务 7)
web/tests/e2e/fixtures.ts 中添加 TalentMiniFixtures 接口testTalent fixture 扩展data-testid 属性添加 (任务 8)
mini-ui-packages/rencai-auth-ui/src/pages/LoginPage/LoginPage.tsxtalent-login-page, talent-page-title, talent-identifier-input, talent-password-input, talent-login-button技术要点:
talent- 前缀与企业小程序区分talent_token/talent-mini新建文件:
web/tests/e2e/pages/mini/talent-mini.page.ts修改文件:
web/tests/e2e/pages/mini/index.ts - 添加 TalentMiniPage 导出web/tests/e2e/fixtures.ts - 添加 TalentMiniFixtures 和 testTalentmini-ui-packages/rencai-auth-ui/src/pages/LoginPage/LoginPage.tsx - 添加 data-testid 属性2026-01-14: Story 12.6 创建完成
2026-01-14: Dev Notes 更新 - 添加 Playwright MCP 探索结果
/talent-mini, 端口 10087)talent_token in localStorage)talent_token key2026-01-14: Story 12.6 实现完成