import { test, expect, Browser, BrowserContext, Page } from '@playwright/test'; test.describe('跨端交互测试', () => { test.beforeAll(async () => { console.log('开始跨端交互测试...'); }); test('Admin创建用户 - 数据一致性验证', async ({ browser }) => { const adminContext = await browser.newContext(); const adminPage = await adminContext.newPage(); try { await adminPage.goto('/login'); await adminPage.waitForLoadState('networkidle'); await adminPage.fill('[data-testid="username-input"] input', 'admin'); await adminPage.fill('[data-testid="password-input"] input', 'admin123456'); await adminPage.click('[data-testid="login-button"]'); await expect(adminPage).toHaveURL(/.*\//, { timeout: 15000 }); await adminPage.goto('/system/user'); await adminPage.waitForLoadState('networkidle'); const timestamp = Date.now(); const testUsername = `cross_test_${timestamp}`; await adminPage.click('[data-testid="add-user-button"]'); await expect(adminPage.locator('.el-dialog')).toBeVisible(); await adminPage.fill('[data-testid="username-input"] input', testUsername); await adminPage.fill('[data-testid="email-input"] input', `${testUsername}@example.com`); await adminPage.fill('[data-testid="phone-input"] input', '13800138000'); await adminPage.fill('[data-testid="password-input"] input', 'Test@123456'); await adminPage.click('[data-testid="submit-button"]'); await expect(adminPage.locator('.el-message--success')).toBeVisible({ timeout: 10000 }); await adminPage.fill('[data-testid="search-username-input"] input', testUsername); await adminPage.click('button:has-text("搜索")'); await adminPage.waitForTimeout(1000); await expect(adminPage.locator(`text=${testUsername}`)).toBeVisible({ timeout: 10000 }); console.log(`用户 ${testUsername} 在Admin端创建成功`); } finally { await adminContext.close(); } }); test('API直接调用 - 验证数据持久化', async ({ request }) => { const response = await request.get('/api/sys/user/list', { headers: { 'Authorization': 'Bearer test_token', }, }); if (response.status() === 401) { console.log('API需要认证,跳过直接调用测试'); test.skip(); return; } expect(response.ok()).toBeTruthy(); const data = await response.json(); expect(data).toBeDefined(); }); test('角色权限变更 - 验证权限生效', async ({ browser }) => { const adminContext = await browser.newContext(); const adminPage = await adminContext.newPage(); try { await adminPage.goto('/login'); await adminPage.fill('[data-testid="username-input"] input', 'admin'); await adminPage.fill('[data-testid="password-input"] input', 'admin123456'); await adminPage.click('[data-testid="login-button"]'); await expect(adminPage).toHaveURL(/.*\//, { timeout: 15000 }); await adminPage.goto('/system/role'); await adminPage.waitForLoadState('networkidle'); const editButton = adminPage.locator('table button:has-text("编辑"), .el-table button:has-text("编辑")'); const buttonCount = await editButton.count(); expect(buttonCount).toBeGreaterThan(0); console.log(`找到 ${buttonCount} 个可编辑的角色`); } finally { await adminContext.close(); } }); test('菜单配置变更 - 验证菜单更新', async ({ browser }) => { const adminContext = await browser.newContext(); const adminPage = await adminContext.newPage(); try { await adminPage.goto('/login'); await adminPage.fill('[data-testid="username-input"] input', 'admin'); await adminPage.fill('[data-testid="password-input"] input', 'admin123456'); await adminPage.click('[data-testid="login-button"]'); await expect(adminPage).toHaveURL(/.*\//, { timeout: 15000 }); await adminPage.goto('/system/menu'); await adminPage.waitForLoadState('networkidle'); const table = adminPage.locator('table, .el-table'); await expect(table).toBeVisible(); const rows = await table.locator('tbody tr').count(); expect(rows).toBeGreaterThan(0); console.log(`找到 ${rows} 个菜单项`); } finally { await adminContext.close(); } }); test('并发用户操作 - 验证数据一致性', async ({ browser }) => { const contexts: BrowserContext[] = []; const pages: Page[] = []; try { for (let i = 0; i < 3; i++) { const context = await browser.newContext(); const page = await context.newPage(); contexts.push(context); pages.push(page); } await Promise.all(pages.map(async (page, index) => { await page.goto('/login'); await page.fill('[data-testid="username-input"] input', 'admin'); await page.fill('[data-testid="password-input"] input', 'admin123456'); await page.click('[data-testid="login-button"]'); await expect(page).toHaveURL(/.*\//, { timeout: 15000 }); console.log(`用户 ${index + 1} 登录成功`); })); await Promise.all(pages.map(async (page) => { await page.goto('/system/user'); await page.waitForLoadState('networkidle'); })); const userCounts = await Promise.all(pages.map(async (page) => { const table = page.locator('[data-testid="user-table"]'); return await table.locator('tbody tr').count(); })); console.log('各会话用户数量:', userCounts); } finally { await Promise.all(contexts.map(context => context.close())); } }); }); test.describe('数据一致性验证', () => { test('用户数据CRUD一致性', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid="username-input"] input', 'admin'); await page.fill('[data-testid="password-input"] input', 'admin123456'); await page.click('[data-testid="login-button"]'); await expect(page).toHaveURL(/.*\//, { timeout: 15000 }); await page.goto('/system/user'); await page.waitForLoadState('networkidle'); const table = page.locator('[data-testid="user-table"]'); const initialCount = await table.locator('tbody tr').count(); console.log(`初始用户数量: ${initialCount}`); const timestamp = Date.now(); await page.click('[data-testid="add-user-button"]'); await page.fill('[data-testid="username-input"] input', `consistency_test_${timestamp}`); await page.fill('[data-testid="email-input"] input', `consistency_${timestamp}@example.com`); await page.fill('[data-testid="phone-input"] input', '13700137000'); await page.fill('[data-testid="password-input"] input', 'Test@123456'); await page.click('[data-testid="submit-button"]'); await expect(page.locator('.el-message--success')).toBeVisible({ timeout: 10000 }); await page.reload(); await page.waitForLoadState('networkidle'); const afterCreateCount = await table.locator('tbody tr').count(); console.log(`创建后用户数量: ${afterCreateCount}`); }); test('API响应数据格式验证', async ({ request }) => { const endpoints = [ { path: '/actuator/health', expectedFields: ['status'] }, ]; for (const endpoint of endpoints) { const response = await request.get(endpoint.path); if (response.ok()) { const data = await response.json(); for (const field of endpoint.expectedFields) { expect(data).toHaveProperty(field); } console.log(`端点 ${endpoint.path} 响应格式正确`); } } }); });