import { test, expect, request } from '@playwright/test'; const timestamp = Date.now() const testProjectId = '550e8400-e29b-41d4-a716-446655440001' function uniqueCode() { return `EQ-${timestamp}-${Math.random().toString(36).substr(2, 8)}` } async function getToken() { const context = await request.newContext() const loginResp = await context.post('http://127.0.0.1:8080/api/auth/login', { headers: { 'Content-Type': 'application/json' }, data: { username: 'admin', password: 'Admin@123' } }) const loginData = await loginResp.json() const token = loginData.data?.token await context.dispose() return token } async function createEquipment(token: string, name: string) { const context = await request.newContext() const resp = await context.post('http://127.0.0.1:8080/api/v1/mdm/equipment', { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, data: { projectId: testProjectId, equipmentName: name, equipmentCode: uniqueCode(), equipmentType: 'ELEVATOR', systemType: 'ELEVATOR', ownershipType: 'PROJECT', status: 'ACTIVE' } }) const data = await resp.json() await context.dispose() if (data.code !== 200 || !data.data) { console.log(`创建设备失败: ${JSON.stringify(data)}`) return null } return data.data } async function createTask(token: string, equipmentId: string, title: string) { const context = await request.newContext() const resp = await context.post('http://127.0.0.1:8080/api/mdm/maintenance-tasks', { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, data: { equipmentId, title, description: `测试工单`, taskType: 'CORRECTIVE', triggerType: 'FAULT', priority: 'MEDIUM' } }) const data = await resp.json() await context.dispose() if (data.code !== 200 || !data.data) { console.log(`创建任务失败: ${JSON.stringify(data)}`) return null } return data.data } async function deleteEquipment(token: string, id: string) { if (!id) return const context = await request.newContext() await context.delete(`http://127.0.0.1:8080/api/v1/mdm/equipment/${id}`, { headers: { 'Authorization': `Bearer ${token}` } }) await context.dispose() } test.describe('业务流程E2E测试', () => { test('1. 设备完整生命周期', async () => { const token = await getToken() expect(token).toBeTruthy() const equipment = await createEquipment(token!, `设备生命周期_${timestamp}`) expect(equipment?.id).toBeTruthy() console.log(`✓ 创建设备: ${equipment?.id}`) const context = await request.newContext() const getResp = await context.get(`http://127.0.0.1:8080/api/v1/mdm/equipment/${equipment.id}`, { headers: { 'Authorization': `Bearer ${token}` } }) expect(getResp.status()).toBe(200) const detailData = await getResp.json() expect(detailData.data.equipmentName).toContain('设备生命周期') console.log('✓ 查询设备详情成功') await context.dispose() await deleteEquipment(token!, equipment.id) console.log('✓ 删除设备成功') }) test('2. 维保工单状态流转', async () => { const token = await getToken() const equipment = await createEquipment(token!, `工单流转_${timestamp}`) if (!equipment) { console.log('设备创建失败,跳过测试') return } const task = await createTask(token!, equipment.id, `工单流转测试_${timestamp}`) if (!task) { console.log('任务创建失败,跳过测试') await deleteEquipment(token!, equipment.id) return } console.log(`✓ 工单创建: ${task?.id}, 状态: ${task?.status}`) const assignCtx = await request.newContext() const assignResp = await assignCtx.post(`http://127.0.0.1:8080/api/mdm/maintenance-tasks/${task.id}/assign`, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, data: { assignedTo: '张三' } }) expect(assignResp.status()).toBe(200) console.log('✓ 派单成功') await assignCtx.dispose() const startCtx = await request.newContext() const startResp = await startCtx.post(`http://127.0.0.1:8080/api/mdm/maintenance-tasks/${task.id}/start`, { headers: { 'Authorization': `Bearer ${token}` } }) expect(startResp.status()).toBe(200) console.log('✓ 开始执行成功') await startCtx.dispose() const completeCtx = await request.newContext() const completeResp = await completeCtx.post(`http://127.0.0.1:8080/api/mdm/maintenance-tasks/${task.id}/complete`, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, data: { result: '已完成', completedBy: '张三' } }) expect(completeResp.status()).toBe(200) console.log('✓ 完成工单成功') await completeCtx.dispose() const verifyCtx = await request.newContext() const verifyResp = await verifyCtx.post(`http://127.0.0.1:8080/api/mdm/maintenance-tasks/${task.id}/verify`, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, data: { verifiedBy: '李经理', rating: 5 } }) expect(verifyResp.status()).toBe(200) console.log('✓ 验收工单成功') await verifyCtx.dispose() await deleteEquipment(token!, equipment.id) console.log('✓ 工单流转测试完成') }) test('3. 设备列表页面正常加载', async ({ page }) => { const token = await getToken() await page.goto('http://127.0.0.1:5175/login') await page.evaluate((t) => { localStorage.setItem('token', t) localStorage.setItem('userInfo', JSON.stringify({ username: 'admin' })) }, token!) await page.goto('http://127.0.0.1:5175/equipment/list') await page.waitForLoadState('networkidle') await page.waitForTimeout(1500) const url = page.url() expect(url).toContain('equipment') console.log('✓ 设备列表页面加载正常') }) }) test.describe('边际情况E2E测试', () => { test('4. 取消工单功能', async () => { const token = await getToken() const equipment = await createEquipment(token!, `取消测试_${timestamp}`) if (!equipment) { console.log('设备创建失败,跳过测试') return } const task = await createTask(token!, equipment.id, `取消测试_${timestamp}`) if (!task) { await deleteEquipment(token!, equipment.id) console.log('任务创建失败,跳过测试') return } const context = await request.newContext() const cancelResp = await context.post(`http://127.0.0.1:8080/api/mdm/maintenance-tasks/${task.id}/cancel`, { headers: { 'Authorization': `Bearer ${token}` } }) expect(cancelResp.status()).toBe(200) const cancelData = await cancelResp.json() expect(cancelData.data?.status).toBe('CANCELLED') console.log('✓ 取消工单成功') await context.dispose() await deleteEquipment(token!, equipment.id) }) test('5. 获取不存在的设备返回404', async () => { const token = await getToken() const context = await request.newContext() const resp = await context.get('http://127.0.0.1:8080/api/v1/mdm/equipment/00000000-0000-0000-0000-000000000000', { headers: { 'Authorization': `Bearer ${token}` } }) const status = resp.status() console.log(`不存在设备响应状态: ${status}`) expect(status).toBe(404) console.log('✓ 不存在资源返回404') await context.dispose() }) test('6. 未登录访问返回401/403', async () => { const context = await request.newContext() const resp = await context.get('http://127.0.0.1:8080/api/mdm/maintenance-tasks') expect([401, 403]).toContain(resp.status()) console.log('✓ 未授权访问被拒绝') await context.dispose() }) test('7. 重复设备名称应允许创建', async () => { const token = await getToken() const dupName = `重复名称_${timestamp}` const eq1 = await createEquipment(token!, dupName) if (!eq1) { console.log('第一个设备创建失败') return } const eq2 = await createEquipment(token!, dupName) expect(eq2?.id).toBeTruthy() console.log('✓ 系统允许重复设备名称') await deleteEquipment(token!, eq1.id) await deleteEquipment(token!, eq2.id) }) }) test.describe('页面稳定性测试', () => { test('8. 设备相关页面无严重错误', async ({ page }) => { const errors: string[] = [] page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()) }) const token = await getToken() await page.goto('http://127.0.0.1:5175/equipment/list') await page.evaluate((t) => { localStorage.setItem('token', t) localStorage.setItem('userInfo', JSON.stringify({ username: 'admin' })) }, token!) await page.reload() const pages = ['/equipment/list', '/equipment/maintenance-plan', '/equipment/maintenance-task'] for (const path of pages) { await page.goto(`http://127.0.0.1:5175${path}`) await page.waitForLoadState('networkidle') await page.waitForTimeout(800) } console.log(`控制台错误数: ${errors.length}`) expect(errors.length).toBeLessThan(5) console.log('✓ 页面无严重错误') }) })