const { chromium } = require('playwright-core'); const fs = require('fs'); const path = require('path'); const SHOTS = 'D:/AI/jiaoyu/_shots'; if (!fs.existsSync(SHOTS)) fs.mkdirSync(SHOTS, { recursive: true }); (async () => { const browser = await chromium.launch({ channel: 'chrome', headless: true, executablePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' }); const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } }); const page = await ctx.newPage(); const allErrors = []; page.on('pageerror', e => allErrors.push('PAGE: ' + e.message)); page.on('console', m => { if (m.type() === 'error') { const t = m.text(); if (!t.includes('favicon') && !t.includes('404')) allErrors.push('CON: ' + t.slice(0,150)); } }); // Login const loginResp = await page.request.post('http://localhost:8000/api/auth/login', { data: { phone: '13943441149', password: 'Test1234' } }); const { access_token } = await loginResp.json(); const pages = [ { name: 'home', url: 'http://localhost:5174/', wait: 2500 }, { name: 'courseware-create', url: 'http://localhost:5174/courseware/create', wait: 2000 }, { name: 'animation', url: 'http://localhost:5174/animation', wait: 2000 }, { name: 'exercise', url: 'http://localhost:5174/exercise', wait: 2000 }, { name: 'lesson-plan', url: 'http://localhost:5174/lesson-plan', wait: 2000 }, { name: 'exam', url: 'http://localhost:5174/exam', wait: 2000 }, { name: 'essay-grade', url: 'http://localhost:5174/essay-grade', wait: 2000 }, { name: 'mindmap', url: 'http://localhost:5174/mindmap', wait: 2000 }, { name: 'resources', url: 'http://localhost:5174/resources', wait: 2000 }, { name: 'community', url: 'http://localhost:5174/community', wait: 2000 }, { name: 'classroom', url: 'http://localhost:5174/classroom', wait: 2000 }, { name: 'materials', url: 'http://localhost:5174/materials', wait: 2000 }, { name: 'profile', url: 'http://localhost:5174/profile', wait: 2000 }, { name: 'search', url: 'http://localhost:5174/search?q=数学', wait: 2000 }, { name: 'assistant', url: 'http://localhost:5174/assistant', wait: 2000 }, ]; const results = []; for (const p of pages) { const errorsBefore = allErrors.length; await page.goto(p.url, { waitUntil: 'networkidle', timeout: 15000 }).catch(() => {}); // Inject token on first navigation if (p.name === 'home') { await page.evaluate((t) => { localStorage.setItem('access_token', t); localStorage.setItem('refresh_token', t); }, access_token); await page.reload({ waitUntil: 'networkidle' }); } await page.waitForTimeout(p.wait); await page.screenshot({ path: path.join(SHOTS, p.name + '.png'), fullPage: false }); const bodyLen = await page.evaluate(() => document.body.innerText.length); const h1 = await page.locator('h1, h2, .page-title, .tpl-title').first().textContent().catch(() => ''); const newErrors = allErrors.slice(errorsBefore); results.push({ name: p.name, bodyLen, title: h1.trim().slice(0,40), errors: newErrors.length }); console.log('[' + p.name + '] bodyLen=' + bodyLen + ' title="' + h1.trim().slice(0,35) + '" errors=' + newErrors.length); if (newErrors.length) newErrors.slice(0,2).forEach(e => console.log(' ' + e)); } console.log('\n=== Summary ==='); console.log('Total pages:', results.length); console.log('Total errors:', allErrors.length); const small = results.filter(r => r.bodyLen < 200); console.log('Pages with thin content (<200 chars):', small.length); small.forEach(r => console.log(' ' + r.name + ': ' + r.bodyLen + ' chars')); await browser.close(); })().catch(e => { console.error('FATAL', e.message); process.exit(1); });