Kaynağa Gözat

feat(story-12.7): 创建 Story 12.7 - 人才小程序登录测试

创建了人才小程序登录 E2E 测试的 Story 文档,包含 5 个验收标准:
- AC1: 成功登录测试
- AC2: 登录失败测试
- AC3: 表单验证测试
- AC4: Token 持久性测试
- AC5: 登出功能测试

更新 Sprint 状态:Story 12.7 状态设置为 ready-for-dev,Epic 12 进度更新为 5/8 Stories done。

Co-Authored-By: Claude <noreply@anthropic.com>
yourname 4 gün önce
ebeveyn
işleme
dc250c8918

+ 446 - 0
_bmad-output/implementation-artifacts/12-7-talent-mini-login.md

@@ -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

+ 2 - 2
_bmad-output/implementation-artifacts/sprint-status.yaml

@@ -197,7 +197,7 @@ development_status:
   12-4-enterprise-mini-page-object: done  # 企业小程序 Page Object ✅ 完成 (2026-01-13)
   12-5-enterprise-mini-login: in-progress      # 企业小程序登录测试 🚀 开发中 (2026-01-13)
   12-6-talent-mini-page-object: done          # 人才小程序 Page Object ✅ 完成 (2026-01-14) - 两轮代码审查问题全部修复
-  12-7-talent-mini-login: backlog          # 人才小程序登录测试
+  12-7-talent-mini-login: ready-for-dev     # 人才小程序登录测试 ✅ Story 创建完成 (2026-01-14)
   12-8-user-permission-test: backlog       # 用户权限验证(小程序无写操作)
   epic-12-retrospective: optional
 
@@ -231,7 +231,7 @@ development_status:
 #   - Epic 10: 订单管理 E2E 测试 ✅ (14/14 Stories done) - 稳定性 97.9%
 #
 # Epic D: 用户管理与小程序登录测试 🔄 进行中
-#   - Epic 12: 用户管理与小程序登录测试 (4/8 Stories done)
+#   - Epic 12: 用户管理与小程序登录测试 (5/8 Stories done)
 #
 # Epic E: 跨端数据同步测试 🆕 新增
 #   - Epic 13: 跨端数据同步测试 (0/5 Stories)