# 基于角色的用户模拟测试套件实现计划

> **面向 AI 代理的工作者：** 必需子技能：使用 superpowers:subagent-driven-development（推荐）或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框（`- [ ]`）语法来跟踪进度。

**目标：** 实现一个基于角色的用户模拟测试套件，替换现有E2E测试，达到真实场景验收标准。

**架构：** 采用混合测试模式（业务流程 + 权限验证），使用Token注入提升执行效率，通过角色定义系统实现权限边界验证，配合测试数据管理器确保测试隔离性。

**技术栈：** TypeScript + Playwright + H2 Database (测试环境) + Spring Boot BCrypt

---

## 文件结构

### 后端文件（密码配置修复）

| 文件路径 | 职责 | 操作 |
|---------|------|------|
| `novalon-manage-api/manage-app/src/main/resources/data-h2.sql` | 主应用H2测试数据 | 修改：统一密码配置 |
| `novalon-manage-api/manage-app/src/test/resources/data-h2.sql` | 测试环境H2数据 | 保持不变（已正确） |
| `novalon-manage-api/manage-sys/src/test/java/cn/novalon/manage/sys/util/PasswordHashGenerator.java` | 密码Hash生成工具 | 修改：添加验证逻辑 |

### 前端文件（测试框架）

| 文件路径 | 职责 | 操作 |
|---------|------|------|
| `novalon-manage-web/e2e/role-based-tests/roles/base.role.ts` | 角色定义基类 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/roles/admin.role.ts` | 管理员角色定义 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/roles/user.role.ts` | 普通用户角色定义 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/roles/test.role.ts` | 测试用户角色定义 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/roles/role-factory.ts` | 角色工厂 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/shared/auth-helper.ts` | 认证辅助工具 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/shared/role-auth-manager.ts` | Token管理器 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/shared/test-data-manager.ts` | 测试数据管理器 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/shared/permission-helper.ts` | 权限验证工具 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/scenarios/authentication/login-flow.spec.ts` | 登录流程测试 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/scenarios/authentication/logout-flow.spec.ts` | 登出流程测试 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/scenarios/user-management/admin-creates-user.spec.ts` | 管理员创建用户测试 | 创建 |
| `novalon-manage-web/e2e/role-based-tests/scenarios/user-management/permission-boundary.spec.ts` | 权限边界验证测试 | 创建 |
| `novalon-manage-web/playwright.config.ts` | Playwright配置 | 修改：添加角色测试项目 |
| `novalon-manage-web/.env.test` | 测试环境变量 | 创建 |
| `novalon-manage-web/package.json` | 项目配置 | 修改：添加测试脚本 |

---

## 任务清单

### 任务 1：修复H2数据库密码不一致问题（P0）

**目标：** 统一主应用和测试环境的H2数据库密码配置，确保所有环境使用相同的密码和BCrypt版本。

**文件：**
- 修改：`novalon-manage-api/manage-app/src/main/resources/data-h2.sql`
- 修改：`novalon-manage-api/manage-sys/src/test/java/cn/novalon/manage/sys/util/PasswordHashGenerator.java`

---

- [ ] **步骤 1：验证BCrypt版本兼容性**

编写测试验证Spring Security BCryptPasswordEncoder能否正确验证`$2a$`和`$2b$`版本的hash。

```java
// novalon-manage-api/manage-sys/src/test/java/cn/novalon/manage/sys/util/PasswordHashGenerator.java

@Test
public void verifyBCryptVersions() {
    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12);
    
    String password = "Test@123";
    
    // $2a$ hash (测试环境当前使用)
    String hash2a = "$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C";
    boolean matches2a = passwordEncoder.matches(password, hash2a);
    System.out.println("========================================");
    System.out.println("验证 $2a$ hash:");
    System.out.println("密码: " + password);
    System.out.println("Hash: " + hash2a);
    System.out.println("验证结果: " + matches2a);
    System.out.println("========================================");
    assertTrue(matches2a, "$2a$ hash验证失败");
    
    // $2b$ hash (主应用当前使用)
    String hash2b = "$2b$12$SFefXlGRFMA0fvxIufpWPuIAl0OPLgRDoCZPThCvjpiJGPYS8yNYy";
    boolean matches2b = passwordEncoder.matches("admin123", hash2b);
    System.out.println("验证 $2b$ hash:");
    System.out.println("密码: admin123");
    System.out.println("Hash: " + hash2b);
    System.out.println("验证结果: " + matches2b);
    System.out.println("========================================");
    assertTrue(matches2b, "$2b$ hash验证失败");
}
```

---

- [ ] **步骤 2：运行测试验证BCrypt兼容性**

运行：`cd novalon-manage-api && ./gradlew :manage-sys:test --tests PasswordHashGenerator.verifyBCryptVersions`

预期：PASS，输出显示两个版本的hash都能正确验证

---

- [ ] **步骤 3：更新主应用data-h2.sql密码配置**

将主应用的H2测试数据密码统一为`Test@123`，使用`$2a$`版本的hash。

```sql
-- novalon-manage-api/manage-app/src/main/resources/data-h2.sql

-- 插入测试用户
-- BCrypt哈希值对应明文密码: Test@123
INSERT INTO sys_user (id, username, password, email, phone, nickname, status, create_by, update_by) 
VALUES 
(1, 'admin', '$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C', 'admin@novalon.com', '13800138000', '超级管理员', 1, 'system', 'system'),
(2, 'testadmin', '$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C', 'testadmin@novalon.com', '13800138001', '测试管理员', 1, 'system', 'system'),
(3, 'normaluser', '$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C', 'normaluser@novalon.com', '13800138002', '普通用户', 1, 'system', 'system'),
(4, 'guestuser', '$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C', 'guestuser@novalon.com', '13800138003', '访客用户', 1, 'system', 'system'),
(5, 'disableduser', '$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C', 'disableduser@novalon.com', '13800138004', '禁用用户', 0, 'system', 'system'),
(10, 'e2e_test_user', '$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C', 'e2e@test.com', '13900139000', 'E2E测试用户', 1, 'system', 'system');
```

---

- [ ] **步骤 4：验证密码配置一致性**

编写测试验证主应用和测试环境的密码配置一致。

```java
// novalon-manage-api/manage-sys/src/test/java/cn/novalon/manage/sys/util/PasswordHashGenerator.java

@Test
public void verifyPasswordConsistency() {
    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12);
    
    String password = "Test@123";
    String hash = "$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C";
    
    boolean matches = passwordEncoder.matches(password, hash);
    
    System.out.println("========================================");
    System.out.println("密码一致性验证:");
    System.out.println("明文密码: " + password);
    System.out.println("Hash: " + hash);
    System.out.println("验证结果: " + matches);
    System.out.println("========================================");
    
    assertTrue(matches, "密码配置不一致");
}
```

---

- [ ] **步骤 5：运行密码一致性测试**

运行：`cd novalon-manage-api && ./gradlew :manage-sys:test --tests PasswordHashGenerator.verifyPasswordConsistency`

预期：PASS

---

- [ ] **步骤 6：Commit密码配置修复**

```bash
cd novalon-manage-api
git add manage-app/src/main/resources/data-h2.sql
git add manage-sys/src/test/java/cn/novalon/manage/sys/util/PasswordHashGenerator.java
git commit -m "fix: 统一H2数据库密码配置为Test@123

- 统一主应用和测试环境的密码配置
- 使用BCrypt $2a$版本hash
- 添加密码验证测试确保一致性

影响范围：
- manage-app/src/main/resources/data-h2.sql
- manage-sys/src/test/java/cn/novalon/manage/sys/util/PasswordHashGenerator.java"
```

---

### 任务 2：创建测试框架目录结构

**目标：** 建立清晰的测试框架目录结构，为后续开发奠定基础。

**文件：**
- 创建目录：`novalon-manage-web/e2e/role-based-tests/`
- 创建目录：`novalon-manage-web/e2e/role-based-tests/roles/`
- 创建目录：`novalon-manage-web/e2e/role-based-tests/scenarios/`
- 创建目录：`novalon-manage-web/e2e/role-based-tests/scenarios/authentication/`
- 创建目录：`novalon-manage-web/e2e/role-based-tests/scenarios/user-management/`
- 创建目录：`novalon-manage-web/e2e/role-based-tests/shared/`

---

- [ ] **步骤 1：创建目录结构**

```bash
cd novalon-manage-web
mkdir -p e2e/role-based-tests/roles
mkdir -p e2e/role-based-tests/scenarios/authentication
mkdir -p e2e/role-based-tests/scenarios/user-management
mkdir -p e2e/role-based-tests/shared
```

---

- [ ] **步骤 2：验证目录结构**

运行：`tree novalon-manage-web/e2e/role-based-tests -L 2`

预期输出：
```
e2e/role-based-tests/
├── roles/
├── scenarios/
│   ├── authentication/
│   └── user-management/
└── shared/
```

---

- [ ] **步骤 3：Commit目录结构**

```bash
cd novalon-manage-web
git add e2e/role-based-tests/
git commit -m "chore: 创建基于角色的测试框架目录结构

创建目录：
- roles/ - 角色定义
- scenarios/ - 业务场景测试
  - authentication/ - 认证场景
  - user-management/ - 用户管理场景
- shared/ - 共享工具"
```

---

### 任务 3：实现角色定义系统

**目标：** 实现角色定义基类和具体角色定义，为测试提供角色信息。

**文件：**
- 创建：`novalon-manage-web/e2e/role-based-tests/roles/base.role.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/roles/admin.role.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/roles/user.role.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/roles/test.role.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/roles/role-factory.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/roles/__tests__/role-factory.test.ts`

---

- [ ] **步骤 1：编写角色定义基类测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/__tests__/base.role.test.ts

import { describe, it, expect } from '@playwright/test';
import type { RoleDefinition } from '../base.role';

describe('RoleDefinition', () => {
  it('should define required role properties', () => {
    const role: RoleDefinition = {
      name: 'test',
      displayName: '测试角色',
      credentials: {
        username: 'testuser',
        password: 'Test@123'
      },
      permissions: ['test:read', 'test:write'],
      cannotAccess: ['/admin'],
      expectedBehaviors: {
        canCreate: ['test'],
        canRead: ['test'],
        canUpdate: ['test'],
        canDelete: []
      }
    };

    expect(role.name).toBe('test');
    expect(role.displayName).toBe('测试角色');
    expect(role.credentials.username).toBe('testuser');
    expect(role.credentials.password).toBe('Test@123');
    expect(role.permissions).toHaveLength(2);
    expect(role.cannotAccess).toHaveLength(1);
  });
});
```

---

- [ ] **步骤 2：运行测试验证失败**

运行：`cd novalon-manage-web && pnpm test roles/__tests__/base.role.test.ts`

预期：FAIL，报错 "Cannot find module '../base.role'"

---

- [ ] **步骤 3：实现角色定义基类**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/base.role.ts

export interface RoleDefinition {
  name: string;
  displayName: string;
  credentials: {
    username: string;
    password: string;
  };
  permissions: string[];
  cannotAccess: string[];
  expectedBehaviors: {
    canCreate: string[];
    canRead: string[];
    canUpdate: string[];
    canDelete: string[];
  };
}
```

---

- [ ] **步骤 4：运行测试验证通过**

运行：`cd novalon-manage-web && pnpm test roles/__tests__/base.role.test.ts`

预期：PASS

---

- [ ] **步骤 5：编写管理员角色定义测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/__tests__/admin.role.test.ts

import { describe, it, expect } from '@playwright/test';
import { AdminRole } from '../admin.role';

describe('AdminRole', () => {
  it('should have admin credentials', () => {
    expect(AdminRole.name).toBe('admin');
    expect(AdminRole.displayName).toBe('超级管理员');
    expect(AdminRole.credentials.username).toBe('admin');
    expect(AdminRole.credentials.password).toBe('Test@123');
  });

  it('should have all permissions', () => {
    expect(AdminRole.permissions).toContain('user:*');
    expect(AdminRole.permissions).toContain('role:*');
    expect(AdminRole.permissions).toContain('menu:*');
    expect(AdminRole.cannotAccess).toHaveLength(0);
  });

  it('should be able to create all resources', () => {
    expect(AdminRole.expectedBehaviors.canCreate).toContain('user');
    expect(AdminRole.expectedBehaviors.canCreate).toContain('role');
    expect(AdminRole.expectedBehaviors.canCreate).toContain('menu');
  });
});
```

---

- [ ] **步骤 6：运行测试验证失败**

运行：`cd novalon-manage-web && pnpm test roles/__tests__/admin.role.test.ts`

预期：FAIL，报错 "Cannot find module '../admin.role'"

---

- [ ] **步骤 7：实现管理员角色定义**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/admin.role.ts

import type { RoleDefinition } from './base.role';

export const AdminRole: RoleDefinition = {
  name: 'admin',
  displayName: '超级管理员',
  credentials: {
    username: 'admin',
    password: 'Test@123'
  },
  permissions: [
    'user:*',
    'role:*',
    'menu:*',
    'config:*',
    'log:read',
    'dict:*'
  ],
  cannotAccess: [],
  expectedBehaviors: {
    canCreate: ['user', 'role', 'menu', 'config', 'dict'],
    canRead: ['user', 'role', 'menu', 'config', 'dict', 'log'],
    canUpdate: ['user', 'role', 'menu', 'config', 'dict'],
    canDelete: ['user', 'role', 'menu', 'config', 'dict']
  }
};
```

---

- [ ] **步骤 8：运行测试验证通过**

运行：`cd novalon-manage-web && pnpm test roles/__tests__/admin.role.test.ts`

预期：PASS

---

- [ ] **步骤 9：实现普通用户角色定义**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/user.role.ts

import type { RoleDefinition } from './base.role';

export const UserRole: RoleDefinition = {
  name: 'user',
  displayName: '普通用户',
  credentials: {
    username: 'normaluser',
    password: 'Test@123'
  },
  permissions: [
    'user:read:self',
    'user:update:self'
  ],
  cannotAccess: [
    '/user-management',
    '/role-management',
    '/menu-management',
    '/system-config'
  ],
  expectedBehaviors: {
    canCreate: [],
    canRead: ['self'],
    canUpdate: ['self'],
    canDelete: []
  }
};
```

---

- [ ] **步骤 10：实现测试用户角色定义**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/test.role.ts

import type { RoleDefinition } from './base.role';

export const TestRole: RoleDefinition = {
  name: 'test',
  displayName: '测试用户',
  credentials: {
    username: 'e2e_test_user',
    password: 'Test@123'
  },
  permissions: [
    'test:read',
    'test:write'
  ],
  cannotAccess: [
    '/user-management',
    '/role-management'
  ],
  expectedBehaviors: {
    canCreate: ['test'],
    canRead: ['test'],
    canUpdate: ['test'],
    canDelete: []
  }
};
```

---

- [ ] **步骤 11：编写角色工厂测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/__tests__/role-factory.test.ts

import { describe, it, expect } from '@playwright/test';
import { RoleFactory } from '../role-factory';

describe('RoleFactory', () => {
  it('should get admin role', () => {
    const role = RoleFactory.getRole('admin');
    expect(role.name).toBe('admin');
    expect(role.credentials.username).toBe('admin');
  });

  it('should get user role', () => {
    const role = RoleFactory.getRole('user');
    expect(role.name).toBe('user');
    expect(role.credentials.username).toBe('normaluser');
  });

  it('should throw error for unknown role', () => {
    expect(() => RoleFactory.getRole('unknown')).toThrow("Role 'unknown' not found");
  });

  it('should get all roles', () => {
    const roles = RoleFactory.getAllRoles();
    expect(roles).toHaveLength(3);
    expect(roles.map(r => r.name)).toContain('admin');
    expect(roles.map(r => r.name)).toContain('user');
    expect(roles.map(r => r.name)).toContain('test');
  });
});
```

---

- [ ] **步骤 12：运行测试验证失败**

运行：`cd novalon-manage-web && pnpm test roles/__tests__/role-factory.test.ts`

预期：FAIL，报错 "Cannot find module '../role-factory'"

---

- [ ] **步骤 13：实现角色工厂**

```typescript
// novalon-manage-web/e2e/role-based-tests/roles/role-factory.ts

import type { RoleDefinition } from './base.role';
import { AdminRole } from './admin.role';
import { UserRole } from './user.role';
import { TestRole } from './test.role';

export class RoleFactory {
  private static roles: Map<string, RoleDefinition> = new Map([
    ['admin', AdminRole],
    ['user', UserRole],
    ['test', TestRole]
  ]);

  static getRole(roleName: string): RoleDefinition {
    const role = this.roles.get(roleName);
    if (!role) {
      throw new Error(`Role '${roleName}' not found`);
    }
    return role;
  }

  static getAllRoles(): RoleDefinition[] {
    return Array.from(this.roles.values());
  }
}
```

---

- [ ] **步骤 14：运行测试验证通过**

运行：`cd novalon-manage-web && pnpm test roles/__tests__/role-factory.test.ts`

预期：PASS

---

- [ ] **步骤 15：Commit角色定义系统**

```bash
cd novalon-manage-web
git add e2e/role-based-tests/roles/
git commit -m "feat: 实现角色定义系统

- 创建角色定义基类 RoleDefinition
- 实现管理员角色 AdminRole
- 实现普通用户角色 UserRole
- 实现测试用户角色 TestRole
- 实现角色工厂 RoleFactory
- 添加完整的单元测试

所有角色统一使用密码: Test@123"
```

---

### 任务 4：实现认证辅助工具

**目标：** 实现Token管理器和认证辅助类，支持Token注入和真实登录两种模式。

**文件：**
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/role-auth-manager.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/auth-helper.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/__tests__/role-auth-manager.test.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/__tests__/auth-helper.test.ts`

---

- [ ] **步骤 1：编写Token管理器测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/__tests__/role-auth-manager.test.ts

import { describe, it, expect, beforeEach } from '@playwright/test';
import { RoleAuthManager } from '../role-auth-manager';

describe('RoleAuthManager', () => {
  beforeEach(() => {
    RoleAuthManager.clearCache();
  });

  it('should get role token', async () => {
    const token = await RoleAuthManager.getRoleToken('admin');
    expect(token).toBeDefined();
    expect(typeof token).toBe('string');
    expect(token.length).toBeGreaterThan(0);
  });

  it('should cache token', async () => {
    const token1 = await RoleAuthManager.getRoleToken('admin');
    const token2 = await RoleAuthManager.getRoleToken('admin');
    expect(token1).toBe(token2);
  });

  it('should throw error for unknown role', async () => {
    await expect(RoleAuthManager.getRoleToken('unknown')).rejects.toThrow();
  });
});
```

---

- [ ] **步骤 2：运行测试验证失败**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/role-auth-manager.test.ts`

预期：FAIL，报错 "Cannot find module '../role-auth-manager'"

---

- [ ] **步骤 3：实现Token管理器**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/role-auth-manager.ts

import { RoleFactory } from '../roles/role-factory';

interface TokenCache {
  token: string;
  expiresAt: number;
}

export class RoleAuthManager {
  private static tokenCache: Map<string, TokenCache> = new Map();
  private static readonly API_BASE_URL = process.env.VITE_API_BASE_URL || 'http://localhost:8084';
  private static readonly TOKEN_EXPIRY_MS = 86400000; // 24小时

  static async getRoleToken(roleName: string): Promise<string> {
    const cached = this.tokenCache.get(roleName);
    
    if (cached && cached.expiresAt > Date.now() + 300000) {
      return cached.token;
    }

    const role = RoleFactory.getRole(roleName);
    const token = await this.fetchTokenFromAPI(role.credentials);
    
    return token;
  }

  private static async fetchTokenFromAPI(credentials: { 
    username: string; 
    password: string 
  }): Promise<string> {
    const response = await fetch(`${this.API_BASE_URL}/api/auth/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(credentials)
    });

    if (!response.ok) {
      throw new Error(`Failed to fetch token: ${response.statusText}`);
    }

    const data = await response.json();
    
    this.tokenCache.set(credentials.username, {
      token: data.token || data.access_token,
      expiresAt: Date.now() + this.TOKEN_EXPIRY_MS
    });

    return data.token || data.access_token;
  }

  static clearCache(): void {
    this.tokenCache.clear();
  }
}
```

---

- [ ] **步骤 4：运行测试验证通过**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/role-auth-manager.test.ts`

预期：PASS（需要后端服务运行）

---

- [ ] **步骤 5：编写认证辅助类测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/__tests__/auth-helper.test.ts

import { test, expect } from '@playwright/test';
import { AuthHelper } from '../auth-helper';

test.describe('AuthHelper', () => {
  test('should login as admin with token injection', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
    
    const token = await page.evaluate(() => localStorage.getItem('token'));
    expect(token).toBeDefined();
    expect(token!.length).toBeGreaterThan(0);
  });

  test('should login as admin with full login flow', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', true);
    
    await expect(page).toHaveURL(/\/(dashboard|\/)/);
  });

  test('should logout successfully', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
    await AuthHelper.logout(page);
    
    const token = await page.evaluate(() => localStorage.getItem('token'));
    expect(token).toBeNull();
  });
});
```

---

- [ ] **步骤 6：运行测试验证失败**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/auth-helper.test.ts`

预期：FAIL，报错 "Cannot find module '../auth-helper'"

---

- [ ] **步骤 7：实现认证辅助类**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/auth-helper.ts

import type { Page } from '@playwright/test';
import { RoleFactory } from '../roles/role-factory';
import { RoleAuthManager } from './role-auth-manager';

export class AuthHelper {
  static async loginAsRole(
    page: Page, 
    roleName: string, 
    useFullLogin: boolean = false
  ): Promise<void> {
    if (useFullLogin) {
      await this.performFullLogin(page, roleName);
    } else {
      try {
        await this.injectToken(page, roleName);
      } catch (error) {
        console.warn('Token注入失败，降级使用真实登录');
        await this.performFullLogin(page, roleName);
      }
    }
  }

  private static async injectToken(page: Page, roleName: string): Promise<void> {
    const token = await RoleAuthManager.getRoleToken(roleName);
    
    await page.goto('/');
    await page.evaluate((token) => {
      localStorage.setItem('token', token);
      localStorage.setItem('access_token', token);
    }, token);
    
    await page.reload();
  }

  private static async performFullLogin(page: Page, roleName: string): Promise<void> {
    const role = RoleFactory.getRole(roleName);
    
    await page.goto('/login');
    await page.fill('[name="username"]', role.credentials.username);
    await page.fill('[name="password"]', role.credentials.password);
    await page.click('[type="submit"]');
    
    await page.waitForURL(/\/(dashboard|\/)/);
  }

  static async logout(page: Page): Promise<void> {
    await page.evaluate(() => {
      localStorage.removeItem('token');
      localStorage.removeItem('access_token');
    });
    
    await page.goto('/login');
  }

  static async isLoggedIn(page: Page): Promise<boolean> {
    const token = await page.evaluate(() => localStorage.getItem('token'));
    return token !== null && token.length > 0;
  }
}
```

---

- [ ] **步骤 8：运行测试验证通过**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/auth-helper.test.ts`

预期：PASS（需要后端服务运行）

---

- [ ] **步骤 9：Commit认证辅助工具**

```bash
cd novalon-manage-web
git add e2e/role-based-tests/shared/
git commit -m "feat: 实现认证辅助工具

- 实现 RoleAuthManager Token管理器
  - Token缓存和自动刷新
  - 从API获取真实Token
- 实现 AuthHelper 认证辅助类
  - 支持Token注入模式
  - 支持真实登录模式
  - 自动降级机制
- 添加完整的单元测试"
```

---

### 任务 5：实现测试数据管理器

**目标：** 实现测试数据生成和管理工具，确保测试数据隔离和清理。

**文件：**
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/test-data-manager.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/__tests__/test-data-manager.test.ts`

---

- [ ] **步骤 1：编写测试数据管理器测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/__tests__/test-data-manager.test.ts

import { describe, it, expect, beforeEach } from '@playwright/test';
import { TestDataManager } from '../test-data-manager';

describe('TestDataManager', () => {
  beforeEach(() => {
    TestDataManager.reset();
  });

  it('should generate test user data', () => {
    const user = TestDataManager.generateTestUser();
    
    expect(user.username).toMatch(/^test_[a-f0-9]{8}$/);
    expect(user.password).toBe('Test@123');
    expect(user.email).toMatch(/^test_[a-f0-9]{8}@example\.com$/);
    expect(user.phone).toMatch(/^138\d{8}$/);
  });

  it('should generate test user with overrides', () => {
    const user = TestDataManager.generateTestUser({
      username: 'custom_user',
      nickname: '自定义用户'
    });
    
    expect(user.username).toBe('custom_user');
    expect(user.nickname).toBe('自定义用户');
    expect(user.password).toBe('Test@123');
  });

  it('should track created user', () => {
    TestDataManager.trackUser('test_user_1');
    TestDataManager.trackUser('test_user_2');
    
    const trackedUsers = TestDataManager.getTrackedUsers();
    expect(trackedUsers).toContain('test_user_1');
    expect(trackedUsers).toContain('test_user_2');
  });
});
```

---

- [ ] **步骤 2：运行测试验证失败**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/test-data-manager.test.ts`

预期：FAIL，报错 "Cannot find module '../test-data-manager'"

---

- [ ] **步骤 3：实现测试数据管理器**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/test-data-manager.ts

import { v4 as uuidv4 } from 'uuid';

export interface TestUserData {
  username: string;
  password: string;
  email: string;
  phone: string;
  nickname: string;
}

export class TestDataManager {
  private static createdUsers: Set<string> = new Set();

  static generateTestUser(overrides?: Partial<TestUserData>): TestUserData {
    const uuid = uuidv4().substring(0, 8);
    return {
      username: `test_${uuid}`,
      password: 'Test@123',
      email: `test_${uuid}@example.com`,
      phone: `138${uuid.substring(0, 8)}`,
      nickname: `测试用户_${Date.now()}`,
      ...overrides
    };
  }

  static trackUser(username: string): void {
    this.createdUsers.add(username);
  }

  static getTrackedUsers(): string[] {
    return Array.from(this.createdUsers);
  }

  static reset(): void {
    this.createdUsers.clear();
  }
}
```

---

- [ ] **步骤 4：运行测试验证通过**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/test-data-manager.test.ts`

预期：PASS

---

- [ ] **步骤 5：Commit测试数据管理器**

```bash
cd novalon-manage-web
git add e2e/role-based-tests/shared/test-data-manager.ts
git add e2e/role-based-tests/shared/__tests__/test-data-manager.test.ts
git commit -m "feat: 实现测试数据管理器

- 实现 generateTestUser 生成测试用户数据
- 实现 trackUser 跟踪创建的用户
- 实现 reset 清理测试数据
- 添加完整的单元测试"
```

---

### 任务 6：实现权限验证工具

**目标：** 实现权限边界验证工具，验证用户能否访问特定资源。

**文件：**
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/permission-helper.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/shared/__tests__/permission-helper.test.ts`

---

- [ ] **步骤 1：编写权限验证工具测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/__tests__/permission-helper.test.ts

import { test, expect } from '@playwright/test';
import { AuthHelper } from '../auth-helper';
import { PermissionHelper } from '../permission-helper';

test.describe('PermissionHelper', () => {
  test('should verify admin can access user management', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
    
    await PermissionHelper.verifyCanAccess(page, '/user-management');
    
    await expect(page).toHaveURL(/user-management/);
  });

  test('should verify user cannot access user management', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'user', false);
    
    await PermissionHelper.verifyCannotAccess(page, '/user-management');
  });

  test('should verify admin can see user management menu', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
    
    await PermissionHelper.verifyCanSeeMenu(page, '用户管理');
  });

  test('should verify user cannot see user management menu', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'user', false);
    
    await PermissionHelper.verifyCannotSeeMenu(page, '用户管理');
  });
});
```

---

- [ ] **步骤 2：运行测试验证失败**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/permission-helper.test.ts`

预期：FAIL，报错 "Cannot find module '../permission-helper'"

---

- [ ] **步骤 3：实现权限验证工具**

```typescript
// novalon-manage-web/e2e/role-based-tests/shared/permission-helper.ts

import type { Page } from '@playwright/test';
import { expect } from '@playwright/test';

export class PermissionHelper {
  static async verifyCanAccess(page: Page, path: string): Promise<void> {
    await page.goto(path);
    
    await expect(page).not.toHaveURL(/.*login/);
    
    const noPermissionElement = page.locator('.no-permission, .forbidden');
    await expect(noPermissionElement).not.toBeVisible();
  }

  static async verifyCannotAccess(page: Page, path: string): Promise<void> {
    await page.goto(path);
    
    const isLoginPage = page.url().includes('login');
    const hasNoPermission = await page.locator('.no-permission').isVisible();
    const hasForbidden = await page.locator('text=/403|Forbidden/').isVisible();
    
    expect(isLoginPage || hasNoPermission || hasForbidden).toBeTruthy();
  }

  static async verifyCanSeeMenu(page: Page, menuText: string): Promise<void> {
    const menuElement = page.locator(`.menu-item:has-text("${menuText}")`);
    await expect(menuElement).toBeVisible();
  }

  static async verifyCannotSeeMenu(page: Page, menuText: string): Promise<void> {
    const menuElement = page.locator(`.menu-item:has-text("${menuText}")`);
    await expect(menuElement).not.toBeVisible();
  }
}
```

---

- [ ] **步骤 4：运行测试验证通过**

运行：`cd novalon-manage-web && pnpm test shared/__tests__/permission-helper.test.ts`

预期：PASS（需要后端服务运行）

---

- [ ] **步骤 5：Commit权限验证工具**

```bash
cd novalon-manage-web
git add e2e/role-based-tests/shared/permission-helper.ts
git add e2e/role-based-tests/shared/__tests__/permission-helper.test.ts
git commit -m "feat: 实现权限验证工具

- 实现 verifyCanAccess 验证用户可以访问
- 实现 verifyCannotAccess 验证用户不能访问
- 实现 verifyCanSeeMenu 验证用户可以看到菜单
- 实现 verifyCannotSeeMenu 验证用户看不到菜单
- 添加完整的集成测试"
```

---

### 任务 7：配置环境变量和Playwright配置

**目标：** 配置测试环境变量和Playwright项目配置，支持角色测试。

**文件：**
- 创建：`novalon-manage-web/.env.test`
- 修改：`novalon-manage-web/playwright.config.ts`
- 修改：`novalon-manage-web/package.json`

---

- [ ] **步骤 1：创建测试环境变量文件**

```bash
# novalon-manage-web/.env.test

VITE_API_BASE_URL=http://localhost:8084
BASE_URL=http://localhost:5173
TEST_TIMEOUT=30000
TEST_RETRIES=2

# 测试用户密码（统一使用Test@123）
ADMIN_USERNAME=admin
ADMIN_PASSWORD=Test@123
USER_USERNAME=normaluser
USER_PASSWORD=Test@123
TEST_USERNAME=e2e_test_user
TEST_PASSWORD=Test@123
```

---

- [ ] **步骤 2：更新Playwright配置**

```typescript
// novalon-manage-web/playwright.config.ts

import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';

dotenv.config({ path: '.env.test' });

export default defineConfig({
  testDir: './e2e',
  testMatch: [
    '**/role-based-tests/**/*.spec.ts',
    '**/legacy-tests/**/*.spec.ts'
  ],
  timeout: parseInt(process.env.TEST_TIMEOUT || '30000'),
  retries: parseInt(process.env.TEST_RETRIES || '2'),
  workers: process.env.CI ? 1 : undefined,
  reporter: [
    ['list'],
    ['html', { outputFolder: 'test-results/html' }],
    ['junit', { outputFile: 'test-results/junit.xml' }]
  ],
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:5173',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    {
      name: 'admin-tests',
      testMatch: /admin.*\.spec\.ts/,
      use: { 
        ...devices['Desktop Chrome'],
        viewport: { width: 1920, height: 1080 }
      },
    },
    {
      name: 'user-tests',
      testMatch: /user.*\.spec\.ts/,
      use: { 
        ...devices['Desktop Chrome'],
        viewport: { width: 1366, height: 768 }
      },
    },
    {
      name: 'auth-tests',
      testMatch: /authentication.*\.spec\.ts/,
      use: { 
        ...devices['Desktop Chrome'],
      },
    },
    {
      name: 'permission-tests',
      testMatch: /permission.*\.spec\.ts/,
      use: { 
        ...devices['Desktop Chrome'],
      },
    }
  ],
  webServer: {
    command: 'pnpm dev',
    url: 'http://localhost:5173',
    reuseExistingServer: !process.env.CI,
  },
});
```

---

- [ ] **步骤 3：更新package.json添加测试脚本**

```json
// novalon-manage-web/package.json

{
  "scripts": {
    "test": "playwright test",
    "test:admin": "playwright test --project=admin-tests",
    "test:user": "playwright test --project=user-tests",
    "test:auth": "playwright test --project=auth-tests",
    "test:permission": "playwright test --project=permission-tests",
    "test:ui": "playwright test --ui",
    "test:debug": "playwright test --debug",
    "test:report": "playwright show-report"
  }
}
```

---

- [ ] **步骤 4：验证配置**

运行：`cd novalon-manage-web && pnpm test --list`

预期：列出所有测试文件

---

- [ ] **步骤 5：Commit配置文件**

```bash
cd novalon-manage-web
git add .env.test
git add playwright.config.ts
git add package.json
git commit -m "chore: 配置测试环境和Playwright项目

- 创建 .env.test 测试环境变量
- 更新 playwright.config.ts 添加角色测试项目
  - admin-tests: 管理员测试
  - user-tests: 普通用户测试
  - auth-tests: 认证测试
  - permission-tests: 权限测试
- 更新 package.json 添加测试脚本"
```

---

### 任务 8：实现认证场景测试

**目标：** 实现登录和登出流程测试，验证认证功能。

**文件：**
- 创建：`novalon-manage-web/e2e/role-based-tests/scenarios/authentication/login-flow.spec.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/scenarios/authentication/logout-flow.spec.ts`

---

- [ ] **步骤 1：编写登录流程测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/scenarios/authentication/login-flow.spec.ts

import { test, expect } from '@playwright/test';
import { AuthHelper } from '../../shared/auth-helper';
import { RoleFactory } from '../../roles/role-factory';

test.describe('登录流程测试', () => {
  test('管理员使用正确凭证登录成功', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', true);
    
    await expect(page).toHaveURL(/\/(dashboard|\/)/);
    
    const isLoggedIn = await AuthHelper.isLoggedIn(page);
    expect(isLoggedIn).toBeTruthy();
  });

  test('管理员使用错误密码登录失败', async ({ page }) => {
    const role = RoleFactory.getRole('admin');
    
    await page.goto('/login');
    await page.fill('[name="username"]', role.credentials.username);
    await page.fill('[name="password"]', 'wrongpassword');
    await page.click('[type="submit"]');
    
    await expect(page).toHaveURL(/.*login/);
    await expect(page.locator('.error-message')).toBeVisible();
  });

  test('普通用户登录成功', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'user', true);
    
    await expect(page).toHaveURL(/\/(dashboard|\/)/);
    
    const isLoggedIn = await AuthHelper.isLoggedIn(page);
    expect(isLoggedIn).toBeTruthy();
  });

  test('禁用用户登录失败', async ({ page }) => {
    await page.goto('/login');
    await page.fill('[name="username"]', 'disableduser');
    await page.fill('[name="password"]', 'Test@123');
    await page.click('[type="submit"]');
    
    await expect(page).toHaveURL(/.*login/);
    await expect(page.locator('.error-message')).toBeVisible();
  });
});
```

---

- [ ] **步骤 2：运行登录流程测试**

运行：`cd novalon-manage-web && pnpm test:auth`

预期：PASS（需要后端服务运行）

---

- [ ] **步骤 3：编写登出流程测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/scenarios/authentication/logout-flow.spec.ts

import { test, expect } from '@playwright/test';
import { AuthHelper } from '../../shared/auth-helper';

test.describe('登出流程测试', () => {
  test('管理员登出成功', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
    
    await AuthHelper.logout(page);
    
    await expect(page).toHaveURL(/.*login/);
    
    const token = await page.evaluate(() => localStorage.getItem('token'));
    expect(token).toBeNull();
  });

  test('普通用户登出成功', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'user', false);
    
    await AuthHelper.logout(page);
    
    await expect(page).toHaveURL(/.*login/);
    
    const token = await page.evaluate(() => localStorage.getItem('token'));
    expect(token).toBeNull();
  });
});
```

---

- [ ] **步骤 4：运行登出流程测试**

运行：`cd novalon-manage-web && pnpm test:auth`

预期：PASS（需要后端服务运行）

---

- [ ] **步骤 5：Commit认证场景测试**

```bash
cd novalon-manage-web
git add e2e/role-based-tests/scenarios/authentication/
git commit -m "feat: 实现认证场景测试

- 实现 login-flow.spec.ts 登录流程测试
  - 管理员正确凭证登录
  - 管理员错误密码登录
  - 普通用户登录
  - 禁用用户登录
- 实现 logout-flow.spec.ts 登出流程测试
  - 管理员登出
  - 普通用户登出"
```

---

### 任务 9：实现用户管理场景测试

**目标：** 实现用户管理场景测试，包括创建用户和权限边界验证。

**文件：**
- 创建：`novalon-manage-web/e2e/role-based-tests/scenarios/user-management/admin-creates-user.spec.ts`
- 创建：`novalon-manage-web/e2e/role-based-tests/scenarios/user-management/permission-boundary.spec.ts`

---

- [ ] **步骤 1：编写管理员创建用户测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/scenarios/user-management/admin-creates-user.spec.ts

import { test, expect } from '@playwright/test';
import { AuthHelper } from '../../shared/auth-helper';
import { TestDataManager } from '../../shared/test-data-manager';

test.describe('管理员创建用户场景', () => {
  test.beforeEach(async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
  });

  test.afterEach(async ({ page }) => {
    TestDataManager.reset();
  });

  test('管理员创建新用户成功', async ({ page }) => {
    const testUser = TestDataManager.generateTestUser();
    
    await page.goto('/user-management');
    await page.click('button:has-text("新建")');
    await page.fill('[name="username"]', testUser.username);
    await page.fill('[name="password"]', testUser.password);
    await page.fill('[name="email"]', testUser.email);
    await page.fill('[name="phone"]', testUser.phone);
    await page.fill('[name="nickname"]', testUser.nickname);
    await page.click('button[type="submit"]');
    
    await expect(page.locator('.success-message')).toBeVisible();
    
    TestDataManager.trackUser(testUser.username);
  });

  test('管理员创建用户失败-用户名已存在', async ({ page }) => {
    const testUser = TestDataManager.generateTestUser({
      username: 'admin'
    });
    
    await page.goto('/user-management');
    await page.click('button:has-text("新建")');
    await page.fill('[name="username"]', testUser.username);
    await page.fill('[name="password"]', testUser.password);
    await page.click('button[type="submit"]');
    
    await expect(page.locator('.error-message')).toBeVisible();
  });
});
```

---

- [ ] **步骤 2：运行管理员创建用户测试**

运行：`cd novalon-manage-web && pnpm test:admin`

预期：PASS（需要后端服务运行）

---

- [ ] **步骤 3：编写权限边界验证测试**

```typescript
// novalon-manage-web/e2e/role-based-tests/scenarios/user-management/permission-boundary.spec.ts

import { test, expect } from '@playwright/test';
import { AuthHelper } from '../../shared/auth-helper';
import { PermissionHelper } from '../../shared/permission-helper';

test.describe('用户管理权限边界验证', () => {
  test('普通用户无法访问用户管理页面', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'user', false);
    await PermissionHelper.verifyCannotAccess(page, '/user-management');
  });

  test('普通用户无法看到用户管理菜单', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'user', false);
    await PermissionHelper.verifyCannotSeeMenu(page, '用户管理');
  });

  test('普通用户无法创建用户', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'user', false);
    
    const token = await page.evaluate(() => localStorage.getItem('token'));
    const response = await fetch(`${process.env.VITE_API_BASE_URL}/api/users`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ 
        username: 'hacker', 
        password: 'hack123' 
      })
    });
    
    expect(response.status).toBe(403);
  });

  test('管理员可以访问用户管理页面', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
    await PermissionHelper.verifyCanAccess(page, '/user-management');
  });

  test('管理员可以看到用户管理菜单', async ({ page }) => {
    await AuthHelper.loginAsRole(page, 'admin', false);
    await PermissionHelper.verifyCanSeeMenu(page, '用户管理');
  });
});
```

---

- [ ] **步骤 4：运行权限边界验证测试**

运行：`cd novalon-manage-web && pnpm test:permission`

预期：PASS（需要后端服务运行）

---

- [ ] **步骤 5：Commit用户管理场景测试**

```bash
cd novalon-manage-web
git add e2e/role-based-tests/scenarios/user-management/
git commit -m "feat: 实现用户管理场景测试

- 实现 admin-creates-user.spec.ts 管理员创建用户测试
  - 创建新用户成功
  - 创建用户失败-用户名已存在
- 实现 permission-boundary.spec.ts 权限边界验证测试
  - 普通用户无法访问用户管理页面
  - 普通用户无法看到用户管理菜单
  - 普通用户无法创建用户
  - 管理员可以访问用户管理页面
  - 管理员可以看到用户管理菜单"
```

---

### 任务 10：验证和文档完善

**目标：** 运行全量测试验证，更新README文档。

**文件：**
- 修改：`novalon-manage-web/README.md`

---

- [ ] **步骤 1：运行全量测试**

运行：`cd novalon-manage-web && pnpm test`

预期：所有测试通过

---

- [ ] **步骤 2：生成测试覆盖率报告**

运行：`cd novalon-manage-web && pnpm test:report`

预期：生成HTML报告

---

- [ ] **步骤 3：更新README文档**

在README.md中添加测试框架说明：

```markdown
## 基于角色的测试框架

### 概述

本系统采用基于角色的用户模拟测试套件，实现真实场景的验收标准。

### 测试结构

```
e2e/role-based-tests/
├── roles/                    # 角色定义
│   ├── base.role.ts
│   ├── admin.role.ts
│   ├── user.role.ts
│   ├── test.role.ts
│   └── role-factory.ts
├── scenarios/                # 业务场景测试
│   ├── authentication/
│   └── user-management/
└── shared/                   # 共享工具
    ├── auth-helper.ts
    ├── role-auth-manager.ts
    ├── test-data-manager.ts
    └── permission-helper.ts
```

### 运行测试

```bash
# 运行所有测试
pnpm test

# 运行管理员测试
pnpm test:admin

# 运行普通用户测试
pnpm test:user

# 运行认证测试
pnpm test:auth

# 运行权限测试
pnpm test:permission

# 查看测试报告
pnpm test:report
```

### 测试数据

所有测试用户统一使用密码：`Test@123`

| 用户名 | 角色 | 说明 |
|--------|------|------|
| admin | 超级管理员 | 拥有所有权限 |
| normaluser | 普通用户 | 只能访问自己的信息 |
| e2e_test_user | 测试用户 | 用于特定测试场景 |
```

---

- [ ] **步骤 4：Commit文档更新**

```bash
cd novalon-manage-web
git add README.md
git commit -m "docs: 更新README添加测试框架说明

- 添加测试框架概述
- 添加测试结构说明
- 添加运行测试命令
- 添加测试数据说明"
```

---

## 自检清单

### 1. 规格覆盖度检查

| 规格需求 | 对应任务 | 状态 |
|---------|---------|------|
| 修复H2密码不一致问题 | 任务1 | ✅ |
| 创建目录结构 | 任务2 | ✅ |
| 实现角色定义系统 | 任务3 | ✅ |
| 实现认证辅助工具 | 任务4 | ✅ |
| 实现测试数据管理器 | 任务5 | ✅ |
| 实现权限验证工具 | 任务6 | ✅ |
| 配置环境变量和Playwright | 任务7 | ✅ |
| 实现认证场景测试 | 任务8 | ✅ |
| 实现用户管理场景测试 | 任务9 | ✅ |
| 验证和文档完善 | 任务10 | ✅ |

**结论**：✅ 所有规格需求都有对应任务

---

### 2. 占位符扫描

**检查结果**：
- ✅ 无"待定"、"TODO"等占位符
- ✅ 所有代码步骤都有完整代码
- ✅ 所有测试步骤都有完整测试代码
- ✅ 所有验证步骤都有明确的命令和预期输出

---

### 3. 类型一致性检查

**检查结果**：
- ✅ RoleDefinition接口在所有角色定义中一致使用
- ✅ TestUserData接口在测试数据管理器中一致使用
- ✅ 所有函数签名和参数类型一致
- ✅ 所有导入路径正确

---

## 执行交接

计划已完成并准备保存。两种执行方式：

**1. 子代理驱动（推荐）** - 每个任务调度一个新的子代理，任务间进行审查，快速迭代

**2. 内联执行** - 在当前会话中使用 executing-plans 执行任务，批量执行并设有检查点

**请选择执行方式。**
