Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
366 lines
16 KiB
JavaScript
366 lines
16 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
/**
|
||
* 全面测试统一姓名管理系统的所有功能
|
||
*/
|
||
|
||
const { chromium } = require('playwright');
|
||
|
||
async function comprehensiveTest() {
|
||
console.log('🔧 开始全面测试统一姓名管理系统...\n');
|
||
|
||
let browser;
|
||
let page;
|
||
let testResults = {
|
||
statusPanel: false,
|
||
generateFunction: false,
|
||
addTemplate: false,
|
||
searchFilter: false,
|
||
tableOperations: false,
|
||
editDelete: false,
|
||
apiEndpoints: {}
|
||
};
|
||
|
||
try {
|
||
browser = await chromium.launch({
|
||
headless: false,
|
||
slowMo: 1000
|
||
});
|
||
|
||
const context = await browser.newContext({
|
||
viewport: { width: 1400, height: 900 }
|
||
});
|
||
|
||
page = await context.newPage();
|
||
|
||
// 监听API调用和错误
|
||
const apiCalls = [];
|
||
page.on('request', request => {
|
||
const url = request.url();
|
||
if (url.includes('/nameTemplate/')) {
|
||
apiCalls.push({
|
||
method: request.method(),
|
||
url: url,
|
||
timestamp: new Date()
|
||
});
|
||
console.log(`🔗 ${request.method()} ${url}`);
|
||
}
|
||
});
|
||
|
||
page.on('response', response => {
|
||
const url = response.url();
|
||
if (url.includes('/nameTemplate/')) {
|
||
console.log(`📡 ${response.status()} ${url}`);
|
||
|
||
// 记录API测试结果
|
||
const endpoint = url.split('/nameTemplate/')[1].split('?')[0];
|
||
testResults.apiEndpoints[endpoint] = {
|
||
status: response.status(),
|
||
success: response.status() >= 200 && response.status() < 300
|
||
};
|
||
}
|
||
});
|
||
|
||
page.on('console', msg => {
|
||
if (msg.type() === 'error') {
|
||
console.log(`❌ 前端错误: ${msg.text()}`);
|
||
}
|
||
});
|
||
|
||
// ==================== 登录 ====================
|
||
console.log('🚀 登录系统...');
|
||
await page.goto('http://localhost:8891');
|
||
await page.waitForLoadState('networkidle');
|
||
|
||
await page.fill('input[type="text"]', 'admin');
|
||
await page.fill('input[type="password"]', '111111');
|
||
await page.click('button:has-text("登录")');
|
||
await page.waitForLoadState('networkidle');
|
||
console.log('✅ 登录成功\n');
|
||
|
||
// ==================== 测试1:系统状态面板 ====================
|
||
console.log('📊 测试1:系统状态面板加载...');
|
||
await page.goto('http://localhost:8891/#/nameManage/unified');
|
||
await page.waitForLoadState('networkidle');
|
||
await page.waitForTimeout(5000);
|
||
|
||
const statusPanelTest = await page.evaluate(() => {
|
||
const statusCards = document.querySelectorAll('.status-card');
|
||
const generatorItems = document.querySelectorAll('.generator-item');
|
||
const platformTags = document.querySelectorAll('.platform-tags .ivu-tag');
|
||
const cultureTags = document.querySelectorAll('.culture-tags .ivu-tag');
|
||
|
||
return {
|
||
hasStatusPanel: !!document.querySelector('.status-panel'),
|
||
statusCardsCount: statusCards.length,
|
||
generatorCount: generatorItems.length,
|
||
platformCount: platformTags.length,
|
||
cultureCount: cultureTags.length,
|
||
generatorStates: Array.from(generatorItems).map(item => ({
|
||
name: item.querySelector('.generator-name')?.textContent,
|
||
available: item.querySelector('.status-success') !== null
|
||
}))
|
||
};
|
||
});
|
||
|
||
testResults.statusPanel = statusPanelTest.hasStatusPanel &&
|
||
statusPanelTest.statusCardsCount === 3 &&
|
||
statusPanelTest.generatorCount === 4;
|
||
|
||
console.log(`${testResults.statusPanel ? '✅' : '❌'} 状态面板测试:`);
|
||
console.log(` - 状态面板存在: ${statusPanelTest.hasStatusPanel}`);
|
||
console.log(` - 状态卡片: ${statusPanelTest.statusCardsCount}/3`);
|
||
console.log(` - 生成器: ${statusPanelTest.generatorCount}/4`);
|
||
console.log(` - 平台标签: ${statusPanelTest.platformCount}`);
|
||
console.log(` - 文化标签: ${statusPanelTest.cultureCount}`);
|
||
statusPanelTest.generatorStates.forEach(gen => {
|
||
console.log(` - ${gen.name}: ${gen.available ? '可用' : '不可用'}`);
|
||
});
|
||
|
||
await page.screenshot({ path: 'test_01_status_panel.png', fullPage: true });
|
||
|
||
// ==================== 测试2:智能生成功能 ====================
|
||
console.log('\n🎲 测试2:智能生成功能...');
|
||
|
||
const generateTest = await page.evaluate(async () => {
|
||
const generateBtn = document.querySelector('button:has-text("生成姓名")');
|
||
const platformSelect = document.querySelector('.generate-panel .ivu-select');
|
||
|
||
if (!generateBtn || !platformSelect) {
|
||
return { hasGeneratePanel: false };
|
||
}
|
||
|
||
// 点击生成按钮
|
||
generateBtn.click();
|
||
|
||
// 等待一下看是否有结果
|
||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||
|
||
const resultItems = document.querySelectorAll('.name-result-item');
|
||
|
||
return {
|
||
hasGeneratePanel: true,
|
||
hasGenerateButton: !!generateBtn,
|
||
resultsCount: resultItems.length,
|
||
buttonDisabled: generateBtn.disabled
|
||
};
|
||
});
|
||
|
||
testResults.generateFunction = generateTest.hasGeneratePanel && generateTest.hasGenerateButton;
|
||
|
||
console.log(`${testResults.generateFunction ? '✅' : '❌'} 智能生成测试:`);
|
||
console.log(` - 生成面板存在: ${generateTest.hasGeneratePanel}`);
|
||
console.log(` - 生成按钮存在: ${generateTest.hasGenerateButton}`);
|
||
console.log(` - 生成结果数量: ${generateTest.resultsCount}`);
|
||
|
||
await page.screenshot({ path: 'test_02_generate_function.png', fullPage: true });
|
||
|
||
// ==================== 测试3:添加模板功能 ====================
|
||
console.log('\n➕ 测试3:添加姓名模板功能...');
|
||
|
||
const addButton = await page.locator('button:has-text("添加姓名模板")');
|
||
if (await addButton.isVisible()) {
|
||
await addButton.click();
|
||
await page.waitForTimeout(2000);
|
||
|
||
const addModalTest = await page.evaluate(() => {
|
||
const modal = document.querySelector('.ivu-modal');
|
||
if (!modal) return { hasModal: false };
|
||
|
||
const inputs = modal.querySelectorAll('input');
|
||
const selects = modal.querySelectorAll('.ivu-select');
|
||
|
||
return {
|
||
hasModal: true,
|
||
title: modal.querySelector('.ivu-modal-header')?.textContent?.trim(),
|
||
inputCount: inputs.length,
|
||
selectCount: selects.length,
|
||
hasLastNameInput: !!modal.querySelector('input[placeholder*="姓氏"]'),
|
||
hasFirstNameInput: !!modal.querySelector('input[placeholder*="名字"]'),
|
||
hasDisplayNameInput: !!modal.querySelector('input[placeholder*="显示名称"]')
|
||
};
|
||
});
|
||
|
||
testResults.addTemplate = addModalTest.hasModal &&
|
||
addModalTest.hasLastNameInput &&
|
||
addModalTest.hasFirstNameInput;
|
||
|
||
console.log(`${testResults.addTemplate ? '✅' : '❌'} 添加模板测试:`);
|
||
console.log(` - 弹窗打开: ${addModalTest.hasModal}`);
|
||
console.log(` - 弹窗标题: ${addModalTest.title}`);
|
||
console.log(` - 输入框数量: ${addModalTest.inputCount}`);
|
||
console.log(` - 下拉选择数量: ${addModalTest.selectCount}`);
|
||
console.log(` - 姓氏输入框: ${addModalTest.hasLastNameInput}`);
|
||
console.log(` - 名字输入框: ${addModalTest.hasFirstNameInput}`);
|
||
console.log(` - 显示名输入框: ${addModalTest.hasDisplayNameInput}`);
|
||
|
||
await page.screenshot({ path: 'test_03_add_modal.png', fullPage: true });
|
||
|
||
// 关闭弹窗
|
||
const cancelButton = await page.locator('button:has-text("取消")');
|
||
if (await cancelButton.isVisible()) {
|
||
await cancelButton.click();
|
||
await page.waitForTimeout(1000);
|
||
}
|
||
}
|
||
|
||
// ==================== 测试4:搜索和过滤功能 ====================
|
||
console.log('\n🔍 测试4:搜索和过滤功能...');
|
||
|
||
const searchTest = await page.evaluate(() => {
|
||
const keywordInput = document.querySelector('input[placeholder*="搜索姓名"]');
|
||
const cultureSelect = document.querySelectorAll('form .ivu-select')[1];
|
||
const platformSelect = document.querySelectorAll('form .ivu-select')[2];
|
||
const qualitySelect = document.querySelectorAll('form .ivu-select')[3];
|
||
const searchBtn = document.querySelector('button:has-text("搜索")');
|
||
const resetBtn = document.querySelector('button:has-text("重置")');
|
||
|
||
return {
|
||
hasKeywordInput: !!keywordInput,
|
||
hasCultureSelect: !!cultureSelect,
|
||
hasPlatformSelect: !!platformSelect,
|
||
hasQualitySelect: !!qualitySelect,
|
||
hasSearchButton: !!searchBtn,
|
||
hasResetButton: !!resetBtn
|
||
};
|
||
});
|
||
|
||
testResults.searchFilter = searchTest.hasKeywordInput &&
|
||
searchTest.hasSearchButton &&
|
||
searchTest.hasResetButton;
|
||
|
||
console.log(`${testResults.searchFilter ? '✅' : '❌'} 搜索过滤测试:`);
|
||
console.log(` - 关键词输入框: ${searchTest.hasKeywordInput}`);
|
||
console.log(` - 文化选择器: ${searchTest.hasCultureSelect}`);
|
||
console.log(` - 平台选择器: ${searchTest.hasPlatformSelect}`);
|
||
console.log(` - 质量选择器: ${searchTest.hasQualitySelect}`);
|
||
console.log(` - 搜索按钮: ${searchTest.hasSearchButton}`);
|
||
console.log(` - 重置按钮: ${searchTest.hasResetButton}`);
|
||
|
||
// ==================== 测试5:数据表格 ====================
|
||
console.log('\n📋 测试5:数据表格显示和操作...');
|
||
|
||
const tableTest = await page.evaluate(() => {
|
||
const table = document.querySelector('table');
|
||
if (!table) return { hasTable: false };
|
||
|
||
const headers = Array.from(table.querySelectorAll('thead th')).map(th => th.textContent?.trim());
|
||
const rows = table.querySelectorAll('tbody tr');
|
||
|
||
const expectedColumns = ['ID', '显示名称', '姓氏', '名字', '文化', '平台', '性别', '质量', '权重', '使用次数', '创建时间', '操作'];
|
||
const hasAdvancedColumns = expectedColumns.every(col => headers.includes(col));
|
||
|
||
return {
|
||
hasTable: true,
|
||
headerCount: headers.length,
|
||
headers: headers,
|
||
rowCount: rows.length,
|
||
hasAdvancedColumns: hasAdvancedColumns,
|
||
expectedColumns: expectedColumns
|
||
};
|
||
});
|
||
|
||
testResults.tableOperations = tableTest.hasTable && tableTest.hasAdvancedColumns;
|
||
|
||
console.log(`${testResults.tableOperations ? '✅' : '❌'} 数据表格测试:`);
|
||
console.log(` - 表格存在: ${tableTest.hasTable}`);
|
||
console.log(` - 列数: ${tableTest.headerCount}`);
|
||
console.log(` - 数据行: ${tableTest.rowCount}`);
|
||
console.log(` - 高级列完整: ${tableTest.hasAdvancedColumns}`);
|
||
if (!tableTest.hasAdvancedColumns) {
|
||
console.log(` - 实际列: ${tableTest.headers.join(', ')}`);
|
||
console.log(` - 期望列: ${tableTest.expectedColumns.join(', ')}`);
|
||
}
|
||
|
||
await page.screenshot({ path: 'test_04_data_table.png', fullPage: true });
|
||
|
||
// ==================== 测试6:API端点 ====================
|
||
console.log('\n🌐 测试6:API端点访问...');
|
||
|
||
// 测试公共API端点
|
||
const publicApiTests = await Promise.all([
|
||
fetch('http://localhost:3000/nameTemplate/supportedOptions').then(r => ({ endpoint: 'supportedOptions', status: r.status, ok: r.ok })),
|
||
fetch('http://localhost:3000/nameTemplate/generatorStatus').then(r => ({ endpoint: 'generatorStatus', status: r.status, ok: r.ok }))
|
||
].map(p => p.catch(err => ({ error: err.message }))));
|
||
|
||
console.log('📡 公共API测试结果:');
|
||
publicApiTests.forEach(result => {
|
||
if (result.error) {
|
||
console.log(` ❌ ${result.endpoint || 'Unknown'}: ${result.error}`);
|
||
} else {
|
||
console.log(` ${result.ok ? '✅' : '❌'} ${result.endpoint}: ${result.status}`);
|
||
testResults.apiEndpoints[result.endpoint] = { status: result.status, success: result.ok };
|
||
}
|
||
});
|
||
|
||
// ==================== 汇总测试结果 ====================
|
||
console.log('\n📊 测试结果汇总:');
|
||
console.log('==========================================');
|
||
|
||
const allTests = [
|
||
{ name: '系统状态面板', result: testResults.statusPanel },
|
||
{ name: '智能生成功能', result: testResults.generateFunction },
|
||
{ name: '添加模板功能', result: testResults.addTemplate },
|
||
{ name: '搜索过滤功能', result: testResults.searchFilter },
|
||
{ name: '数据表格操作', result: testResults.tableOperations }
|
||
];
|
||
|
||
let passedTests = 0;
|
||
allTests.forEach(test => {
|
||
console.log(`${test.result ? '✅' : '❌'} ${test.name}: ${test.result ? '通过' : '失败'}`);
|
||
if (test.result) passedTests++;
|
||
});
|
||
|
||
console.log('\n🌐 API端点测试:');
|
||
Object.entries(testResults.apiEndpoints).forEach(([endpoint, result]) => {
|
||
console.log(`${result.success ? '✅' : '❌'} ${endpoint}: ${result.status}`);
|
||
});
|
||
|
||
const successRate = Math.round((passedTests / allTests.length) * 100);
|
||
console.log(`\n📈 总体测试通过率: ${passedTests}/${allTests.length} (${successRate}%)`);
|
||
|
||
if (successRate < 100) {
|
||
console.log('\n⚠️ 需要修复的问题:');
|
||
allTests.forEach(test => {
|
||
if (!test.result) {
|
||
console.log(` - ${test.name}`);
|
||
}
|
||
});
|
||
}
|
||
|
||
await page.screenshot({ path: 'test_05_final_result.png', fullPage: true });
|
||
|
||
console.log('\n📂 测试截图已保存:');
|
||
console.log(' - test_01_status_panel.png');
|
||
console.log(' - test_02_generate_function.png');
|
||
console.log(' - test_03_add_modal.png');
|
||
console.log(' - test_04_data_table.png');
|
||
console.log(' - test_05_final_result.png');
|
||
|
||
console.log('\n⏰ 浏览器将保持打开10秒供检查...');
|
||
await page.waitForTimeout(10000);
|
||
|
||
return testResults;
|
||
|
||
} catch (error) {
|
||
console.error('❌ 测试失败:', error.message);
|
||
if (page) {
|
||
await page.screenshot({ path: 'test_error.png', fullPage: true });
|
||
}
|
||
return testResults;
|
||
} finally {
|
||
if (browser) {
|
||
await browser.close();
|
||
}
|
||
console.log('🏁 全面测试结束');
|
||
}
|
||
}
|
||
|
||
// 导出模块和直接运行
|
||
if (require.main === module) {
|
||
comprehensiveTest().then(results => {
|
||
console.log('\n🎯 最终测试结果:', JSON.stringify(results, null, 2));
|
||
}).catch(console.error);
|
||
}
|
||
|
||
module.exports = comprehensiveTest; |