Files
aurak/test-permission-flow.mjs
T
Developer 9b4412792b feat: 用户管理页加角色列和角色编辑弹窗
- 用户表新增「角色」列,显示超级管理员/管理员/用户徽章
- 编辑用户弹窗增加角色选择(USER/TENANT_ADMIN/SUPER_ADMIN)
- 角色选择时同步显示该角色的权限预览
- 保存时自动调用 PATCH /tenants/:id/members/:userId 更新角色
- 新增 test-permission-flow.mjs 三层用户权限测试脚本

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 23:37:13 +08:00

133 lines
4.8 KiB
JavaScript

import { chromium } from 'playwright';
const BASE = 'http://localhost:13001';
const API = 'http://localhost:3001';
const USERS = [
{ label: 'SUPER_ADMIN (admin)', username: 'admin', password: 'admin123', expectedPerms: 26 },
{ label: 'TENANT_ADMIN (ta_admin)', username: 'ta_admin', password: 'pass123', expectedPerms: 21 },
{ label: 'USER (user1)', username: 'user1', password: 'pass123', expectedPerms: 5 },
];
async function login(page, username, password) {
await page.goto(`${BASE}/login`, { waitUntil: 'networkidle' });
await page.waitForTimeout(1000);
await page.locator('input[type="text"]').first().fill(username);
await page.locator('input[type="password"]').first().fill(password);
await page.locator('button[type="submit"]').click();
await page.waitForURL('**/');
await page.waitForTimeout(1000);
}
async function getApiKey(page) {
return await page.evaluate(() => localStorage.getItem('kb_api_key') || '');
}
async function run() {
const browser = await chromium.launch({ headless: true });
const results = [];
for (const u of USERS) {
console.log(`\n${'='.repeat(60)}`);
console.log(`🧑‍💻 ${u.label}`);
console.log(`${'='.repeat(60)}`);
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
const r = { user: u.label, login: false, perms: 0, nav: [], settingsTabs: [], api: {} };
try {
// Login
await login(page, u.username, u.password);
r.login = true;
console.log(` ✅ 登录成功`);
// Get API key from page
const apiKey = await getApiKey(page);
console.log(` 🔑 API Key: ${apiKey.substring(0, 16)}...`);
// Check navigation sidebar
r.nav = await page.evaluate(() => {
return Array.from(document.querySelectorAll('aside, nav, [class*="sidebar"], [class*="navigation"]'))
.flatMap(el => Array.from(el.querySelectorAll('a, button')))
.map(el => (el.textContent || '').trim())
.filter(Boolean)
.filter(t => !t.startsWith('AuraK') && !t.startsWith('Admin'))
.filter((v, i, a) => a.indexOf(v) === i);
});
console.log(` 📋 导航: ${r.nav.join(', ')}`);
// Check settings tabs
await page.goto(`${BASE}/settings`, { waitUntil: 'networkidle' });
await page.waitForTimeout(2000);
r.settingsTabs = await page.evaluate(() => {
return Array.from(document.querySelectorAll('aside button, [class*="sidebar"] button'))
.map(b => (b.textContent || '').trim())
.filter(Boolean)
.filter((v, i, a) => a.indexOf(v) === i);
});
console.log(` ⚙️ 设置Tab: ${r.settingsTabs.join(', ')}`);
// API permission checks
const headers = { 'x-api-key': apiKey };
// /api/permissions/mine
const permRes = await fetch(`${API}/api/permissions/mine`, { headers });
const permData = await permRes.json();
r.perms = (permData.permissions || []).length;
console.log(` 🔒 权限数: ${r.perms} (期望: ${u.expectedPerms})`);
// /api/users (user:view)
const usersRes = await fetch(`${API}/api/users`, { headers });
r.api['user:view'] = usersRes.status;
console.log(` GET /api/users: ${usersRes.ok ? '✅' : '❌'} (${usersRes.status})`);
// /api/roles (TENANT_ADMIN+)
const rolesRes = await fetch(`${API}/api/roles`, { headers });
r.api['roles'] = rolesRes.status;
console.log(` GET /api/roles: ${rolesRes.ok ? '✅' : '❌'} (${rolesRes.status})`);
// Check assessment access
await page.goto(`${BASE}/assessment`, { waitUntil: 'networkidle' });
await page.waitForTimeout(2000);
const assessOK = await page.evaluate(() => {
const body = document.body.textContent || '';
return body.includes('AI协作技巧') || body.includes('开始专业评估');
});
r.api['assessment'] = assessOK;
console.log(` 📝 考核页可访问: ${assessOK ? '✅' : '❌'}`);
} catch (err) {
console.error(` ❌ 错误: ${err.message}`);
} finally {
await page.close();
}
results.push(r);
}
// Summary table
console.log(`\n${'='.repeat(60)}`);
console.log('📊 权限测试汇总');
console.log(`${'='.repeat(60)}`);
console.log(`用户 登录 权限 users roles 设置Tab`);
console.log(`${'─'.repeat(60)}`);
for (const r of results) {
const tabStr = r.settingsTabs.filter(t => !['基本设置'].includes(t)).join('/') || '-';
console.log(
r.user.padEnd(22),
r.login ? '✅' : '❌',
String(r.perms).padStart(3),
r.api['user:view'] === 200 ? ' ✅' : ' ❌',
String(r.api['roles']).padStart(3),
tabStr,
);
}
console.log(`${'='.repeat(60)}`);
console.log('✅ 测试完成');
await browser.close();
}
run().catch(e => { console.error('❌', e.message); process.exit(1); });