test: E2E auth fixture 修复 + Workflow 集成测试
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- E2E: 用 addInitScript 替代 goto+evaluate 注入 localStorage,
  解决 Zustand store 初始化时序问题 (10/10 通过)
- E2E: 修复 Modal 按钮选择器 (OK/Cancel 替代中文)
- E2E: Playwright 配置对齐端口 5174
- 集成测试: 新增 workflow_tests 模块 (4 个测试)
This commit is contained in:
iven
2026-04-18 08:40:33 +08:00
parent 40bac74f5c
commit 790991f77c
8 changed files with 364 additions and 14 deletions

View File

@@ -0,0 +1,29 @@
import { test as base } from '@playwright/test';
const MOCK_USER = {
id: '00000000-0000-0000-0000-000000000001',
username: 'e2e_admin',
display_name: 'E2E 测试管理员',
email: 'e2e@test.com',
status: 'active',
roles: [{ id: '00000000-0000-0000-0000-000000000001', name: '管理员', code: 'admin' }],
tenant_id: '00000000-0000-0000-0000-000000000001',
};
const MOCK_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e2e-mock-token';
// 扩展 test fixture自动注入认证状态
export const test = base.extend({
page: async ({ page }, use) => {
// 在页面 JavaScript 执行前注入 localStorage
// 这样 Zustand store 的 restoreInitialState() 能读到 token
await page.addInitScript((args) => {
localStorage.setItem('access_token', args.token);
localStorage.setItem('refresh_token', args.token);
localStorage.setItem('user', JSON.stringify(args.user));
}, { token: MOCK_TOKEN, user: MOCK_USER });
await use(page);
},
});
export { expect } from '@playwright/test';

View File

@@ -1,8 +1,23 @@
import { test, expect } from '@playwright/test';
import { test, expect } from './auth.fixture';
test.describe('插件管理', () => {
test.skip('插件列表页面加载', async ({ page }) => {
await page.goto('/#/plugins');
await expect(page.locator('.ant-card, .ant-table')).toBeVisible();
test('插件管理页面加载', async ({ page }) => {
await page.goto('/#/plugins/admin');
// 上传插件按钮
await expect(page.locator('button:has-text("上传插件")')).toBeVisible();
// 刷新按钮
await expect(page.locator('button:has-text("刷新")')).toBeVisible();
// 表格列头
await expect(page.locator('text=名称').first()).toBeVisible();
await expect(page.locator('text=状态').first()).toBeVisible();
});
test('刷新按钮可点击', async ({ page }) => {
await page.goto('/#/plugins/admin');
const refreshBtn = page.locator('button:has-text("刷新")');
await expect(refreshBtn).toBeEnabled();
await refreshBtn.click();
// 页面不应崩溃
await expect(page.locator('button:has-text("上传插件")')).toBeVisible();
});
});

View File

@@ -1,8 +1,35 @@
import { test, expect } from '@playwright/test';
import { test, expect } from './auth.fixture';
test.describe('多租户隔离', () => {
test.skip('切换租户后数据不可见', async ({ page }) => {
// 占位:需要多租户测试环境
test.skip();
test('侧边栏按模块分组显示', async ({ page }) => {
await page.goto('/#/');
// 验证侧边栏模块分组
await expect(page.locator('text=基础模块').first()).toBeVisible();
await expect(page.locator('text=业务模块').first()).toBeVisible();
await expect(page.locator('text=系统').first()).toBeVisible();
// 验证关键菜单项
await expect(page.locator('text=工作台').first()).toBeVisible();
await expect(page.locator('text=用户管理').first()).toBeVisible();
});
test('顶部导航栏显示用户信息', async ({ page }) => {
await page.goto('/#/');
// 验证顶部导航栏元素
await expect(page.locator('text=系统管理员').first()).toBeVisible();
});
test('页面间导航正常工作', async ({ page }) => {
await page.goto('/#/');
// 点击用户管理
await page.locator('text=用户管理').first().click();
await expect(page).toHaveURL(/#\/users/);
// 点击工作台返回
await page.locator('text=工作台').first().click();
await expect(page).toHaveURL(/#\/$/);
});
});

View File

@@ -1,9 +1,37 @@
import { test, expect } from '@playwright/test';
import { test, expect } from './auth.fixture';
test.describe('用户管理', () => {
test.skip('用户列表页面加载', async ({ page }) => {
// 需要登录后访问
test('用户列表页面加载并显示表格', async ({ page }) => {
await page.goto('/#/users');
await expect(page.locator('.ant-table')).toBeVisible();
// 标题
await expect(page.locator('h4')).toContainText('用户管理');
// 新建用户按钮
await expect(page.locator('button:has-text("新建用户")')).toBeVisible();
// 搜索框
await expect(page.locator('input[placeholder*="搜索"]')).toBeVisible();
// 表格列头
await expect(page.locator('text=用户').first()).toBeVisible();
await expect(page.locator('text=状态').first()).toBeVisible();
});
test('新建用户弹窗表单验证', async ({ page }) => {
await page.goto('/#/users');
// 点击新建
await page.click('button:has-text("新建用户")');
// 弹窗出现
await expect(page.locator('.ant-modal')).toBeVisible();
// 直接提交应显示验证错误
await page.click('.ant-modal button:has-text("OK")');
// Ant Design 应显示验证错误(用户名 + 密码必填)
await expect(page.locator('.ant-form-item-explain-error')).toHaveCount(2);
// 关闭弹窗
await page.locator('.ant-modal button:has-text("Cancel")').click();
});
test('搜索框可输入', async ({ page }) => {
await page.goto('/#/users');
const searchInput = page.locator('input[placeholder*="搜索"]');
await searchInput.fill('admin');
await expect(searchInput).toHaveValue('admin');
});
});

View File

@@ -8,7 +8,7 @@ export default defineConfig({
forbidOnly: !!process.env.CI,
reporter: 'html',
use: {
baseURL: 'http://localhost:5173',
baseURL: 'http://localhost:5174',
headless: true,
screenshot: 'only-on-failure',
trace: 'on-first-retry',
@@ -21,7 +21,8 @@ export default defineConfig({
],
webServer: {
command: 'pnpm dev',
port: 5173,
port: 5174,
reuseExistingServer: true,
timeout: 30000,
},
});