|
@@ -0,0 +1,338 @@
|
|
|
|
|
+# Story 12.5: 企业小程序登录测试
|
|
|
|
|
+
|
|
|
|
|
+Status: ready-for-dev
|
|
|
|
|
+
|
|
|
|
|
+<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
|
|
|
|
+
|
|
|
|
|
+## 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
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 1: 创建测试文件和基础设施 (AC: #7)
|
|
|
|
|
+ - [ ] 1.1 创建 `web/tests/e2e/specs/mini/enterprise-mini-login.spec.ts`
|
|
|
|
|
+ - [ ] 1.2 配置 test fixtures(adminLoginPage 用于准备数据, enterpriseMiniPage)
|
|
|
|
|
+ - [ ] 1.3 添加测试前置条件(准备企业用户数据)
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 2: 实现基本登录成功测试 (AC: #1)
|
|
|
|
|
+ - [ ] 2.1 编写"应该成功登录企业小程序"测试
|
|
|
|
|
+ - [ ] 2.2 验证登录成功后页面变化
|
|
|
|
|
+ - [ ] 2.3 验证 token 存储正确
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 3: 实现登录失败测试 (AC: #2)
|
|
|
|
|
+ - [ ] 3.1 编写"使用不存在的用户名登录失败"测试
|
|
|
|
|
+ - [ ] 3.2 编写"使用错误的密码登录失败"测试
|
|
|
|
|
+ - [ ] 3.3 验证错误提示显示
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 4: 实现表单验证测试 (AC: #3)
|
|
|
|
|
+ - [ ] 4.1 编写"手机号为空时显示错误提示"测试
|
|
|
|
|
+ - [ ] 4.2 编写"密码为空时显示错误提示"测试
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 5: 实现 Token 持久性测试 (AC: #4)
|
|
|
|
|
+ - [ ] 5.1 编写"页面刷新后 token 仍然有效"测试
|
|
|
|
|
+ - [ ] 5.2 编写"使用已存储 token 继续访问"测试
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 6: 实现退出登录测试 (AC: #5)
|
|
|
|
|
+ - [ ] 6.1 编写"成功退出登录"测试
|
|
|
|
|
+ - [ ] 6.2 验证 token 被清除
|
|
|
|
|
+ - [ ] 6.3 验证退出后无法访问需要认证的页面
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 7: 实现测试数据准备和清理策略 (AC: #6)
|
|
|
|
|
+ - [ ] 7.1 添加 beforeAll 钩子准备测试用户
|
|
|
|
|
+ - [ ] 7.2 添加 afterEach 钩子清理测试数据
|
|
|
|
|
+ - [ ] 7.3 使用时间戳确保用户名唯一
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 8: 验证代码质量 (AC: #7)
|
|
|
|
|
+ - [ ] 8.1 运行 `pnpm typecheck` 验证类型检查
|
|
|
|
|
+ - [ ] 8.2 运行测试确保所有测试通过
|
|
|
|
|
+ - [ ] 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<void>
|
|
|
|
|
+async expectToBeVisible(): Promise<void>
|
|
|
|
|
+
|
|
|
|
|
+// 登录方法
|
|
|
|
|
+async login(phone: string, password: string): Promise<void>
|
|
|
|
|
+async fillPhone(phone: string): Promise<void>
|
|
|
|
|
+async fillPassword(password: string): Promise<void>
|
|
|
|
|
+async clickLoginButton(): Promise<void>
|
|
|
|
|
+
|
|
|
|
|
+// 验证方法
|
|
|
|
|
+async expectLoginSuccess(): Promise<void>
|
|
|
|
|
+async expectLoginError(expectedMessage?: string): Promise<void>
|
|
|
|
|
+
|
|
|
|
|
+// Token 管理
|
|
|
|
|
+async getToken(): Promise<string | null>
|
|
|
|
|
+async setToken(token: string): Promise<void>
|
|
|
|
|
+async clearAuth(): Promise<void>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**选择器定义(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<EnterpriseMiniFixtures>({
|
|
|
|
|
+ enterpriseMiniPage: async ({ page }, use) => {
|
|
|
|
|
+ const miniPage = new EnterpriseMiniPage(page);
|
|
|
|
|
+ await use(miniPage);
|
|
|
|
|
+ },
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Dev Agent Record
|
|
|
|
|
+
|
|
|
|
|
+### Agent Model Used
|
|
|
|
|
+
|
|
|
|
|
+Claude (d8d-model)
|
|
|
|
|
+
|
|
|
|
|
+### Debug Log References
|
|
|
|
|
+
|
|
|
|
|
+_N/A - 开发尚未开始_
|
|
|
|
|
+
|
|
|
|
|
+### Completion Notes List
|
|
|
|
|
+
|
|
|
|
|
+_待开发完成后填写_
|
|
|
|
|
+
|
|
|
|
|
+### File List
|
|
|
|
|
+
|
|
|
|
|
+_待开发完成后填写_
|
|
|
|
|
+
|
|
|
|
|
+## Change Log
|
|
|
|
|
+
|
|
|
|
|
+- 2026-01-13: Story 12.5 创建完成
|
|
|
|
|
+ - 企业小程序登录测试需求
|
|
|
|
|
+ - 7 个主要验收标准
|
|
|
|
|
+ - 8 个任务/子任务
|
|
|
|
|
+ - 状态:ready-for-dev
|