CI/CD Pipeline / UI Contracts (source-structure gates) (push) Canceled after 0s
CI/CD Pipeline / E2E (live stack) (push) Canceled after 0s
CI/CD Pipeline / Backend Build & Test (push) Canceled after 0s
CI/CD Pipeline / Admin Web Build (push) Canceled after 0s
CI/CD Pipeline / Mini Program Compile Check (push) Canceled after 0s
CI/CD Pipeline / Migration Validation (push) Canceled after 0s
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Canceled after 0s
80 lines
4.8 KiB
JavaScript
80 lines
4.8 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { chromium } = require(process.env.PLAYWRIGHT_MODULE || 'C:/Users/13070/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright');
|
|
const base = process.env.DEMO_BASE_URL || 'http://localhost:6688';
|
|
const uuid = /[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}/i;
|
|
const code = /^[A-Z]{2}\d{11}$/;
|
|
const output = path.resolve(__dirname, '../.mimosa/public-id-page-evidence');
|
|
fs.mkdirSync(output, { recursive: true });
|
|
(async () => {
|
|
assert(process.env.DEMO_OPERATOR_PASSWORD, '请通过环境变量提供演示账号密码,不写入测试文件');
|
|
const browser = await chromium.launch({ channel: 'msedge', headless: true });
|
|
try {
|
|
const context = await browser.newContext({ viewport: { width: 1366, height: 768 } });
|
|
const page = await context.newPage();
|
|
const errors = [];
|
|
page.on('pageerror', error => errors.push(error.message));
|
|
await page.goto(`${base}/admin/login`);
|
|
await page.getByPlaceholder('请输入用户名').fill(process.env.DEMO_OPERATOR_USERNAME || 'demo_admin');
|
|
await page.locator('input[type=password]').fill(process.env.DEMO_OPERATOR_PASSWORD);
|
|
await page.getByRole('button', { name: '登录管理后台' }).click();
|
|
await page.waitForURL('**/admin/dashboard');
|
|
const endpoints = [
|
|
'/operator/users?page=1&pageSize=20', '/operator/operators', '/operator/activities',
|
|
'/operator/reviews/pending?page=1&pageSize=20', '/operator/risk/reports/pending',
|
|
'/operator/matchmaker/management/services', '/operator/matchmaker/recommendations',
|
|
'/service-appointments/operator/list', '/referrals/operator/history',
|
|
'/activities/operator/activity-interest-summary',
|
|
];
|
|
let checked = 0;
|
|
const results = [];
|
|
for (const endpoint of endpoints) {
|
|
const response = await context.request.get(`${base}/api/v1${endpoint}`);
|
|
assert(response.ok(), `${endpoint}: HTTP ${response.status()}`);
|
|
const body = await response.json();
|
|
assert(body.success, `${endpoint}: ${body.message}`);
|
|
function inspect(value) {
|
|
if (!value || typeof value !== 'object') return;
|
|
for (const [key, child] of Object.entries(value)) {
|
|
if (/DisplayId$|DisplayNumber$|^displayId$|^displayNumber$/.test(key) && child != null) {
|
|
assert(code.test(child), `${endpoint}: ${key} 格式错误`); checked++;
|
|
}
|
|
if (typeof child === 'object') inspect(child);
|
|
}
|
|
}
|
|
inspect(body.data);
|
|
results.push({ endpoint, status: response.status() });
|
|
}
|
|
assert(checked > 0, '接口没有可验收编号');
|
|
const pages = [
|
|
['users', '用户管理'], ['operators', '系统设置'], ['activities', '活动管理'],
|
|
['review', '资料审核'], ['risk/reports', '举报风控'], ['service-appointment', '服务预约'],
|
|
['referral', '公益红娘'], ['activities/interests', '匹配管理'], ['matchmaker', '红娘服务'],
|
|
];
|
|
for (const [route, label] of pages) {
|
|
await page.getByText(label, { exact: true }).first().click();
|
|
await page.waitForTimeout(300);
|
|
await page.waitForLoadState('networkidle');
|
|
assert(!page.url().includes('/login'), `${route}: 被退回登录`);
|
|
const text = await page.locator('body').innerText();
|
|
assert(!uuid.test(text), `${route}: 可见文本仍有 UUID`);
|
|
await page.screenshot({ path: path.join(output, `${route.replaceAll('/', '-')}-1366.png`), fullPage: true });
|
|
if (route === 'matchmaker') {
|
|
await page.getByRole('tab', { name: '联系授权审批' }).click();
|
|
await page.waitForLoadState('networkidle');
|
|
assert(!uuid.test(await page.locator('body').innerText()), '联系授权仍有 UUID');
|
|
await page.screenshot({ path: path.join(output, 'contact-authorization-1366.png'), fullPage: true });
|
|
await page.setViewportSize({ width: 1920, height: 1080 });
|
|
await page.screenshot({ path: path.join(output, 'contact-authorization-1920.png'), fullPage: true });
|
|
}
|
|
}
|
|
assert.equal(errors.length, 0, `页面运行错误: ${errors.join('; ')}`);
|
|
const anonymous = await browser.newContext();
|
|
const denied = await anonymous.request.get(`${base}/api/v1/operator/matchmaker/management/services`);
|
|
assert([401, 403].includes(denied.status()), '未登录不应读取管理服务');
|
|
fs.writeFileSync(path.join(output, 'results.json'), JSON.stringify({ results, checkedDisplayFields: checked, pages: 10, anonymousStatus: denied.status(), errors }, null, 2));
|
|
console.log(`PASS: ${results.length} 类真实接口、${checked} 个展示字段、10 个页面/区域、匿名访问拒绝;截图已保存。`);
|
|
} finally { await browser.close(); }
|
|
})().catch(error => { console.error(error.message); process.exitCode = 1; });
|