#!/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;