|
|
@@ -0,0 +1,446 @@
|
|
|
+# Story 12.7: 人才小程序登录测试
|
|
|
+
|
|
|
+Status: ready-for-dev
|
|
|
+
|
|
|
+<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
|
|
+
|
|
|
+## Story
|
|
|
+
|
|
|
+作为测试开发者,
|
|
|
+我想要编写人才小程序登录的 E2E 测试,
|
|
|
+以便验证人才用户可以成功登录小程序并获得正确的访问权限。
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+
|
|
|
+### AC1: 成功登录测试
|
|
|
+**Given** Story 12.3 创建的人才用户存在
|
|
|
+**When** 人才用户使用正确的凭据登录人才小程序
|
|
|
+**Then** 测试应满足以下要求:
|
|
|
+- 登录成功后跳转到主页或显示用户信息
|
|
|
+- Token 正确存储到 localStorage(key: `talent_token`)
|
|
|
+- 用户信息正确显示(昵称、用户类型等)
|
|
|
+- 登录状态在页面刷新后保持
|
|
|
+
|
|
|
+### AC2: 登录失败测试
|
|
|
+**Given** 人才小程序登录页面可访问
|
|
|
+**When** 用户使用错误的凭据尝试登录
|
|
|
+**Then** 测试应满足以下要求:
|
|
|
+- 显示错误提示信息
|
|
|
+- 不跳转到主页
|
|
|
+- 不存储 token
|
|
|
+- 登录按钮可重新点击
|
|
|
+
|
|
|
+### AC3: 表单验证测试
|
|
|
+**Given** 用户在人才小程序登录页面
|
|
|
+**When** 用户提交未填写必填字段的表单
|
|
|
+**Then** 测试应满足以下要求:
|
|
|
+- 显示验证错误提示
|
|
|
+- 阻止表单提交
|
|
|
+- 高亮错误字段
|
|
|
+
|
|
|
+### AC4: Token 持久性测试
|
|
|
+**Given** 用户已成功登录
|
|
|
+**When** 刷新页面或重新访问小程序
|
|
|
+**Then** 测试应满足以下要求:
|
|
|
+- Token 仍然存在于 localStorage
|
|
|
+- 用户保持登录状态
|
|
|
+- 无需重新登录
|
|
|
+
|
|
|
+### AC5: 登出功能测试
|
|
|
+**Given** 用户已成功登录
|
|
|
+**When** 用户执行登出操作
|
|
|
+**Then** 测试应满足以下要求:
|
|
|
+- Token 从 localStorage 清除
|
|
|
+- 用户信息不再显示
|
|
|
+- 返回到登录页面
|
|
|
+
|
|
|
+### AC6: 测试隔离和清理
|
|
|
+**Given** 多个登录测试需要并行运行
|
|
|
+**When** 执行登录测试套件
|
|
|
+**Then** 测试应满足以下要求:
|
|
|
+- 每个测试使用独立的测试用户
|
|
|
+- 测试后清理认证状态(clearAuth)
|
|
|
+- 测试之间无状态污染
|
|
|
+- 支持并行执行
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+
|
|
|
+- [ ] 任务 1: 创建登录测试文件结构 (AC: #1, #6)
|
|
|
+ - [ ] 1.1 创建 `web/tests/e2e/specs/mini/talent-mini-login.spec.ts` 文件
|
|
|
+ - [ ] 1.2 导入必要的依赖(TalentMiniPage, fixtures)
|
|
|
+ - [ ] 1.3 配置测试套件和基础设置
|
|
|
+
|
|
|
+- [ ] 任务 2: 实现成功登录测试 (AC: #1)
|
|
|
+ - [ ] 2.1 使用 Story 12.3 创建的测试用户
|
|
|
+ - [ ] 2.2 验证登录后页面跳转或用户信息显示
|
|
|
+ - [ ] 2.3 验证 token 正确存储到 localStorage
|
|
|
+ - [ ] 2.4 验证用户信息显示正确
|
|
|
+
|
|
|
+- [ ] 任务 3: 实现登录失败测试 (AC: #2)
|
|
|
+ - [ ] 3.1 测试错误的用户名场景
|
|
|
+ - [ ] 3.2 测试错误的密码场景
|
|
|
+ - [ ] 3.3 测试不存在的用户场景
|
|
|
+ - [ ] 3.4 验证错误提示显示正确
|
|
|
+
|
|
|
+- [ ] 任务 4: 实现表单验证测试 (AC: #3)
|
|
|
+ - [ ] 4.1 测试空用户名提交
|
|
|
+ - [ ] 4.2 测试空密码提交
|
|
|
+ - [ ] 4.3 测试两者都为空提交
|
|
|
+ - [ ] 4.4 验证表单验证消息
|
|
|
+
|
|
|
+- [ ] 任务 5: 实现 Token 持久性测试 (AC: #4)
|
|
|
+ - [ ] 5.1 登录后验证 token 存储
|
|
|
+ - [ ] 5.2 刷新页面验证登录状态保持
|
|
|
+ - [ ] 5.3 重新访问小程序验证无需重新登录
|
|
|
+
|
|
|
+- [ ] 任务 6: 实现登出功能测试 (AC: #5)
|
|
|
+ - [ ] 6.1 测试登出按钮点击(如有)
|
|
|
+ - [ ] 6.2 验证 token 清除
|
|
|
+ - [ ] 6.3 验证返回登录页面
|
|
|
+
|
|
|
+- [ ] 任务 7: 配置测试隔离和清理 (AC: #6)
|
|
|
+ - [ ] 7.1 在 beforeEach 中设置测试用户
|
|
|
+ - [ ] 7.2 在 afterEach 中清理认证状态(clearAuth)
|
|
|
+ - [ ] 7.3 验证测试可以独立运行
|
|
|
+ - [ ] 7.4 验证并行执行无冲突
|
|
|
+
|
|
|
+- [ ] 任务 8: 运行测试并验证稳定性 (AC: #1-#6)
|
|
|
+ - [ ] 8.1 运行所有登录测试
|
|
|
+ - [ ] 8.2 验证所有测试通过
|
|
|
+ - [ ] 8.3 运行稳定性测试(5次连续运行)
|
|
|
+ - [ ] 8.4 记录测试通过率
|
|
|
+
|
|
|
+## 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 12.6: 人才小程序 Page Object ✅ (已完成)
|
|
|
+Story 12.7: 人才小程序登录测试 ← 当前 Story
|
|
|
+Story 12.8: 用户权限验证测试
|
|
|
+```
|
|
|
+
|
|
|
+### Story 12.5(企业小程序登录测试)参考
|
|
|
+
|
|
|
+从企业小程序登录测试中学习到的模式:
|
|
|
+
|
|
|
+**测试文件结构:**
|
|
|
+```typescript
|
|
|
+import { test } from '../../fixtures';
|
|
|
+import { UserManagementPage } from '../../pages/admin/user-management.page';
|
|
|
+import { EnterpriseMiniPage } from '../../pages/mini/enterprise-mini.page';
|
|
|
+
|
|
|
+test.describe('企业小程序登录测试', () => {
|
|
|
+ test.beforeEach(async ({ adminLoginPage, userManagementPage }) => {
|
|
|
+ // 登录后台并创建测试用户
|
|
|
+ });
|
|
|
+
|
|
|
+ test.afterEach(async ({ enterpriseMiniPage }) => {
|
|
|
+ // 清理认证状态
|
|
|
+ await enterpriseMiniPage.clearAuth();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('应该成功登录企业小程序', async ({ enterpriseMiniPage }) => {
|
|
|
+ // 测试登录流程
|
|
|
+ });
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+**测试场景参考:**
|
|
|
+1. 使用后台创建的测试用户登录
|
|
|
+2. 验证 token 存储(localStorage)
|
|
|
+3. 验证用户信息显示
|
|
|
+4. 验证登录失败场景
|
|
|
+5. 验证登出功能
|
|
|
+
|
|
|
+### Story 12.6 关键经验
|
|
|
+
|
|
|
+从已完成的 Story 12.6(人才小程序 Page Object)中学习到的模式:
|
|
|
+
|
|
|
+**Page Object 方法签名:**
|
|
|
+```typescript
|
|
|
+class TalentMiniPage {
|
|
|
+ // 导航到小程序
|
|
|
+ async goto(): Promise<void>
|
|
|
+
|
|
|
+ // 验证页面可见
|
|
|
+ async expectToBeVisible(): Promise<void>
|
|
|
+
|
|
|
+ // 完整登录流程
|
|
|
+ async login(identifier: string, password: string): Promise<void>
|
|
|
+
|
|
|
+ // 填写身份标识(手机号/身份证号/残疾证号)
|
|
|
+ async fillIdentifier(identifier: string): Promise<void>
|
|
|
+
|
|
|
+ // 填写密码
|
|
|
+ async fillPassword(password: string): Promise<void>
|
|
|
+
|
|
|
+ // 点击登录按钮
|
|
|
+ async clickLoginButton(): Promise<void>
|
|
|
+
|
|
|
+ // 验证登录成功
|
|
|
+ async expectLoginSuccess(): Promise<void>
|
|
|
+
|
|
|
+ // 验证登录失败
|
|
|
+ async expectLoginError(): Promise<void>
|
|
|
+
|
|
|
+ // Token 管理
|
|
|
+ async getToken(): Promise<string | null>
|
|
|
+ async setToken(token: string): Promise<void>
|
|
|
+ async clearAuth(): Promise<void>
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**选择器信息(Story 12.6 已添加 data-testid):**
|
|
|
+- 登录页面: `[data-testid="talent-login-page"]`
|
|
|
+- 身份标识输入: `[data-testid="talent-identifier-input"]`
|
|
|
+- 密码输入: `[data-testid="talent-password-input"]`
|
|
|
+- 登录按钮: `[data-testid="talent-login-button"]`
|
|
|
+
|
|
|
+### Token 管理策略
|
|
|
+
|
|
|
+**存储位置:** localStorage (H5 环境)
|
|
|
+
|
|
|
+**Token Key:** `talent_token`
|
|
|
+**User Key:** `talent_user`
|
|
|
+
|
|
|
+**验证 Token 存储:**
|
|
|
+```typescript
|
|
|
+const token = await talentMiniPage.getToken();
|
|
|
+expect(token).toBeTruthy();
|
|
|
+// 验证 token 格式(如 JWT)
|
|
|
+expect(token?.length).toBeGreaterThan(0);
|
|
|
+```
|
|
|
+
|
|
|
+### 测试用户创建(Story 12.3)
|
|
|
+
|
|
|
+**后台创建人才用户的测试数据:**
|
|
|
+```typescript
|
|
|
+const talentUserData = {
|
|
|
+ username: `test_talent_${Date.now()}`,
|
|
|
+ password: 'password123',
|
|
|
+ nickname: '测试人才用户',
|
|
|
+ userType: UserType.TALENT,
|
|
|
+ disabilityPersonId: 1, // 关联残疾人
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+**在测试中创建用户:**
|
|
|
+```typescript
|
|
|
+test.beforeEach(async ({ adminLoginPage, userManagementPage }) => {
|
|
|
+ await adminLoginPage.goto();
|
|
|
+ await adminLoginPage.login('admin', 'admin123');
|
|
|
+
|
|
|
+ const uniqueId = Date.now();
|
|
|
+ const userData = {
|
|
|
+ username: `test_talent_${uniqueId}`,
|
|
|
+ password: 'password123',
|
|
|
+ nickname: `测试人才用户_${uniqueId}`,
|
|
|
+ disabilityPersonId: 1,
|
|
|
+ };
|
|
|
+
|
|
|
+ await userManagementPage.goto();
|
|
|
+ await userManagementPage.createTalentUser(userData);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 小程序登录流程
|
|
|
+
|
|
|
+**预期登录流程:**
|
|
|
+1. 导航到 `/talent-mini` 页面
|
|
|
+2. 填写身份标识(手机号/身份证号/残疾证号)
|
|
|
+3. 填写密码
|
|
|
+4. 点击登录按钮
|
|
|
+5. 验证登录成功(跳转到主页或显示用户信息)
|
|
|
+6. 验证 token 存储
|
|
|
+
|
|
|
+**登录成功验证:**
|
|
|
+- 检查页面 URL 变化或主页元素出现
|
|
|
+- 检查 localStorage 中的 `talent_token`
|
|
|
+- 检查用户信息显示(如适用)
|
|
|
+
|
|
|
+### 测试文件组织
|
|
|
+
|
|
|
+**测试文件位置:** `web/tests/e2e/specs/mini/talent-mini-login.spec.ts`
|
|
|
+
|
|
|
+**测试文件结构:**
|
|
|
+```typescript
|
|
|
+import { testTalent } from '../../fixtures';
|
|
|
+import { TalentMiniPage } from '../../pages/mini/talent-mini.page';
|
|
|
+import { UserManagementPage } from '../../pages/admin/user-management.page';
|
|
|
+import { AdminLoginPage } from '../../pages/admin/admin-login.page';
|
|
|
+
|
|
|
+testTalent.describe('人才小程序登录测试', () => {
|
|
|
+ let testUserData: {
|
|
|
+ username: string;
|
|
|
+ password: string;
|
|
|
+ nickname: string;
|
|
|
+ };
|
|
|
+
|
|
|
+ testTalent.beforeEach(async ({ adminLoginPage, userManagementPage }) => {
|
|
|
+ // 登录后台并创建测试用户
|
|
|
+ await adminLoginPage.goto();
|
|
|
+ await adminLoginPage.login('admin', 'admin123');
|
|
|
+
|
|
|
+ const uniqueId = Date.now();
|
|
|
+ testUserData = {
|
|
|
+ username: `test_talent_${uniqueId}`,
|
|
|
+ password: 'password123',
|
|
|
+ nickname: `测试人才用户_${uniqueId}`,
|
|
|
+ };
|
|
|
+
|
|
|
+ await userManagementPage.goto();
|
|
|
+ await userManagementPage.createTalentUser({
|
|
|
+ username: testUserData.username,
|
|
|
+ password: testUserData.password,
|
|
|
+ nickname: testUserData.nickname,
|
|
|
+ disabilityPersonId: 1,
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ testTalent.afterEach(async ({ talentMiniPage }) => {
|
|
|
+ // 清理认证状态
|
|
|
+ await talentMiniPage.clearAuth();
|
|
|
+ });
|
|
|
+
|
|
|
+ testTalent('应该成功登录人才小程序', async ({ talentMiniPage }) => {
|
|
|
+ await talentMiniPage.goto();
|
|
|
+ await talentMiniPage.login(testUserData.username, testUserData.password);
|
|
|
+ await talentMiniPage.expectLoginSuccess();
|
|
|
+
|
|
|
+ // 验证 token 存储
|
|
|
+ const token = await talentMiniPage.getToken();
|
|
|
+ expect(token).toBeTruthy();
|
|
|
+ });
|
|
|
+
|
|
|
+ // 更多测试...
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 测试隔离和并行执行
|
|
|
+
|
|
|
+**关键原则:**
|
|
|
+1. 每个测试使用唯一的用户名(时间戳)
|
|
|
+2. 测试后清理认证状态(clearAuth)
|
|
|
+3. 避免依赖全局状态
|
|
|
+4. 支持并行执行
|
|
|
+
|
|
|
+### 测试超时配置
|
|
|
+
|
|
|
+**Playwright 配置超时:** 60秒(单个测试默认超时)
|
|
|
+
|
|
|
+**TIMEOUTS 常量:**
|
|
|
+```typescript
|
|
|
+import { TIMEOUTS } from '../../utils/timeouts';
|
|
|
+```
|
|
|
+
|
|
|
+### 测试数据管理
|
|
|
+
|
|
|
+**测试用户创建策略:**
|
|
|
+- 在 beforeEach 中创建唯一用户(使用时间戳)
|
|
|
+- 测试后可选择清理(或使用唯一的测试用户)
|
|
|
+- 避免硬编码用户名导致冲突
|
|
|
+
|
|
|
+### 企业小程序 vs 人才小程序对比
|
|
|
+
|
|
|
+| 特性 | 企业小程序 | 人才小程序 |
|
|
|
+|------|-----------|-----------|
|
|
|
+| H5 URL | `/mini` | `/talent-mini` |
|
|
|
+| Token Key | `enterprise_token` | `talent_token` |
|
|
|
+| User Key | `enterprise_user` | `talent_user` |
|
|
|
+| 输入字段 | 手机号 | 手机号/身份证号/残疾证号 |
|
|
|
+| Page Object | EnterpriseMiniPage | TalentMiniPage |
|
|
|
+| Fixture | testEnterprise | testTalent |
|
|
|
+
|
|
|
+### Playwright 运行命令
|
|
|
+
|
|
|
+**运行测试:**
|
|
|
+```bash
|
|
|
+cd web
|
|
|
+pnpm test:e2e:chromium talent-mini-login
|
|
|
+```
|
|
|
+
|
|
|
+**快速失败模式(调试):**
|
|
|
+```bash
|
|
|
+timeout 60 pnpm test:e2e:chromium talent-mini-login
|
|
|
+```
|
|
|
+
|
|
|
+**查看测试结果:**
|
|
|
+- 测试报告: `web/test-results/`
|
|
|
+- 失败截图: `web/test-results/*/`
|
|
|
+
|
|
|
+### 项目结构
|
|
|
+
|
|
|
+**新建文件:**
|
|
|
+- `web/tests/e2e/specs/mini/talent-mini-login.spec.ts`
|
|
|
+
|
|
|
+**相关参考文件:**
|
|
|
+- `web/tests/e2e/specs/mini/enterprise-mini-login.spec.ts` (Story 12.5) - 企业小程序登录测试
|
|
|
+- `web/tests/e2e/pages/mini/talent-mini.page.ts` (Story 12.6) - 人才小程序 Page Object
|
|
|
+- `web/tests/e2e/pages/admin/user-management.page.ts` (Story 12.1) - 用户管理 Page Object
|
|
|
+- `web/tests/e2e/specs/admin/create-talent-user.spec.ts` (Story 12.3) - 创建人才用户测试
|
|
|
+
|
|
|
+### 小程序只读特性
|
|
|
+
|
|
|
+根据 Epic 12 文档:
|
|
|
+- 小程序只读,无写操作
|
|
|
+- 登录测试主要关注认证和访问权限
|
|
|
+- 不需要测试创建、编辑、删除等写操作
|
|
|
+
|
|
|
+### 参考文档
|
|
|
+
|
|
|
+**架构文档:**
|
|
|
+- `_bmad-output/planning-artifacts/architecture.md`
|
|
|
+- `docs/standards/e2e-radix-testing.md` (Radix UI 测试标准)
|
|
|
+
|
|
|
+**相关 Story 文档:**
|
|
|
+- `12-3-create-talent-user.md` (后台创建人才用户测试)
|
|
|
+- `12-5-enterprise-mini-login.md` (企业小程序登录测试)
|
|
|
+- `12-6-talent-mini-page-object.md` (人才小程序 Page Object)
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+Claude (d8d-model)
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+_N/A - 待开发过程中记录_
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+_待开发过程中记录_
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+**新建文件:**
|
|
|
+- `web/tests/e2e/specs/mini/talent-mini-login.spec.ts`
|
|
|
+
|
|
|
+**参考文件:**
|
|
|
+- `web/tests/e2e/specs/mini/enterprise-mini-login.spec.ts` (参考测试结构)
|
|
|
+- `web/tests/e2e/pages/mini/talent-mini.page.ts` (Story 12.6 创建)
|
|
|
+- `web/tests/e2e/pages/admin/user-management.page.ts` (Story 12.1 创建)
|
|
|
+
|
|
|
+## Change Log
|
|
|
+
|
|
|
+- 2026-01-14: Story 12.7 创建完成
|
|
|
+ - 人才小程序登录测试需求
|
|
|
+ - 登录成功、失败、表单验证、Token 持久性、登出功能测试
|
|
|
+ - 测试隔离和清理策略
|
|
|
+ - 状态:ready-for-dev
|