// 全功能测试脚本 - 包含正向和负向测试 const { chromium } = require('playwright'); async function runFullTest() { console.log('🚀 开始全功能自动化测试...\n'); console.log('=' .repeat(60)); const browser = await chromium.launch({ headless: false }); const context = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); const page = await context.newPage(); const results = []; const baseUrl = 'http://localhost:5175'; // 辅助函数:截图并保存 async function takeScreenshot(name) { const filename = `test-screenshots/${name}-${Date.now()}.png`; await page.screenshot({ path: filename, fullPage: true }); console.log(` 📸 截图: ${filename}`); return filename; } // ======================================== // Test 1: 侧边栏导航测试 // ======================================== console.log('\n📋 Test 1: 侧边栏导航测试'); console.log('-'.repeat(60)); try { await page.goto(baseUrl, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); // 检查侧边栏导航项 const navItems = await page.$$('.sidebar-nav-item'); console.log(` ✅ 找到 ${navItems.length} 个导航项`); // 逐个点击导航测试 const navLabels = ['首页', '记账', '预算', '统计']; for (let i = 0; i < navItems.length; i++) { await navItems[i].click(); await page.waitForTimeout(1000); const currentUrl = page.url(); console.log(` ${navLabels[i] || `菜单${i+1}`}: ${currentUrl.includes(navLabels[i]) ? '✅' : '⚠️'} 跳转成功`); } results.push({ test: '侧边栏导航', status: '✅ 通过', detail: `导航项: ${navItems.length}` }); } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '侧边栏导航', status: '❌ 失败', error: error.message }); } // ======================================== // Test 2: 正向测试 - 添加记账记录 // ======================================== console.log('\n📋 Test 2: 正向测试 - 添加记账记录(正常数据)'); console.log('-'.repeat(60)); try { await page.goto(`${baseUrl}/record`, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); // 点击添加按钮 const addBtn = await page.$('button:has-text("添加")'); if (addBtn) { await addBtn.click(); await page.waitForTimeout(500); // 填写表单 const amountInput = await page.$('input[type="number"], input[placeholder*="金额"]'); if (amountInput) { await amountInput.fill('150'); } // 选择类型(支出) const expenseOption = await page.$('text=支出'); if (expenseOption) { await expenseOption.click(); } // 选择类别 const categoryOption = await page.$('text=餐饮'); if (categoryOption) { await categoryOption.click(); } // 点击提交 const submitBtn = await page.$('button:has-text("保存"), button:has-text("提交")'); if (submitBtn) { await submitBtn.click(); await page.waitForTimeout(2000); console.log(' ✅ 记录添加成功(正向测试)'); } } else { console.log(' ⚠️ 未找到添加按钮'); } results.push({ test: '添加记账记录(正向)', status: '✅ 通过' }); } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '添加记账记录(正向)', status: '❌ 失败', error: error.message }); } // ======================================== // Test 3: 正向测试 - 设置预算 // ======================================== console.log('\n📋 Test 3: 正向测试 - 设置预算(正常数据)'); console.log('-'.repeat(60)); try { await page.goto(`${baseUrl}/budget`, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); // 点击设置预算按钮 const setBudgetBtn = await page.$('button:has-text("设置预算"), button:has-text("添加预算")'); if (setBudgetBtn) { await setBudgetBtn.click(); await page.waitForTimeout(500); // 填写预算金额 const budgetInput = await page.$('input[type="number"], input[placeholder*="预算"]'); if (budgetInput) { await budgetInput.fill('2000'); } // 选择类别 const categoryOption = await page.$('text=购物'); if (categoryOption) { await categoryOption.click(); } // 提交 const submitBtn = await page.$('button:has-text("保存"), button:has-text("提交"), button:has-text("确定")'); if (submitBtn) { await submitBtn.click(); await page.waitForTimeout(2000); console.log(' ✅ 预算设置成功(正向测试)'); } } else { console.log(' ⚠️ 未找到设置预算按钮'); } results.push({ test: '设置预算(正向)', status: '✅ 通过' }); } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '设置预算(正向)', status: '❌ 失败', error: error.message }); } // ======================================== // Test 4: 负向测试 - 空白表单提交 // ======================================== console.log('\n📋 Test 4: 负向测试 - 空白表单提交验证'); console.log('-'.repeat(60)); try { await page.goto(`${baseUrl}/record`, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); // 点击添加按钮 const addBtn = await page.$('button:has-text("添加")'); if (addBtn) { await addBtn.click(); await page.waitForTimeout(500); // 直接点击提交(不填写任何内容) const submitBtn = await page.$('button:has-text("保存"), button:has-text("提交")'); if (submitBtn) { await submitBtn.click(); await page.waitForTimeout(1000); // 检查是否有错误提示 const errorMsg = await page.$('.error, .error-message, [class*="error"], text=/不能为空|必填|请输入/'); if (errorMsg) { console.log(' ✅ 空白表单被正确拒绝,显示错误提示'); results.push({ test: '空白表单(负向)', status: '✅ 通过', detail: '正确拒绝空白提交' }); } else { console.log(' ⚠️ 未检测到明确的错误提示'); results.push({ test: '空白表单(负向)', status: '⚠️ 部分通过' }); } } } } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '空白表单(负向)', status: '❌ 失败', error: error.message }); } // ======================================== // Test 5: 负向测试 - 金额格式错误 // ======================================== console.log('\n📋 Test 5: 负向测试 - 金额格式错误验证'); console.log('-'.repeat(60)); try { await page.goto(`${baseUrl}/record`, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); const addBtn = await page.$('button:has-text("添加")'); if (addBtn) { await addBtn.click(); await page.waitForTimeout(500); // 输入无效金额(负数) const amountInput = await page.$('input[type="number"], input[placeholder*="金额"]'); if (amountInput) { await amountInput.fill('-100'); await page.waitForTimeout(500); // 检查是否有验证错误 const validationError = await page.$('input:invalid, .error, text=/无效|错误|正数/'); if (validationError) { console.log(' ✅ 负数金额被正确拒绝'); results.push({ test: '负数金额(负向)', status: '✅ 通过', detail: '正确拒绝负数' }); } else { console.log(' ⚠️ 未检测到负数验证错误'); results.push({ test: '负数金额(负向)', status: '⚠️ 部分通过' }); } } } } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '负数金额(负向)', status: '❌ 失败', error: error.message }); } // ======================================== // Test 6: 负向测试 - 必填字段缺失 // ======================================== console.log('\n📋 Test 6: 负向测试 - 必填字段缺失验证'); console.log('-'.repeat(60)); try { await page.goto(`${baseUrl}/record`, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); const addBtn = await page.$('button:has-text("添加")'); if (addBtn) { await addBtn.click(); await page.waitForTimeout(500); // 只填写金额,不填写其他必填项 const amountInput = await page.$('input[type="number"], input[placeholder*="金额"]'); if (amountInput) { await amountInput.fill('50'); } // 直接提交 const submitBtn = await page.$('button:has-text("保存"), button:has-text("提交")'); if (submitBtn) { await submitBtn.click(); await page.waitForTimeout(1000); console.log(' ✅ 部分必填字段缺失测试完成'); results.push({ test: '必填字段缺失(负向)', status: '✅ 通过' }); } } } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '必填字段缺失(负向)', status: '❌ 失败', error: error.message }); } // ======================================== // Test 7: 侧边栏折叠/展开 // ======================================== console.log('\n📋 Test 7: 侧边栏折叠/展开测试'); console.log('-'.repeat(60)); try { await page.goto(baseUrl, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); // 查找折叠按钮 const toggleBtn = await page.$('.sidebar-toggle, [class*="toggle"], [class*="collapse"]'); if (toggleBtn) { // 测试折叠 await toggleBtn.click(); await page.waitForTimeout(500); const isCollapsed = await page.$('.sidebar.collapsed, [class*="collapsed"]'); console.log(` 折叠功能: ${isCollapsed ? '✅' : '⚠️'}`); // 测试展开 await toggleBtn.click(); await page.waitForTimeout(500); const isExpanded = await page.$('.sidebar:not(.collapsed)'); console.log(` 展开功能: ${isExpanded ? '✅' : '⚠️'}`); results.push({ test: '侧边栏折叠/展开', status: '✅ 通过' }); } else { console.log(' ⚠️ 未找到折叠按钮'); results.push({ test: '侧边栏折叠/展开', status: '⚠️ 未找到按钮' }); } } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '侧边栏折叠/展开', status: '❌ 失败', error: error.message }); } // ======================================== // Test 8: 统计图表切换 // ======================================== console.log('\n📋 Test 8: 统计图表切换测试'); console.log('-'.repeat(60)); try { await page.goto(`${baseUrl}/statistics`, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForTimeout(2000); // 查找图表切换标签 const tabs = await page.$$('.chart-tabs button, [class*="tab"] button, button[class*="chart"]'); console.log(` 找到 ${tabs.length} 个图表切换标签`); if (tabs.length > 0) { // 依次点击切换 for (let i = 0; i < tabs.length; i++) { await tabs[i].click(); await page.waitForTimeout(1000); console.log(` 标签 ${i+1}: ✅ 切换成功`); } results.push({ test: '图表切换', status: '✅ 通过', detail: `${tabs.length} 个标签` }); } else { // 检查是否有图表 const charts = await page.$$('.chart-card, [class*="chart"]'); console.log(` 找到 ${charts.length} 个图表`); results.push({ test: '图表切换', status: '⚠️ 无切换标签' }); } } catch (error) { console.log(` ❌ 错误: ${error.message}`); results.push({ test: '图表切换', status: '❌ 失败', error: error.message }); } // ======================================== // 测试总结 // ======================================== console.log('\n' + '='.repeat(60)); console.log('📊 测试结果总结'); console.log('='.repeat(60)); const passed = results.filter(r => r.status.includes('✅')).length; const total = results.length; const passRate = ((passed / total) * 100).toFixed(1); results.forEach(r => { const status = r.status.includes('✅') ? '✅' : r.status.includes('⚠️') ? '⚠️' : '❌'; console.log(`${status} ${r.test.padEnd(25)} : ${r.status}`); }); console.log('='.repeat(60)); console.log(`总计: ${passed}/${total} 通过 (${passRate}%)`); console.log('='.repeat(60)); if (parseFloat(passRate) >= 80) { console.log('\n🎉 测试结果:优秀!系统功能正常!'); } else if (parseFloat(passRate) >= 60) { console.log('\n⚠️ 测试结果:一般,部分功能需要修复'); } else { console.log('\n❌ 测试结果:不理想,需要修复关键问题'); } await browser.close(); console.log('\n✅ 全功能测试完成!'); return results; } // 运行测试 runFullTest().catch(console.error);