2
0

12-4-enterprise-mini-page-object.md 12 KB

Story 12.4: 企业小程序 Page Object

Status: review

Story

作为测试开发者, 我想要创建企业小程序的 Page Object, 以便组织企业小程序相关的页面元素和操作。

Acceptance Criteria

AC1: Page Object 基础结构

Given Playwright E2E 测试框架已配置 When 创建企业小程序 Page Object Then 测试应满足以下要求:

  • 创建 web/tests/e2e/pages/mini/enterprise-mini.page.ts 文件
  • 定义 EnterpriseMiniPage 类,继承 Playwright 的 Page 对象模式
  • 实现基础选择器定义(登录表单、主页元素等)
  • 所有选择器使用 data-testid 属性(优先级高于文本选择器)
  • 遵循项目 Page Object 设计模式

AC2: 小程序页面导航

Given 企业小程序 Page Object 已创建 When 实现页面导航方法 Then 测试应满足以下要求:

  • 实现 goto() 方法导航到企业小程序 H5 页面 (/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 创建 enterprise-mini.page.ts 文件
    • 1.3 定义 EnterpriseMiniPage
    • 1.4 定义基础选择器(使用 data-testid
  • [x] 任务 2: 实现页面导航功能 (AC: #2)

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

    • 3.1 实现 fillUsername() 方法(实际命名为 fillPhone 以匹配实际 UI)
    • 3.2 实现 fillPassword() 方法
    • 3.3 实现 clickLoginButton() 方法
    • 3.4 实现 login() 完整登录方法
    • 3.5 实现 expectLoginSuccess() 验证方法
  • [x] 任务 4: 实现 Token 管理 (AC: #4)

    • 4.1 实现 getToken() 方法
    • 4.2 实现 setToken() 方法
    • 4.3 使用 localStorage 存储 token(额外添加 clearAuth 方法)
  • [x] 任务 5: 定义主页元素选择器 (AC: #5)

    • 5.1 定义订单列表选择器(基础结构已定义,待主页实现后完善)
    • 5.2 定义导航菜单选择器(基础结构已定义,待主页实现后完善)
    • 5.3 定义用户信息选择器(已定义 userInfo 选择器)
  • [x] 任务 6: 代码质量验证 (AC: #6)

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

    • 7.1 创建 fixtures.ts 文件并添加 enterpriseMiniPage fixture
    • 7.2 验证 fixture 正确初始化(类型检查通过)

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
Story 12.5: 企业小程序登录测试
Story 12.6: 人才小程序 Page Object
Story 12.7: 人才小程序登录测试
Story 12.8: 用户权限验证测试

Story 12.1 关键经验

从已完成的 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();
  }
}

小程序登录流程

预期登录流程:

  1. 导航到 /mini 页面
  2. 填写用户名(在测试中创建的企业用户)
  3. 填写密码
  4. 点击登录按钮
  5. 验证登录成功(跳转到主页或显示用户信息)
  6. 存储 token 用于后续请求

测试用户创建(参考 Story 12.2):

// Story 12.2 创建的企业用户
const employerUserData = {
  username: `test_employer_${Date.now()}`,
  password: 'password123',
  nickname: '测试企业用户',
  userType: UserType.EMPLOYER,
  companyId: 1,  // 使用测试公司
};

Token 管理策略

存储位置: 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 Fixture 集成

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 文档:

  • 小程序只读,无写操作
  • 这意味着 Page Object 不需要包含创建、编辑、删除等操作方法
  • 主要关注登录、查看、验证等只读操作

选择器策略

优先级(遵循项目标准):

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

示例:

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=用户名',
};

TypeScript 类型定义

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.md
  • docs/standards/e2e-radix-testing.md (Radix UI 测试标准)

相关 Story 文档:

  • 12-1-user-page-object.md (用户管理 Page Object)
  • 12-2-create-employer-user.md (后台创建企业用户测试)

Dev Agent Record

Agent Model Used

Claude (d8d-model)

Debug Log References

N/A - 无需调试

Completion Notes List

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

  1. Page Object 基础结构

    • 创建了 EnterpriseMiniPage 类,继承 Playwright Page 对象模式
    • 所有选择器使用 data-testid 属性
    • 遵循项目命名约定(类名 PascalCase,方法名 camelCase)
  2. 页面导航功能

    • 实现 goto() 方法导航到 /mini
    • 实现 expectToBeVisible() 方法验证页面可见性
    • 添加页面加载验证逻辑
  3. 登录功能封装

    • 实现 fillPhone() 方法(使用手机号而非用户名,匹配实际 UI)
    • 实现 fillPassword() 方法
    • 实现 clickLoginButton() 方法
    • 实现 login() 完整登录方法
    • 实现 expectLoginSuccess() 验证方法
    • 实现 expectLoginError() 错误验证方法
  4. Token 管理

    • 实现 getToken() 方法获取当前存储的 token
    • 实现 setToken() 方法设置 token
    • 实现 clearAuth() 方法清除所有认证存储
    • 支持 localStorage 和 sessionStorage
  5. 主页元素选择器

    • 定义 userInfo 选择器
    • 预留订单列表和导航菜单选择器扩展点
  6. 代码质量

    • TypeScript 类型安全,无 any 类型
    • 所有公共方法有完整的 JSDoc 注释
    • 使用 TIMEOUTS 常量定义超时
    • 通过 pnpm typecheck 类型检查
  7. 测试 Fixture

    • 创建 fixtures.ts 文件定义 enterpriseMiniPage fixture
    • 类型检查通过
  8. 小程序登录页面更新

    • 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 - 登录按钮

File List

新建的文件:

  • 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 属性

Change Log

  • 2026-01-13: Story 12.4 创建完成

    • 企业小程序 Page Object 基础结构设计
    • 登录功能封装需求
    • Token 管理策略
    • 状态:ready-for-dev
  • 2026-01-13: Story 12.4 实现完成

    • 创建 EnterpriseMiniPage Page Object 类
    • 实现页面导航、登录、Token 管理功能
    • 在小程序登录页面添加 data-testid 属性
    • 创建 Playwright fixtures 文件
    • 所有任务已完成,状态更新为 review