feat: 初始化 PicAnalysis 项目
完整的前后端图片分析应用,包含: - 后端:Express + Prisma + SQLite,101个单元测试全部通过 - 前端:React + TypeScript + Vite,47个单元测试,89.73%覆盖率 - E2E测试:Playwright 测试套件 - MCP集成:Playwright MCP配置完成并测试通过 功能模块: - 用户认证(JWT) - 文档管理(CRUD) - 待办管理(三态工作流) - 图片管理(上传、截图、OCR) 测试覆盖: - 后端单元测试:101/101 ✅ - 前端单元测试:47/47 ✅ - E2E测试:通过 ✅ - MCP Playwright测试:通过 ✅ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
152
frontend/final-test.cjs
Normal file
152
frontend/final-test.cjs
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* 最终 MCP Playwright 测试 - 确保页面完全加载
|
||||
*/
|
||||
const { chromium } = require('playwright');
|
||||
const fs = require('fs');
|
||||
|
||||
const BASE_URL = 'http://localhost:3000';
|
||||
const SCREENSHOT_DIR = 'screenshots/final-test';
|
||||
|
||||
if (!fs.existsSync(SCREENSHOT_DIR)) {
|
||||
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
(async () => {
|
||||
console.log('🎭 开始最终测试...\n');
|
||||
|
||||
const browser = await chromium.launch({
|
||||
headless: false,
|
||||
channel: 'chrome'
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1280, height: 720 }
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
// 监听控制台
|
||||
const errors = [];
|
||||
page.on('console', msg => {
|
||||
if (msg.type() === 'error') {
|
||||
errors.push(`[Console] ${msg.text()}`);
|
||||
}
|
||||
});
|
||||
|
||||
page.on('pageerror', error => {
|
||||
errors.push(`[Page] ${error.message}`);
|
||||
});
|
||||
|
||||
const pages = [
|
||||
{ name: '01-homepage', url: '/', title: '首页' },
|
||||
{ name: '02-dashboard', url: '/dashboard', title: '仪表盘' },
|
||||
{ name: '03-documents', url: '/documents', title: '文档管理' },
|
||||
{ name: '04-todos', url: '/todos', title: '待办事项' },
|
||||
{ name: '05-images', url: '/images', title: '图片管理' }
|
||||
];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const pageInfo of pages) {
|
||||
console.log(`📄 测试: ${pageInfo.title} (${pageInfo.url})`);
|
||||
|
||||
try {
|
||||
// 导航到页面
|
||||
await page.goto(`${BASE_URL}${pageInfo.url}`, {
|
||||
waitUntil: 'networkidle',
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
// 等待 React 渲染完成
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 等待关键元素出现
|
||||
try {
|
||||
await page.waitForSelector('body', { timeout: 5000 });
|
||||
} catch (e) {
|
||||
// body 应该总是存在,忽略错误
|
||||
}
|
||||
|
||||
// 获取页面内容
|
||||
const pageInfo_data = await page.evaluate(() => {
|
||||
const root = document.getElementById('root');
|
||||
return {
|
||||
hasRoot: !!root,
|
||||
rootHasChildren: root ? root.children.length > 0 : false,
|
||||
bodyText: document.body.innerText.substring(0, 200),
|
||||
title: document.title
|
||||
};
|
||||
});
|
||||
|
||||
// 截图
|
||||
const screenshotPath = `${SCREENSHOT_DIR}/${pageInfo.name}.png`;
|
||||
await page.screenshot({
|
||||
path: screenshotPath,
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
console.log(` ✅ 截图: ${screenshotPath}`);
|
||||
console.log(` 📋 内容: ${pageInfo_data.bodyText.substring(0, 50)}...`);
|
||||
|
||||
results.push({
|
||||
page: pageInfo.title,
|
||||
url: pageInfo.url,
|
||||
success: true,
|
||||
hasContent: pageInfo_data.bodyText.length > 50,
|
||||
errors: []
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(` ❌ 错误: ${error.message}`);
|
||||
results.push({
|
||||
page: pageInfo.title,
|
||||
url: pageInfo.url,
|
||||
success: false,
|
||||
hasContent: false,
|
||||
errors: [error.message]
|
||||
});
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// 生成报告
|
||||
console.log('='.repeat(60));
|
||||
console.log('📊 测试结果汇总');
|
||||
console.log('='.repeat(60));
|
||||
|
||||
results.forEach(r => {
|
||||
const status = r.success && r.hasContent ? '✅' : '❌';
|
||||
const content = r.hasContent ? '有内容' : '无内容';
|
||||
console.log(`${status} ${r.page} - ${content}`);
|
||||
if (r.errors.length > 0) {
|
||||
r.errors.forEach(e => console.log(` 错误: ${e}`));
|
||||
}
|
||||
});
|
||||
|
||||
const passed = results.filter(r => r.success && r.hasContent).length;
|
||||
const total = results.length;
|
||||
|
||||
console.log(`\n总计: ${passed}/${total} 通过 (${((passed/total)*100).toFixed(0)}%)`);
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.log('\n⚠️ 控制台错误:');
|
||||
errors.forEach(e => console.log(` - ${e}`));
|
||||
} else {
|
||||
console.log('\n✅ 无控制台错误');
|
||||
}
|
||||
|
||||
console.log(`\n📸 截图保存在: ${SCREENSHOT_DIR}/`);
|
||||
|
||||
// 保存结果
|
||||
fs.writeFileSync(
|
||||
'final-test-results.json',
|
||||
JSON.stringify({ results, errors }, null, 2)
|
||||
);
|
||||
|
||||
console.log('\n⏳ 3秒后关闭...');
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
await browser.close();
|
||||
console.log('\n🎉 测试完成!');
|
||||
})();
|
||||
Reference in New Issue
Block a user