/** * 影子系统功能测试脚本 * * 测试功能: * 1. 用户登录 * 2. 用户角色切换(管理员/普通用户) * 3. 用户状态管理 * * 使用方法: * npx tsx scripts/test-shadow-system.ts */ import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); // 测试配置 const SHADOW_SYSTEM_URL = process.env.SHADOW_SYSTEM_URL || 'http://192.168.58.20:5320'; const TEST_USER_EMAIL = process.env.TEST_USER_EMAIL || ''; const TEST_USER_PASSWORD = process.env.TEST_USER_PASSWORD || ''; interface TestResult { name: string; passed: boolean; error?: string; details?: any; } const results: TestResult[] = []; async function test(name: string, testFn: () => Promise): Promise { try { console.log(`\n🧪 测试: ${name}`); const details = await testFn(); results.push({ name, passed: true, details }); console.log(` ✅ 通过`); } catch (error: any) { results.push({ name, passed: false, error: error.message }); console.log(` ❌ 失败: ${error.message}`); } } async function main() { console.log('========================================'); console.log('影子系统功能测试'); console.log('========================================'); console.log(`测试目标: ${SHADOW_SYSTEM_URL}`); console.log(`数据库: ${process.env.DATABASE_URL?.split('@')[1] || '未设置'}`); console.log(''); // 测试1: 检查数据库连接 await test('数据库连接', async () => { await prisma.$connect(); const count = await prisma.user.count(); return { totalUsers: count }; }); // 测试2: 检查用户状态字段 await test('用户状态字段检查', async () => { const users = await prisma.user.findMany({ take: 5, select: { id: true, email: true, username: true, status: true, isActive: true, role: true, lastLoginAt: true, loginCount: true, }, }); const hasStatus = users.every(u => u.status !== null && u.status !== undefined); const hasIsActive = users.every(u => u.isActive !== null && u.isActive !== undefined); if (!hasStatus || !hasIsActive) { throw new Error('用户状态字段缺失'); } return { sampleUsers: users.map(u => ({ email: u.email, status: u.status, isActive: u.isActive, role: u.role, hasLastLoginAt: u.lastLoginAt !== null, loginCount: u.loginCount, })), }; }); // 测试3: 检查部门外键关联 await test('部门外键关联检查', async () => { const usersWithDept = await prisma.user.findMany({ where: { department: { not: '' }, }, take: 5, select: { id: true, email: true, department: true, departmentId: true, departmentRef: { select: { id: true, name: true, }, }, }, }); const allHaveDepartmentId = usersWithDept.every(u => u.departmentId !== null); const allHaveDepartmentRef = usersWithDept.every(u => u.departmentRef !== null); const namesMatch = usersWithDept.every( u => !u.departmentRef || u.department === u.departmentRef.name ); if (!allHaveDepartmentId) { throw new Error('部分用户缺少 departmentId'); } if (!allHaveDepartmentRef) { throw new Error('部分用户缺少 departmentRef 关联'); } if (!namesMatch) { throw new Error('部门名称与关联不匹配'); } return { sampleUsers: usersWithDept.map(u => ({ email: u.email, department: u.department, departmentId: u.departmentId, departmentRefName: u.departmentRef?.name, })), }; }); // 测试4: 查找测试用户(管理员和普通用户) await test('查找测试用户', async () => { const adminUser = await prisma.user.findFirst({ where: { role: 'ADMIN', status: 'active', }, select: { id: true, email: true, username: true, role: true, status: true, }, }); const normalUser = await prisma.user.findFirst({ where: { role: 'USER', status: 'active', }, select: { id: true, email: true, username: true, role: true, status: true, }, }); if (!adminUser || !normalUser) { throw new Error('未找到足够的测试用户(需要至少1个管理员和1个普通用户)'); } return { adminUser: { id: adminUser.id, email: adminUser.email, username: adminUser.username, role: adminUser.role, status: adminUser.status, }, normalUser: { id: normalUser.id, email: normalUser.email, username: normalUser.username, role: normalUser.role, status: normalUser.status, }, }; }); // 测试5: 测试角色切换(模拟) await test('角色切换功能(数据验证)', async () => { // 找到一个普通用户 const user = await prisma.user.findFirst({ where: { role: 'USER', status: 'active', }, }); if (!user) { throw new Error('未找到可测试的普通用户'); } const originalRole = user.role; // 验证可以切换到ADMIN await prisma.user.update({ where: { id: user.id }, data: { role: 'ADMIN' }, }); const updatedUser = await prisma.user.findUnique({ where: { id: user.id }, select: { role: true }, }); if (updatedUser?.role !== 'ADMIN') { throw new Error('角色切换失败'); } // 恢复原角色 await prisma.user.update({ where: { id: user.id }, data: { role: originalRole }, }); return { testUserId: user.id, originalRole, switchedToAdmin: true, restored: true, }; }); // 测试6: 测试状态切换(模拟) await test('状态切换功能(数据验证)', async () => { const user = await prisma.user.findFirst({ where: { status: 'active', }, }); if (!user) { throw new Error('未找到可测试的用户'); } const originalStatus = user.status; const originalIsActive = user.isActive; // 测试切换到suspended await prisma.user.update({ where: { id: user.id }, data: { status: 'suspended', isActive: false, }, }); const suspendedUser = await prisma.user.findUnique({ where: { id: user.id }, select: { status: true, isActive: true }, }); if (suspendedUser?.status !== 'suspended' || suspendedUser?.isActive !== false) { throw new Error('状态切换失败'); } // 测试切换回active await prisma.user.update({ where: { id: user.id }, data: { status: 'active', isActive: true, }, }); const activeUser = await prisma.user.findUnique({ where: { id: user.id }, select: { status: true, isActive: true }, }); if (activeUser?.status !== 'active' || activeUser?.isActive !== true) { throw new Error('状态恢复失败'); } return { testUserId: user.id, originalStatus, switchedToSuspended: true, restoredToActive: true, }; }); // 测试7: 验证双写逻辑(status 和 isActive 的一致性) await test('双写逻辑验证(status 和 isActive 一致性)', async () => { const inconsistencies = await prisma.user.findMany({ where: { OR: [ { status: 'active', isActive: false }, { status: { not: 'active' }, isActive: true }, ], }, take: 10, select: { id: true, email: true, status: true, isActive: true, }, }); if (inconsistencies.length > 0) { throw new Error( `发现 ${inconsistencies.length} 个用户 status 和 isActive 不一致` ); } return { checked: true, inconsistencies: 0, }; }); // 测试8: 统计信息 await test('数据统计', async () => { const totalUsers = await prisma.user.count(); const activeUsers = await prisma.user.count({ where: { status: 'active' } }); const pendingUsers = await prisma.user.count({ where: { status: 'pending' } }); const suspendedUsers = await prisma.user.count({ where: { status: 'suspended' } }); const archivedUsers = await prisma.user.count({ where: { status: 'archived' } }); const adminUsers = await prisma.user.count({ where: { role: 'ADMIN' } }); const normalUsers = await prisma.user.count({ where: { role: 'USER' } }); const usersWithDept = await prisma.user.count({ where: { departmentId: { not: null } } }); return { totalUsers, byStatus: { active: activeUsers, pending: pendingUsers, suspended: suspendedUsers, archived: archivedUsers, }, byRole: { admin: adminUsers, user: normalUsers, }, usersWithDepartmentId: usersWithDept, }; }); // 输出测试结果 console.log('\n========================================'); console.log('测试结果汇总'); console.log('========================================'); const passed = results.filter(r => r.passed).length; const failed = results.filter(r => !r.passed).length; results.forEach(result => { const icon = result.passed ? '✅' : '❌'; console.log(`${icon} ${result.name}`); if (!result.passed && result.error) { console.log(` 错误: ${result.error}`); } }); console.log('\n========================================'); console.log(`总计: ${results.length} 个测试`); console.log(`✅ 通过: ${passed}`); console.log(`❌ 失败: ${failed}`); console.log('========================================\n'); if (failed > 0) { process.exit(1); } } main() .catch((error) => { console.error('测试执行失败:', error); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });