168 lines
7.4 KiB
JavaScript
168 lines
7.4 KiB
JavaScript
const { chromium, request } = require('/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/node_modules/playwright');
|
|
|
|
const FRONTEND = process.env.LEAUDIT_FRONTEND_URL || 'http://172.16.0.59:5173';
|
|
const BACKEND = process.env.LEAUDIT_BACKEND_URL || 'http://127.0.0.1:8096';
|
|
const runId = `pwr${Date.now()}`;
|
|
const results = [];
|
|
|
|
function record(name, ok, details = {}) {
|
|
results.push({ name, ok, details });
|
|
console.log(`[${ok ? 'PASS' : 'FAIL'}] ${name}: ${JSON.stringify(details)}`);
|
|
if (!ok) throw new Error(`${name}: ${JSON.stringify(details)}`);
|
|
}
|
|
|
|
async function asJson(response) {
|
|
try {
|
|
return await response.json();
|
|
} catch {
|
|
return { text: await response.text() };
|
|
}
|
|
}
|
|
|
|
function unwrap(payload) {
|
|
if (payload && typeof payload === 'object' && Object.prototype.hasOwnProperty.call(payload, 'data')) {
|
|
return payload.data;
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
async function apiFetch(api, method, path, token, options = {}) {
|
|
const headers = { ...(options.headers || {}) };
|
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
const response = await api.fetch(`${BACKEND}${path}`, { method, ...options, headers });
|
|
return { response, body: await asJson(response) };
|
|
}
|
|
|
|
async function loginFrontendContext(browser) {
|
|
const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } });
|
|
const loginResponse = await context.request.post(`${FRONTEND}/api/auth/password-login`, {
|
|
data: { username: '000', password: 'admin06111' },
|
|
});
|
|
const loginBody = await asJson(loginResponse);
|
|
if (!loginResponse.ok() || !loginBody?.access_token) {
|
|
throw new Error(`前端登录失败 ${loginResponse.status()} ${JSON.stringify(loginBody)}`);
|
|
}
|
|
return { context, token: loginBody.access_token };
|
|
}
|
|
|
|
async function createEntryModule(api, token) {
|
|
const payload = {
|
|
name: `PW验收政务入口-${runId}`,
|
|
description: 'playwright remaining acceptance',
|
|
path: '/govdoc/audits',
|
|
route_path: '/govdoc/audits',
|
|
menu_profile: 'govdoc',
|
|
features: ['home', 'govdoc_audits', 'govdoc_upload', 'rule_groups'],
|
|
tenants: [{ tenant_code: 'PUBLIC', tenant_name: '公共资源域', enabled: true, sort_order: 1 }],
|
|
};
|
|
const { response, body } = await apiFetch(api, 'POST', '/api/v3/entry-modules', token, { data: payload });
|
|
record('创建名字不含公文的 govdoc 入口成功', response.status() === 200, { status: response.status(), body });
|
|
const module = unwrap(body);
|
|
record('govdoc 入口保存 menu_profile/features', module.menu_profile === 'govdoc' && module.features?.includes('govdoc_audits'), module);
|
|
return module;
|
|
}
|
|
|
|
async function createDocType(api, token, moduleId) {
|
|
const payload = {
|
|
code: `pw.remaining.${runId}`,
|
|
name: `PW验收文档类型-${runId}`,
|
|
description: 'playwright remaining acceptance',
|
|
entryModuleId: Number(moduleId),
|
|
isEnabled: true,
|
|
sortOrder: 1,
|
|
ruleSetIds: [],
|
|
};
|
|
const { response, body } = await apiFetch(api, 'POST', '/api/document-types', token, { data: payload });
|
|
record('为验收入口创建文档类型成功', response.status() === 200, { status: response.status(), body });
|
|
return unwrap(body);
|
|
}
|
|
|
|
async function sidebarTexts(page) {
|
|
return await page.locator('.sidebar a.sidebar-menu-item').evaluateAll((els) => (
|
|
els.map((el) => (el.textContent || '').replace(/\s+/g, ' ').trim()).filter(Boolean)
|
|
));
|
|
}
|
|
|
|
async function createCommonUserToken(api, adminToken) {
|
|
const sub = `pw-no-image-${runId}`;
|
|
const login = await apiFetch(api, 'POST', '/api/auth/login', null, {
|
|
data: {
|
|
userInfo: {
|
|
sub,
|
|
username: sub,
|
|
nickname: `PW无图标权限-${runId}`,
|
|
email: `${sub}@playwright.local`,
|
|
phone_number: '13800000000',
|
|
ou_id: 'pw-no-image',
|
|
ou_name: 'Playwright验收组织',
|
|
is_leader: false,
|
|
},
|
|
area: '公共资源域',
|
|
expiresIn: 3600,
|
|
},
|
|
});
|
|
record('创建无图标权限测试用户登录成功', login.response.status() === 200, { status: login.response.status(), body: login.body });
|
|
const loginData = unwrap(login.body);
|
|
const userId = Number(loginData.user_info?.user_id);
|
|
|
|
const roles = await apiFetch(api, 'GET', '/api/v3/rbac/roles?page=1&page_size=200', adminToken);
|
|
const roleItems = unwrap(roles.body)?.items || [];
|
|
const commonRole = roleItems.find((item) => item.role_key === 'common');
|
|
record('找到 common 角色用于无权限验收', Boolean(commonRole?.id), { commonRole });
|
|
|
|
const assign = await apiFetch(api, 'POST', `/api/v3/rbac/users/${userId}/roles`, adminToken, {
|
|
data: { role_ids: [Number(commonRole.id)] },
|
|
});
|
|
record('无图标权限测试用户分配 common 角色成功', assign.response.status() === 200, { status: assign.response.status(), body: assign.body });
|
|
return loginData.access_token;
|
|
}
|
|
|
|
async function main() {
|
|
const browser = await chromium.launch({ headless: true });
|
|
const { context, token } = await loginFrontendContext(browser);
|
|
const api = await request.newContext();
|
|
const page = await context.newPage();
|
|
|
|
const module = await createEntryModule(api, token);
|
|
await createDocType(api, token, module.id);
|
|
|
|
await page.goto(`${FRONTEND}/`, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
await page.waitForLoadState('networkidle', { timeout: 20000 }).catch(() => {});
|
|
await page.getByRole('button', { name: module.name, exact: true }).click({ timeout: 15000 });
|
|
await page.waitForURL((url) => url.pathname === '/govdoc/audits' && url.searchParams.get('entryModuleId') === String(module.id), { timeout: 15000 });
|
|
await page.waitForLoadState('networkidle', { timeout: 20000 }).catch(() => {});
|
|
await page.waitForTimeout(1200);
|
|
|
|
const side = await sidebarTexts(page);
|
|
const headingText = await page.locator('.govdoc-audit-scope h2').first().textContent({ timeout: 10000 });
|
|
const storage = await page.evaluate(() => JSON.parse(sessionStorage.getItem('selectedEntryModuleContext') || 'null'));
|
|
|
|
record('公文入口标题使用当前入口模块名称', headingText === `${module.name}文档列表`, { headingText, expected: `${module.name}文档列表` });
|
|
record('公文入口上下文保存为 govdoc', storage?.menuProfile === 'govdoc' && Number(storage?.id) === Number(module.id), storage);
|
|
record('govdoc 侧栏显示公文列表/公文上传/规则分组', ['公文列表', '公文上传', '规则分组'].every((text) => side.includes(text)), { side });
|
|
record('govdoc 侧栏不显示普通文件上传/文档列表', !side.includes('文件上传') && !side.includes('文档列表'), { side });
|
|
|
|
const commonToken = await createCommonUserToken(api, token);
|
|
const image403 = await apiFetch(api, 'POST', `/api/v3/entry-modules/${module.id}/image`, commonToken, {
|
|
multipart: {
|
|
file: {
|
|
name: 'entry-module.png',
|
|
mimeType: 'image/png',
|
|
buffer: Buffer.from('89504e470d0a1a0a', 'hex'),
|
|
},
|
|
},
|
|
});
|
|
record('无 entry_module:image:write 用户上传入口图标返回 403', image403.response.status() === 403, { status: image403.response.status(), body: image403.body });
|
|
|
|
await api.dispose();
|
|
await context.close();
|
|
await browser.close();
|
|
console.log('\nSUMMARY ' + JSON.stringify({ runId, pass: results.filter((r) => r.ok).length, fail: results.filter((r) => !r.ok).length, results }, null, 2));
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('\nERROR', err);
|
|
console.log('\nSUMMARY ' + JSON.stringify({ runId, pass: results.filter((r) => r.ok).length, fail: results.filter((r) => !r.ok).length, results }, null, 2));
|
|
process.exit(1);
|
|
});
|