You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

251 lines
7.6 KiB

/**
* Playwright MCP 测试执行器
*
* 此文件提供便捷的测试执行函数,可通过 Claude 调用 MCP 工具执行测试
*
* 使用方法:
* 1. 在 Claude 中说 "执行全部 Playwright 测试"
* 2. Claude 会调用此文件中的函数
*/
import { TEST_CONFIG, ROUTES } from './config';
// 测试模块定义
interface TestCase {
name: string;
description: string;
action: () => Promise<void>;
}
interface TestModule {
name: string;
description: string;
tests: TestCase[];
}
// 测试结果
interface TestResult {
module: string;
test: string;
passed: boolean;
error?: string;
duration: number;
}
/**
* 测试执行器类
*/
class MCPTestExecutor {
private results: TestResult[] = [];
private startTime: number = 0;
/**
* 执行所有测试
*/
async runAllTests(): Promise<TestResult[]> {
this.results = [];
this.startTime = Date.now();
console.log('🚀 Playwright MCP 完整测试套件\n');
console.log(`📅 ${new Date().toLocaleString()}`);
console.log(`🎯 目标: ${TEST_CONFIG.baseURL}`);
console.log('');
// 定义测试模块(按执行顺序)
const modules = [
{ name: '登录测试', fn: this.runLoginTests },
{ name: '导航测试', fn: this.runNavigationTests },
{ name: '仪表板测试', fn: this.runDashboardTests },
{ name: '用户管理测试', fn: this.runUserTests },
{ name: '设置页面测试', fn: this.runSettingsTests },
];
for (const module of modules) {
console.log(`\n📦 ${module.name}`);
console.log('─'.repeat(50));
try {
await module.fn.call(this);
} catch (error) {
console.error(`${module.name} 执行失败:`, error);
}
}
this.printSummary();
return this.results;
}
/**
* 登录测试
*/
private async runLoginTests(): Promise<void> {
const tests = [
{ name: '访问登录页面', action: 'navigate', url: `${TEST_CONFIG.baseURL}${ROUTES.login}` },
{ name: '验证页面结构', action: 'snapshot', check: ['BASE', '管理面板登录', '邮箱地址'] },
{ name: '测试错误登录', action: 'login', email: 'wrong@test.com', password: 'wrong', expectError: true },
{ name: '测试正确登录', action: 'login', email: TEST_CONFIG.testUser.email, password: TEST_CONFIG.testUser.password },
];
for (const test of tests) {
await this.executeTest('登录测试', test.name, async () => {
console.log(` 📝 ${test.name}`);
// 实际测试逻辑由 Claude 通过 MCP 工具执行
await this.simulateTestAction(test);
});
}
}
/**
* 导航测试
*/
private async runNavigationTests(): Promise<void> {
const tests = [
{ name: '验证侧边栏导航', action: 'checkSidebar' },
{ name: '测试页面跳转', action: 'navigate', routes: [ROUTES.dashboard, ROUTES.users, ROUTES.settings] },
{ name: '测试路由保护', action: 'checkAuthGuard' },
{ name: '测试退出登录', action: 'logout' },
];
for (const test of tests) {
await this.executeTest('导航测试', test.name, async () => {
console.log(` 📝 ${test.name}`);
await this.simulateTestAction(test);
});
}
}
/**
* 仪表板测试
*/
private async runDashboardTests(): Promise<void> {
const tests = [
{ name: '访问仪表板', action: 'navigate', url: `${TEST_CONFIG.baseURL}${ROUTES.dashboard}` },
{ name: '验证统计卡片', action: 'checkStats', items: ['总用户数', '活跃用户', '系统负载'] },
{ name: '验证用户增长图表', action: 'checkChart', selector: '.h-64' },
{ name: '验证最近活动', action: 'checkActivity' },
];
for (const test of tests) {
await this.executeTest('仪表板测试', test.name, async () => {
console.log(` 📝 ${test.name}`);
await this.simulateTestAction(test);
});
}
}
/**
* 用户管理测试
*/
private async runUserTests(): Promise<void> {
const tests = [
{ name: '访问用户管理页', action: 'navigate', url: `${TEST_CONFIG.baseURL}${ROUTES.users}` },
{ name: '验证用户表格', action: 'checkTable', headers: ['ID', '用户名', '邮箱', '手机号'] },
{ name: '测试搜索功能', action: 'search', keyword: 'admin' },
{ name: '测试创建用户弹窗', action: 'openModal', trigger: '添加用户' },
{ name: '测试编辑用户弹窗', action: 'openFirstEdit' },
{ name: '测试表单验证', action: 'checkFormValidation' },
];
for (const test of tests) {
await this.executeTest('用户管理测试', test.name, async () => {
console.log(` 📝 ${test.name}`);
await this.simulateTestAction(test);
});
}
}
/**
* 设置页面测试
*/
private async runSettingsTests(): Promise<void> {
const tests = [
{ name: '访问设置页', action: 'navigate', url: `${TEST_CONFIG.baseURL}${ROUTES.settings}` },
{ name: '验证设置分类', action: 'checkCategories', items: ['个人设置', '通知设置', '安全设置'] },
{ name: '测试邮件通知开关', action: 'toggleSwitch', label: '邮件通知' },
{ name: '测试系统消息开关', action: 'toggleSwitch', label: '系统消息' },
{ name: '测试深色模式开关', action: 'toggleSwitch', label: '深色模式' },
];
for (const test of tests) {
await this.executeTest('设置页面测试', test.name, async () => {
console.log(` 📝 ${test.name}`);
await this.simulateTestAction(test);
});
}
}
/**
* 执行单个测试
*/
private async executeTest(
module: string,
name: string,
action: () => Promise<void>
): Promise<void> {
const start = Date.now();
try {
await action();
this.results.push({
module,
test: name,
passed: true,
duration: Date.now() - start,
});
console.log(` ✅ 通过 (${Date.now() - start}ms)`);
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
this.results.push({
module,
test: name,
passed: false,
error: errorMsg,
duration: Date.now() - start,
});
console.log(` ❌ 失败: ${errorMsg}`);
}
}
/**
* 模拟测试动作(实际由 Claude 执行)
*/
private async simulateTestAction(test: any): Promise<void> {
// 此函数仅作为占位符
// 实际测试动作由 Claude 读取此配置后通过 MCP 工具执行
await new Promise(resolve => setTimeout(resolve, 100));
}
/**
* 打印测试摘要
*/
private printSummary(): void {
const duration = Date.now() - this.startTime;
const total = this.results.length;
const passed = this.results.filter(r => r.passed).length;
const failed = total - passed;
console.log('\n' + '='.repeat(50));
console.log('📊 测试报告摘要');
console.log('='.repeat(50));
console.log(` 总计: ${total} 个测试`);
console.log(` ✅ 通过: ${passed}`);
console.log(` ❌ 失败: ${failed}`);
console.log(` ⏱️ 耗时: ${(duration / 1000).toFixed(2)}`);
console.log('='.repeat(50));
if (failed > 0) {
console.log('\n❌ 失败的测试:');
this.results
.filter(r => !r.passed)
.forEach(r => console.log(` [${r.module}] ${r.test}: ${r.error}`));
}
console.log('\n✨ 测试执行完成!');
}
}
// 导出单例
export const mcpExecutor = new MCPTestExecutor();
// 便捷函数
export const runAllTests = () => mcpExecutor.runAllTests();
export default mcpExecutor;