# Story 12.5: 企业小程序登录测试 Status: in-progress ## Story 作为测试开发者, 我想要编写企业小程序登录的 E2E 测试, 以便验证企业用户可以通过小程序成功登录,并解锁小程序端的测试能力。 ## Acceptance Criteria ### AC1: 基本登录成功测试 **Given** 企业小程序 Page Object (Story 12.4) 已完成 **When** 编写企业用户登录成功的测试用例 **Then** 测试应验证以下功能: - 导航到企业小程序 H5 页面 (`/mini`) - 使用在 Story 12.2 中创建的企业用户凭据登录 - 填写手机号(用户名)和密码 - 点击登录按钮 - 验证登录成功(页面跳转或用户信息显示) - 验证 token 正确存储在 localStorage 或 sessionStorage ### AC2: 登录失败测试 **Given** 企业小程序登录页面已加载 **When** 使用错误的凭据尝试登录 **Then** 测试应验证以下场景: - 使用不存在的用户名登录,显示错误提示 - 使用错误的密码登录,显示错误提示 - 验证错误提示内容正确(如"用户名或密码错误") - 验证未存储 token ### AC3: 表单验证测试 **Given** 企业小程序登录表单已显示 **When** 在不同表单验证场景下尝试提交 **Then** 测试应验证以下场景: - 手机号为空时提交,显示错误提示 - 密码为空时提交,显示错误提示 - 验证表单验证错误提示清晰可见 ### AC4: Token 持久性测试 **Given** 企业用户已成功登录 **When** 刷新页面或重新打开页面 **Then** 测试应验证以下功能: - 验证 token 在页面刷新后仍然有效 - 验证使用已存储 token 可以继续访问需要认证的页面 - 验证用户信息仍然正确显示 ### AC5: 退出登录测试 **Given** 企业用户已成功登录 **When** 执行退出登录操作 **Then** 测试应验证以下功能: - 点击退出登录按钮 - 验证 token 被清除 - 验证返回登录页面 - 验证退出后无法访问需要认证的页面 ### AC6: 测试数据准备和清理 **Given** 测试运行环境中需要企业用户数据 **When** 执行测试 **Then** 测试应遵循以下策略: - 在测试前准备企业用户数据(使用 Story 12.2 的模式) - 每个测试后清理测试数据(避免数据冲突) - 使用时间戳确保用户名唯一 ### AC7: 代码质量标准 **Given** 遵循项目测试规范 **When** 编写测试代码 **Then** 代码应符合以下标准: - 使用 TIMEOUTS 常量定义超时 - 使用 data-testid 选择器(优先级高于文本选择器) - 测试文件命名:`enterprise-mini-login.spec.ts` - 完整的测试描述和注释 - TypeScript 类型安全 - 通过 `pnpm typecheck` 类型检查 ## Tasks / Subtasks - [x] 任务 1: 创建测试文件和基础设施 (AC: #7) ✅ - [x] 1.1 创建 `web/tests/e2e/specs/mini/enterprise-mini-login.spec.ts` ✅ - [x] 1.2 配置 test fixtures(enterpriseMiniPage) ✅ - [x] 1.3 添加测试前置条件 ✅ - [ ] 任务 2: 实现基本登录成功测试 (AC: #1) ⏸️ 需要预创建用户 - [ ] 2.1 编写"应该成功登录企业小程序"测试 (SKIPPED - 需要独立测试套件) - [ ] 2.2 验证登录成功后页面变化 (SKIPPED - 需要独立测试套件) - [ ] 2.3 验证 token 存储正确 (SKIPPED - 需要独立测试套件) - [x] 任务 3: 实现登录失败测试 (AC: #2) ✅ - [x] 3.1 编写"使用不存在的用户名登录失败"测试 ✅ - [x] 3.2 编写"使用错误的密码登录失败"测试 ✅ - [x] 3.3 验证错误提示显示 ✅ - [x] 任务 4: 实现表单验证测试 (AC: #3) ✅ - [x] 4.1 编写"手机号为空时显示错误提示"测试 ✅ - [x] 4.2 编写"密码为空时显示错误提示"测试 ✅ - [ ] 任务 5: 实现 Token 持久性测试 (AC: #4) ⏸️ 需要预创建用户 - [ ] 5.1 编写"页面刷新后 token 仍然有效"测试 (SKIPPED - 需要独立测试套件) - [ ] 5.2 编写"使用已存储 token 继续访问"测试 (SKIPPED - 需要独立测试套件) - [ ] 任务 6: 实现退出登录测试 (AC: #5) ⏸️ 需要预创建用户 - [ ] 6.1 编写"成功退出登录"测试 (SKIPPED - 需要独立测试套件) - [ ] 6.2 验证 token 被清除 (SKIPPED - 需要独立测试套件) - [ ] 6.3 验证退出后无法访问需要认证的页面 (SKIPPED - 需要独立测试套件) - [ ] 任务 7: 实现测试数据准备和清理策略 (AC: #6) ⏸️ 部分完成 - [ ] 7.1 添加 beforeAll 钩子准备测试用户 (NOT NEEDED - 使用有效手机号格式) - [ ] 7.2 添加 afterEach 钩子清理测试数据 (NOT NEEDED) - [ ] 7.3 使用时间戳确保用户名唯一 (NOT NEEDED) - [x] 任务 8: 验证代码质量 (AC: #7) ✅ - [x] 8.1 运行 `pnpm typecheck` 验证类型检查 ✅ - [x] 8.2 运行测试确保所有测试通过 ✅ (6/6 测试通过) - [x] 8.3 验证选择器使用 data-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 Story 12.6: 人才小程序 Page Object Story 12.7: 人才小程序登录测试 Story 12.8: 用户权限验证测试 ``` ### Story 12.4 关键经验 从已完成的 Story 12.4 中学习到的 Page Object 使用模式: **EnterpriseMiniPage 可用方法:** ```typescript // 导航方法 async goto(): Promise async expectToBeVisible(): Promise // 登录方法 async login(phone: string, password: string): Promise async fillPhone(phone: string): Promise async fillPassword(password: string): Promise async clickLoginButton(): Promise // 验证方法 async expectLoginSuccess(): Promise async expectLoginError(expectedMessage?: string): Promise // Token 管理 async getToken(): Promise async setToken(token: string): Promise async clearAuth(): Promise ``` **选择器定义(Story 12.4 已添加 data-testid):** ```typescript private readonly selectors = { loginPage: '[data-testid="mini-login-page"]', phoneInput: '[data-testid="mini-phone-input"]', passwordInput: '[data-testid="mini-password-input"]', loginButton: '[data-testid="mini-login-button"]', pageTitle: '[data-testid="mini-page-title"]', userInfo: '[data-testid="mini-user-info"]', // ... }; ``` ### Story 12.2 关键经验 从已完成的 Story 12.2 中学习到的测试数据准备模式: **企业用户创建模式:** ```typescript // 使用 UserManagementPage 在测试前创建企业用户 const employerUserData = { username: `test_employer_${Date.now()}`, password: 'password123', nickname: '测试企业用户', userType: UserType.EMPLOYER, companyId: 1, // 使用测试公司 }; ``` **测试清理策略:** ```typescript test.afterEach(async ({ userManagementPage }) => { // 清理测试数据 await userManagementPage.deleteUser(username); }); ``` ### 小程序登录流程 **预期登录流程:** 1. 导航到 `/mini` 页面 2. 填写手机号(在 Story 12.2 中创建的企业用户的用户名) 3. 填写密码 4. 点击登录按钮 5. 验证登录成功(跳转到主页或显示用户信息) 6. 验证 token 存储在 localStorage 或 sessionStorage **Token 验证方法:** ```typescript // 验证 token 存储正确 const token = await enterpriseMiniPage.getToken(); expect(token).toBeTruthy(); // 验证 token 在页面刷新后仍然有效 await page.reload(); const tokenAfterReload = await enterpriseMiniPage.getToken(); expect(tokenAfterReload).toBe(token); ``` ### 项目结构 **新建文件:** - `web/tests/e2e/specs/mini/enterprise-mini-login.spec.ts` **相关参考文件:** - `web/tests/e2e/pages/mini/enterprise-mini.page.ts` (Story 12.4) - `web/tests/e2e/pages/admin/user-management.page.ts` (Story 12.1) - `web/tests/e2e/specs/admin/user-create-employer.spec.ts` (Story 12.2) ### 选择器策略 **优先级(遵循项目标准):** 1. `data-testid` 属性(最高优先级) 2. ARIA 属性 + role 3. 文本内容(最低优先级,避免使用) **Story 12.4 已添加的 data-testid:** - `mini-login-page` - 页面容器 - `mini-phone-input` - 手机号输入框 - `mini-password-input` - 密码输入框 - `mini-login-button` - 登录按钮 - `mini-page-title` - 页面标题(Navbar 组件) - `mini-user-info` - 用户信息显示 ### TypeScript 类型定义 **测试数据类型:** ```typescript interface EmployerUserCredentials { username: string; // 手机号 password: string; nickname: string; userType: 'EMPLOYER'; companyId: number; } ``` ### 测试超时配置 **使用 TIMEOUTS 常量:** ```typescript import { TIMEOUTS } from '../../utils/timeouts'; await expect(page.locator(selectors.userInfo)).toBeVisible({ timeout: TIMEOUTS.default, }); ``` ### 参考文档 **架构文档:** - `_bmad-output/planning-artifacts/architecture.md` - `docs/standards/e2e-radix-testing.md` (Radix UI 测试标准) **相关 Story 文档:** - `12-4-enterprise-mini-page-object.md` (企业小程序 Page Object) - `12-2-create-employer-user.md` (后台创建企业用户测试) ### 小程序只读特性 根据 Epic 12 文档: - 小程序只读,无写操作 - 登录测试主要关注认证和 token 管理 - 无需测试创建、编辑、删除等操作 ### Playwright Fixture 集成 **在 `playwright.config.ts` 或测试文件中:** ```typescript import { test as base } from '@playwright/test'; import { EnterpriseMiniPage } from '../../pages/mini/enterprise-mini.page'; type EnterpriseMiniFixtures = { enterpriseMiniPage: EnterpriseMiniPage; }; export const test = base.extend({ enterpriseMiniPage: async ({ page }, use) => { const miniPage = new EnterpriseMiniPage(page); await use(miniPage); }, }); ``` ## Dev Agent Record ### Agent Model Used Claude (d8d-model) ### Debug Log References 测试开发过程中的主要问题和解决方案: 1. **Taro Input 组件交互问题** - 问题:Playwright 的 `.fill()` 方法不支持 Taro 的自定义元素 (``) - 解决:改用 `.click()` + `.type()` 组合,并使用 `Control+A` 全选已有内容 2. **Page Object 选择器严格模式冲突** - 问题:使用 `.or()` 选择器时,多个匹配元素导致严格模式冲突 - 解决:简化为单一 `data-testid` 选择器 3. **登录失败测试的表单验证** - 问题:表单验证阻止无效手机号提交到后端 - 解决:使用有效格式的手机号(11位,1开头)触发后端验证 4. **expect 未定义错误** - 问题:Page Object 文件缺少 `expect` 导入 - 解决:从 `@playwright/test` 导入 `expect` ### Completion Notes List **实现摘要:** - ✅ 6 个测试通过(表单验证 + 登录失败) - ⏸️ 8 个测试跳过(需要预创建用户:登录成功、Token 持久性、退出登录) **已完成的验收标准:** - AC2: 登录失败测试 ✅ - AC3: 表单验证测试 ✅ - AC7: 代码质量标准 ✅ **部分完成的验收标准:** - AC1: 基本登录成功测试 ⏸️ (需要预创建用户) - AC4: Token 持久性测试 ⏸️ (需要预创建用户) - AC5: 退出登录测试 ⏸️ (需要预创建用户) - AC6: 测试数据准备和清理 ⏸️ (部分完成) **技术挑战:** 1. **Fixture 共享问题**:adminLoginPage 和 enterpriseMiniPage 共享同一个 `page` 实例 - 解决方案:将需要用户创建的测试移至独立测试套件,使用专用 page context 2. **Taro 组件兼容性**:Taro Input 组件不是标准 HTML 元素 - 解决方案:使用 `.type()` 代替 `.fill()` **后续工作建议:** 1. 创建独立的测试套件处理需要预创建用户的测试(AC1, AC4, AC5) 2. 在独立套件中使用 beforeAll/afterAll 钩子管理测试数据 3. 确保测试套件之间不共享 page context ### File List **新建文件:** - `web/tests/e2e/specs/mini/enterprise-mini-login.spec.ts` - 企业小程序登录测试文件 **修改文件:** - `web/tests/e2e/utils/test-setup.ts` - 添加 `enterpriseMiniPage` fixture - `web/tests/e2e/pages/mini/enterprise-mini.page.ts` - 修复 Taro Input 组件交互方法 ## Change Log - 2026-01-13: Story 12.5 开发进行中 - ✅ 创建测试文件和配置 fixtures - ✅ 实现表单验证测试 (AC3) - 3/3 测试通过 - ✅ 实现登录失败测试 (AC2) - 3/3 测试通过 - ✅ 验证代码质量 (AC7) - 类型检查通过 - ⏸️ 跳过需要预创建用户的测试 (AC1, AC4, AC5) - 状态:in-progress (6/14 测试通过,8 个需要预创建用户的测试已跳过)