Files
aurak/check-result.mjs
Developer c57c3028e2 fix: shuffleArray bug + Playwright多轮对话测试 + 初学者考核脚本
- 修复 shuffleArray 返回新数组但调用处用 const 未接收返回值(3处)
- 新增 test-multiround.mjs Playwright 多轮对话测试(简答+追问全流程)
- 新增 do-assessment.mjs / check-result.mjs 考核体验脚本
- CLAUDE.md 增加 AI 工作流指令规则
- package.json 添加 playwright 依赖

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 22:34:04 +08:00

157 lines
6.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { chromium } from 'playwright';
const BASE = 'http://localhost:13001';
async function run() {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
// 登录
await page.goto(`${BASE}/login`, { waitUntil: 'networkidle' });
await page.waitForTimeout(1000);
await page.locator('input[type="text"]').first().fill('admin');
await page.locator('input[type="password"]').first().fill('admin123');
await page.locator('button[type="submit"]').click();
await page.waitForURL('**/');
// 进入考核页(首页会显示历史记录侧栏)
await page.goto(`${BASE}/assessment`, { waitUntil: 'networkidle' });
await page.waitForTimeout(3000);
// 截图1:首页(含历史记录侧栏)
await page.screenshot({ path: 'assessment-overview.png', fullPage: true });
console.log('📸 1/5 首页截图(含历史侧栏)保存');
// 看看历史记录里有什么
const historyInfo = await page.evaluate(() => {
const items = Array.from(document.querySelectorAll('.w-80 div.space-y-3 > div'));
return items.map(el => ({
text: (el.textContent || '').replace(/\s+/g, ' ').trim(),
}));
});
console.log('\n📋 历史记录:');
historyInfo.forEach((h, i) => console.log(` [${i+1}] ${h.text}`));
if (historyInfo.length === 0) {
console.log(' 没有历史记录,可能是空状态');
await browser.close();
return;
}
// 点击第一条历史记录查看详情(选分数最高的那条)
// 找分数最高的:解析数字
let bestIdx = 0;
let bestScore = -1;
historyInfo.forEach((h, i) => {
const m = h.text.match(/([\d.]+)\/10/);
if (m) {
const s = parseFloat(m[1]);
if (s > bestScore) { bestScore = s; bestIdx = i; }
}
});
console.log(`\n🔍 选择分数最高的记录 #${bestIdx+1} (${bestScore}/10)`);
// 历史记录在右侧边栏,每条记录最右边有个查看按钮(FileText图标)
const histButtons = page.locator('.w-80 div.space-y-3 > div button');
const btnCount = await histButtons.count();
console.log(` 右侧历史栏共有 ${btnCount} 个按钮`);
// 每条记录有2个按钮(删除+查看),查看按钮在最后
// 第N条记录的查看按钮索引 = (N * 2 + 1) (从0开始)
const viewBtnIdx = bestIdx * 2 + 1;
if (viewBtnIdx < btnCount) {
await histButtons.nth(viewBtnIdx).click();
await new Promise(r => setTimeout(r, 3000));
// 截图2:历史考核详情页
await page.screenshot({ path: 'assessment-history-detail.png', fullPage: true });
console.log('📸 2/5 考核详情页截图');
// 看看详情页有什么内容
const detailInfo = await page.evaluate(() => {
const body = document.body.textContent || '';
const scoreMatch = body.match(/([\d.]+)\/10/g);
const levelMatch = body.match(/(?:LEVEL|等级)[:]\s*(\w+)/i);
const reportSection = body.includes('综合报告') || body.includes('comprehensive');
const detailSection = body.includes('每题详情') || body.includes('details');
const hasPassed = body.includes('合格') || body.includes('VERIFIED');
// 按钮文字
const btns = Array.from(document.querySelectorAll('button'))
.map(b => (b.textContent || '').trim())
.filter(Boolean);
return { scores: scoreMatch, level: levelMatch?.[1], reportSection, detailSection, hasPassed, btns };
});
console.log(`\n📊 得分列表: ${detailInfo.scores?.join(', ') || '无'}`);
console.log(`🏆 等级: ${detailInfo.level || '未显示'}`);
console.log(`✅ 合格: ${detailInfo.hasPassed ? '是' : '否'}`);
console.log(`📋 每题详情: ${detailInfo.detailSection ? '✅ 有' : '❌ 无'}`);
console.log(`📝 综合报告: ${detailInfo.reportSection ? '✅ 有' : '❌ 无'}`);
console.log(`\n🔘 按钮列表:`);
detailInfo.btns.forEach(b => console.log(` - ${b}`));
// 找"查看证书"按钮
const certBtnText = detailInfo.btns.find(b =>
b.includes('证书') || b.includes('Certificate') || b.includes('certificate')
);
console.log(`\n🔖 证书按钮: ${certBtnText || '没找到'}`);
// 如果有证书按钮,点击它
if (certBtnText) {
const certBtn = page.locator('button', { hasText: /证书|Certificate|certificate/ });
if (await certBtn.isVisible().catch(() => false)) {
await certBtn.click();
await new Promise(r => setTimeout(r, 2000));
// 截图3:证书弹窗
await page.screenshot({ path: 'assessment-certificate-modal.png', fullPage: true });
console.log('📸 3/5 证书弹窗截图');
// 读取证书弹窗内容
const certData = await page.evaluate(() => {
// 找 portal(弹窗在 document.body 最下层)
const modal = document.querySelector('.fixed.inset-0.z-\\[1000\\]');
if (!modal) return { found: false };
const text = modal.textContent || '';
const level = text.match(/(\w+)/)?.[1] || '';
const totalScore = text.match(/([\d.]+)\/10/)?.[1] || '';
const dimScores = Array.from(text.matchAll(/(\w+)\s*([\d.]+)\/10/g))
.map(m => `${m[1]}: ${m[2]}/10`);
const questionCount = text.match(/题目列表[\s\S]*?#(\d+)/)?.[1] || '';
return {
found: true,
text: text.substring(0, 500),
level, totalScore, dimScores, questionCount,
};
});
if (certData.found) {
console.log(`\n📜 证书内容:`);
console.log(` 等级: ${certData.level}`);
console.log(` 总分: ${certData.totalScore}/10`);
console.log(` 维度得分: ${certData.dimScores.join(', ') || '无'}`);
console.log(` 题目数: ${certData.questionCount || '未知'}`);
}
// 关掉弹窗
await page.keyboard.press('Escape');
await new Promise(r => setTimeout(r, 500));
}
}
// 看 PDF 和 Excel 导出
const hasPdf = detailInfo.btns.some(b => b.includes('PDF'));
const hasExcel = detailInfo.btns.some(b => b.includes('Excel') || b.includes('excel'));
console.log(`\n📄 PDF下载: ${hasPdf ? '✅ 有' : '❌ 无'}`);
console.log(`📊 Excel导出: ${hasExcel ? '✅ 有' : '❌ 无'}`);
}
await browser.close();
console.log('\n=== 完成 ===');
}
run().catch(e => { console.error('❌', e.message); process.exit(1); });