Files
PicAnalysis/frontend/mcp-full-test.cjs
wjl 1a0ebde95d 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>
2026-02-22 20:10:11 +08:00

321 lines
8.8 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
/**
* MCP Playwright 完整测试
* 测试所有页面并检查:
* 1. 页面加载正常
* 2. 控制台无错误
* 3. UI 展示正常
* 4. 基本功能可用
*/
const { chromium } = require('playwright');
const fs = require('fs');
// 测试配置
const BASE_URL = 'http://localhost:3000';
const SCREENSHOT_DIR = 'screenshots/mcp-full-test';
const TEST_USER = {
username: 'testuser',
password: 'Password123@'
};
// 创建截图目录
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
// 测试结果收集
const testResults = {
timestamp: new Date().toISOString(),
pages: [],
summary: {
total: 0,
passed: 0,
failed: 0,
errors: []
}
};
/**
* 测试单个页面
*/
async function testPage(page, pageInfo) {
const pageResult = {
name: pageInfo.name,
url: pageInfo.url,
passed: true,
errors: [],
warnings: [],
screenshots: []
};
console.log(`\n📄 测试页面: ${pageInfo.name}`);
console.log(` URL: ${pageInfo.url}`);
try {
// 监听控制台消息
const consoleMessages = [];
page.on('console', msg => {
const type = msg.type();
const text = msg.text();
if (type === 'error') {
consoleMessages.push({ type, text });
pageResult.errors.push(`[Console Error] ${text}`);
} else if (type === 'warning') {
pageResult.warnings.push(`[Console Warning] ${text}`);
}
});
// 监听页面错误
const pageErrors = [];
page.on('pageerror', error => {
pageErrors.push(error.toString());
pageResult.errors.push(`[Page Error] ${error.message}`);
});
// 导航到页面
console.log(` ⏳ 正在加载页面...`);
await page.goto(pageInfo.url, {
waitUntil: 'networkidle',
timeout: 30000
});
// 等待页面稳定
await page.waitForTimeout(2000);
// 检查页面标题
const title = await page.title();
console.log(` 📋 页面标题: ${title}`);
// 截图 - 完整页面
const fullScreenshot = `${SCREENSHOT_DIR}/${pageInfo.name}-full.png`;
await page.screenshot({
path: fullScreenshot,
fullPage: true
});
pageResult.screenshots.push(fullScreenshot);
console.log(` 📸 完整截图: ${fullScreenshot}`);
// 截图 - 视口
const viewportScreenshot = `${SCREENSHOT_DIR}/${pageInfo.name}-viewport.png`;
await page.screenshot({
path: viewportScreenshot,
fullPage: false
});
pageResult.screenshots.push(viewportScreenshot);
// 检查页面基本信息
const bodyText = await page.evaluate(() => document.body.innerText);
const hasContent = bodyText.length > 100;
console.log(` 📝 内容长度: ${bodyText.length} 字符`);
if (!hasContent) {
pageResult.errors.push('页面内容过少,可能未正常加载');
pageResult.passed = false;
}
// 检查是否有死链
const brokenLinks = await page.evaluate(() => {
const links = Array.from(document.querySelectorAll('a[href]'));
return links.filter(link => {
const href = link.getAttribute('href');
return href && href.startsWith('http') && !href.includes(window.location.hostname);
}).length;
});
if (brokenLinks > 0) {
pageResult.warnings.push(`发现 ${brokenLinks} 个外部链接`);
}
// 检查响应式设计
const mobileViewport = { width: 375, height: 667 };
await page.setViewportSize(mobileViewport);
await page.waitForTimeout(500);
const mobileScreenshot = `${SCREENSHOT_DIR}/${pageInfo.name}-mobile.png`;
await page.screenshot({ path: mobileScreenshot });
pageResult.screenshots.push(mobileScreenshot);
console.log(` 📱 移动端截图: ${mobileScreenshot}`);
// 恢复桌面视口
await page.setViewportSize({ width: 1280, height: 720 });
// 执行页面特定测试
if (pageInfo.test) {
console.log(` 🔧 执行页面特定测试...`);
await pageInfo.test(page, pageResult);
}
// 统计错误
if (pageResult.errors.length > 0) {
pageResult.passed = false;
console.log(` ❌ 发现 ${pageResult.errors.length} 个错误:`);
pageResult.errors.forEach(err => console.log(` - ${err}`));
}
if (pageResult.warnings.length > 0) {
console.log(` ⚠️ 发现 ${pageResult.warnings.length} 个警告:`);
pageResult.warnings.slice(0, 3).forEach(warn => console.log(` - ${warn}`));
}
if (pageResult.passed) {
console.log(` ✅ 页面测试通过`);
} else {
console.log(` ❌ 页面测试失败`);
}
} catch (error) {
pageResult.passed = false;
pageResult.errors.push(`测试异常: ${error.message}`);
console.log(` ❌ 测试失败: ${error.message}`);
}
return pageResult;
}
/**
* 主测试流程
*/
async function runTests() {
console.log('🎭 MCP Playwright 完整测试开始');
console.log('='.repeat(60));
console.log(`基础URL: ${BASE_URL}`);
console.log(`截图目录: ${SCREENSHOT_DIR}`);
console.log('='.repeat(60));
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 pagesToTest = [
{
name: '01-homepage',
url: `${BASE_URL}/`,
description: '首页/登录页'
},
{
name: '02-dashboard',
url: `${BASE_URL}/dashboard`,
description: '仪表盘'
},
{
name: '03-documents',
url: `${BASE_URL}/documents`,
description: '文档管理'
},
{
name: '04-todos',
url: `${BASE_URL}/todos`,
description: '待办事项'
},
{
name: '05-images',
url: `${BASE_URL}/images`,
description: '图片管理'
}
];
// 首先尝试登录
console.log('\n🔐 尝试登录...');
try {
await page.goto(`${BASE_URL}/`, { waitUntil: 'networkidle' });
await page.waitForTimeout(1000);
// 查找并填写登录表单
const usernameInput = page.locator('input[type="text"]').first();
const passwordInput = page.locator('input[type="password"]').first();
const loginButton = page.locator('button').filter({ hasText: /登录|Login/i }).first();
if (await usernameInput.count() > 0 && await passwordInput.count() > 0) {
await usernameInput.fill(TEST_USER.username);
await passwordInput.fill(TEST_USER.password);
if (await loginButton.count() > 0) {
await loginButton.click();
console.log(' ✅ 登录表单已提交');
await page.waitForTimeout(2000);
} else {
console.log(' ⚠️ 未找到登录按钮');
}
} else {
console.log(' 未找到登录表单,可能已经登录');
}
} catch (error) {
console.log(` ⚠️ 登录过程异常: ${error.message}`);
}
// 测试每个页面
for (const pageInfo of pagesToTest) {
const result = await testPage(page, pageInfo);
testResults.pages.push(result);
testResults.summary.total++;
if (result.passed) {
testResults.summary.passed++;
} else {
testResults.summary.failed++;
testResults.summary.errors.push(...result.errors);
}
// 页面间等待
await page.waitForTimeout(1000);
}
// 生成测试报告
console.log('\n' + '='.repeat(60));
console.log('📊 测试汇总');
console.log('='.repeat(60));
testResults.pages.forEach(page => {
const status = page.passed ? '✅' : '❌';
console.log(`${status} ${page.name} - ${page.errors.length} 错误, ${page.warnings.length} 警告`);
});
console.log('\n总计:');
console.log(` 总页面数: ${testResults.summary.total}`);
console.log(` 通过: ${testResults.summary.passed}`);
console.log(` 失败: ${testResults.summary.failed}`);
console.log(` 通过率: ${((testResults.summary.passed / testResults.summary.total) * 100).toFixed(1)}%`);
if (testResults.summary.errors.length > 0) {
console.log('\n⚠ 所有错误:');
testResults.summary.errors.forEach((err, i) => {
console.log(` ${i + 1}. ${err}`);
});
}
console.log('\n📸 所有截图保存在:', SCREENSHOT_DIR);
// 保存测试结果
const resultsPath = 'test-results.json';
fs.writeFileSync(resultsPath, JSON.stringify(testResults, null, 2));
console.log('📄 测试结果已保存到:', resultsPath);
// 等待用户查看
console.log('\n⏳ 5秒后关闭浏览器...');
await page.waitForTimeout(5000);
await browser.close();
console.log('\n🎉 测试完成!');
return testResults;
}
// 运行测试
runTests()
.then(results => {
const exitCode = results.summary.failed > 0 ? 1 : 0;
process.exit(exitCode);
})
.catch(error => {
console.error('❌ 测试运行失败:', error);
process.exit(1);
});