| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- import assert from 'node:assert/strict';
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
- import { chromium } from 'playwright';
- // 使用真实会话撤销和独立 HTTP 配额修改检查草稿恢复,生成模型调用次数为 0。
- const credentials = JSON.parse(await readFile(new URL('../../.work/platform-accounts.json', import.meta.url), 'utf8'));
- const base = (process.env.FRONTEND_URL || 'http://127.0.0.1:18762').replace(/\/$/, '');
- const browser = await chromium.launch({ headless: true, executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE || 'C:/Users/Administrator/AppData/Local/ms-playwright/chromium-1228/chrome-win64/chrome.exe' });
- const page = await browser.newPage();
- page.setDefaultTimeout(15000);
- const errors = [];
- page.on('pageerror', error => errors.push(error.message));
- const content = page.locator('.platform-pages');
- const panel = page.locator('.login-panel');
- const navigation = page.getByRole('navigation', { name: '系统导航' });
- const checks = [];
- let externalToken;
- async function login() {
- await panel.getByLabel('员工账户', { exact: true }).fill(credentials.username);
- await panel.getByLabel('密码', { exact: true }).fill(credentials.password);
- const response = page.waitForResponse(item => item.url().endsWith('/platform/auth/sessions') && item.request().method() === 'POST');
- await panel.getByRole('button', { name: '登录', exact: true }).click();
- const authenticated = await response;
- assert.equal(authenticated.status(), 200);
- await panel.waitFor({ state: 'hidden' });
- await content.getByRole('status').waitFor({ state: 'hidden' });
- return (await authenticated.json()).access_token;
- }
- async function open(name, field) {
- await navigation.getByRole('button', { name, exact: true }).click();
- await content.getByLabel(field, { exact: true }).waitFor();
- }
- async function call(method, path, body, token) {
- const response = await page.context().request.fetch(`${base}/openapi/v1/platform${path}`, {
- method, data: body,
- headers: { Authorization: `Bearer ${token}`, 'Idempotency-Key': crypto.randomUUID() },
- });
- assert.ok(response.ok(), `${method} ${path}: ${response.status()}`);
- return response.status() === 204 ? null : response.json();
- }
- try {
- await page.goto(`${base}/#/platform/tenants`);
- const token = await login();
- const name = `平台会话验证 ${Date.now()}`;
- const tenant = await call('POST', '/tenants', { name, contact: '平台功能检查' }, token);
- await open('配额管理', '修改原因');
- await content.locator('.el-select__wrapper').click();
- await page.getByRole('option', { name, exact: true }).click();
- await content.getByLabel('交互并发上限', { exact: true }).fill('3');
- await content.getByLabel('后台并发上限', { exact: true }).fill('1');
- await content.getByLabel('每日 token 上限', { exact: true }).fill('3000');
- await content.getByLabel('修改原因', { exact: true }).fill('待本人检查的额度草稿');
- await open('商家管理', '商家名称');
- await content.getByLabel('商家名称', { exact: true }).fill('尚未提交的商家名称');
- await content.getByLabel('接入负责人', { exact: true }).fill('尚未提交的负责人');
- await call('DELETE', '/auth/sessions/current', undefined, token);
- await navigation.getByRole('button', { name: '配额管理', exact: true }).click();
- await panel.waitFor();
- assert.equal(await navigation.count(), 0);
- checks.push('服务端撤销平台会话后隐藏管理内容并要求登录');
- const externalLogin = await page.context().request.post(`${base}/openapi/v1/platform/auth/sessions`, {
- data: { username: credentials.username, password: credentials.password },
- });
- assert.equal(externalLogin.status(), 200);
- externalToken = (await externalLogin.json()).access_token;
- const previous = (await call('GET', '/state', undefined, externalToken)).capacity[tenant.id];
- const updated = await call('PUT', `/tenants/${tenant.id}/capacity`, {
- interactive: 2, reserved: 0, background: 0, tokens: 1200, reason: '独立请求更新配置版本',
- expected_version: previous.version, expected_token_version: previous.tokenVersion,
- }, externalToken);
- const writes = [];
- page.on('request', request => {
- if (request.method() === 'PUT' && request.url().endsWith(`/tenants/${tenant.id}/capacity`)) writes.push(request.postDataJSON());
- });
- await login();
- await content.getByLabel('修改原因', { exact: true }).waitFor();
- assert.equal(await content.getByLabel('交互并发上限', { exact: true }).inputValue(), '3');
- assert.equal(await content.getByLabel('每日 token 上限', { exact: true }).inputValue(), '3000');
- assert.equal(await content.getByLabel('修改原因', { exact: true }).inputValue(), '待本人检查的额度草稿');
- assert.equal(writes.length, 0);
- checks.push('同身份登录保留额度草稿且没有自动提交');
- await open('商家管理', '商家名称');
- assert.equal(await content.getByLabel('商家名称', { exact: true }).inputValue(), '尚未提交的商家名称');
- assert.equal(await content.getByLabel('接入负责人', { exact: true }).inputValue(), '尚未提交的负责人');
- checks.push('同身份登录恢复商家登记草稿');
- await open('配额管理', '修改原因');
- const saved = page.waitForResponse(response => response.request().method() === 'PUT' && response.url().endsWith(`/tenants/${tenant.id}/capacity`));
- await content.getByRole('button', { name: '检查并保存额度', exact: true }).click();
- assert.equal((await saved).status(), 200);
- assert.equal(writes.length, 1);
- assert.equal(writes[0].expected_version, updated.version);
- assert.equal(writes[0].expected_token_version, updated.tokenVersion);
- await content.getByLabel('修改原因', { exact: true }).waitFor();
- const persisted = (await call('GET', '/state', undefined, externalToken)).capacity[tenant.id];
- assert.equal(persisted.tokens, 3000);
- assert.equal(persisted.interactive, 3);
- checks.push('本人再次提交使用重新读取的配置版本并保存真实数据');
- await page.getByRole('button', { name: '退出登录', exact: true }).click();
- await page.getByRole('dialog').getByRole('button', { name: '确认操作', exact: true }).click();
- await panel.waitFor();
- await login();
- await open('商家管理', '商家名称');
- assert.equal(await content.getByLabel('商家名称', { exact: true }).inputValue(), '');
- assert.equal(await content.getByLabel('接入负责人', { exact: true }).inputValue(), '');
- checks.push('主动退出清理平台未提交草稿');
- assert.deepEqual(errors, []);
- await mkdir(new URL('../../.work/frontend-verification/', import.meta.url), { recursive: true });
- await writeFile(new URL('../../.work/frontend-verification/platform-session.json', import.meta.url), JSON.stringify({ date: new Date().toISOString(), checks, browserErrors: errors, generatedModelCalls: 0 }, null, 2));
- console.log(JSON.stringify({ checks, browserErrors: errors.length, generatedModelCalls: 0 }, null, 2));
- } finally {
- if (externalToken) await call('DELETE', '/auth/sessions/current', undefined, externalToken);
- await browser.close();
- }
|