Status: review
作为测试开发者, 我想要创建企业小程序的 Page Object, 以便组织企业小程序相关的页面元素和操作。
Given Playwright E2E 测试框架已配置 When 创建企业小程序 Page Object Then 测试应满足以下要求:
web/tests/e2e/pages/mini/enterprise-mini.page.ts 文件EnterpriseMiniPage 类,继承 Playwright 的 Page 对象模式data-testid 属性(优先级高于文本选择器)Given 企业小程序 Page Object 已创建 When 实现页面导航方法 Then 测试应满足以下要求:
goto() 方法导航到企业小程序 H5 页面 (/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/ 目录(如不存在)enterprise-mini.page.ts 文件EnterpriseMiniPage 类data-testid)[x] 任务 2: 实现页面导航功能 (AC: #2)
goto() 方法(导航到 /mini)expectToBeVisible() 方法[x] 任务 3: 实现登录功能封装 (AC: #3)
fillUsername() 方法(实际命名为 fillPhone 以匹配实际 UI)fillPassword() 方法clickLoginButton() 方法login() 完整登录方法expectLoginSuccess() 验证方法[x] 任务 4: 实现 Token 管理 (AC: #4)
getToken() 方法setToken() 方法clearAuth 方法)[x] 任务 5: 定义主页元素选择器 (AC: #5)
userInfo 选择器)[x] 任务 6: 代码质量验证 (AC: #6)
pnpm typecheck 验证类型检查[x] 任务 7: 创建测试 fixture (AC: #6)
fixtures.ts 文件并添加 enterpriseMiniPage fixtureEpic 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
Story 12.5: 企业小程序登录测试
Story 12.6: 人才小程序 Page Object
Story 12.7: 人才小程序登录测试
Story 12.8: 用户权限验证测试
从已完成的 Story 12.1 中学习到的 Page Object 模式:
UserManagementPage 设计模式:
export class UserManagementPage {
readonly page: Page;
// 选择器定义(使用 data-testid)
private readonly selectors = {
addButton: '[data-testid="add-user-button"]',
usernameInput: '[data-testid="username-input"]',
// ...
};
constructor(page: Page) {
this.page = page;
}
// 导航方法
async goto(): Promise<void> {
await this.page.goto('/admin/users');
}
// 可见性验证
async expectToBeVisible(): Promise<void> {
await expect(this.page.locator(this.selectors.pageContainer)).toBeVisible();
}
}
预期登录流程:
/mini 页面测试用户创建(参考 Story 12.2):
// Story 12.2 创建的企业用户
const employerUserData = {
username: `test_employer_${Date.now()}`,
password: 'password123',
nickname: '测试企业用户',
userType: UserType.EMPLOYER,
companyId: 1, // 使用测试公司
};
存储位置: localStorage 或 sessionStorage(根据实际小程序实现)
Token 操作方法:
// 获取 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);
}
在 playwright.config.ts 或测试文件中添加 fixture:
import { test as base } from '@playwright/test';
import { EnterpriseMiniPage } from './pages/mini/enterprise-mini.page';
type EnterpriseMiniFixtures = {
enterpriseMiniPage: EnterpriseMiniPage;
};
export const test = base.extend<EnterpriseMiniFixtures>({
enterpriseMiniPage: async ({ page }, use) => {
const miniPage = new EnterpriseMiniPage(page);
await use(miniPage);
},
});
新建文件:
web/tests/e2e/pages/mini/enterprise-mini.page.ts相关参考文件:
web/tests/e2e/pages/admin/user-management.page.ts (Story 12.1)web/tests/e2e/utils/timeouts.ts (TIMEOUTS 常量)根据 Epic 12 文档:
优先级(遵循项目标准):
data-testid 属性(最高优先级)示例:
private readonly selectors = {
// ✅ 优先:data-testid
usernameInput: '[data-testid="mini-username-input"]',
passwordInput: '[data-testid="mini-password-input"]',
loginButton: '[data-testid="mini-login-button"]',
// ⚠️ 备选:ARIA + role(如 data-testid 不可用)
// usernameInput: '[aria-label="用户名"]',
// ❌ 避免:纯文本选择器
// usernameInput: 'text=用户名',
};
Page Object 类类型:
export class EnterpriseMiniPage {
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-2-create-employer-user.md (后台创建企业用户测试)Claude (d8d-model)
N/A - 无需调试
实现完成(2026-01-13):
Page Object 基础结构
EnterpriseMiniPage 类,继承 Playwright Page 对象模式data-testid 属性页面导航功能
goto() 方法导航到 /miniexpectToBeVisible() 方法验证页面可见性登录功能封装
fillPhone() 方法(使用手机号而非用户名,匹配实际 UI)fillPassword() 方法clickLoginButton() 方法login() 完整登录方法expectLoginSuccess() 验证方法expectLoginError() 错误验证方法Token 管理
getToken() 方法获取当前存储的 tokensetToken() 方法设置 tokenclearAuth() 方法清除所有认证存储主页元素选择器
userInfo 选择器代码质量
any 类型pnpm typecheck 类型检查测试 Fixture
fixtures.ts 文件定义 enterpriseMiniPage fixture小程序登录页面更新
mini-ui-packages/mini-enterprise-auth-ui/src/pages/login/Login.tsx 中添加 data-testid 属性mini-login-page - 页面容器mini-phone-input - 手机号输入框mini-password-input - 密码输入框mini-login-button - 登录按钮新建的文件:
web/tests/e2e/pages/mini/enterprise-mini.page.ts - 企业小程序 Page Object 文件web/tests/e2e/pages/mini/index.ts - Mini Page Objects 导出文件web/tests/e2e/fixtures.ts - Playwright fixtures 文件修改的文件:
mini-ui-packages/mini-enterprise-auth-ui/src/pages/login/Login.tsx - 添加 data-testid 属性2026-01-13: Story 12.4 创建完成
2026-01-13: Story 12.4 实现完成
EnterpriseMiniPage Page Object 类data-testid 属性