You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
11 KiB
JavaScript
280 lines
11 KiB
JavaScript
const { chromium } = require('playwright');
|
|
|
|
(async () => {
|
|
const browser = await chromium.launch({ headless: true });
|
|
const page = await browser.newPage();
|
|
const results = [];
|
|
|
|
function log(category, name, pass, detail) {
|
|
const status = pass ? '✅' : '❌';
|
|
console.log(`${status} [${category}] ${name}: ${detail}`);
|
|
results.push({ category, name, pass, detail });
|
|
}
|
|
|
|
// === 登录 ===
|
|
await page.goto('http://127.0.0.1/admin/login');
|
|
await page.waitForTimeout(500);
|
|
await page.fill('input[type="text"]', 'admin');
|
|
await page.fill('input[type="password"]', 'admin123');
|
|
await page.click('button:has-text("登录")');
|
|
await page.waitForTimeout(2000);
|
|
|
|
// === 导航到产量报表 ===
|
|
await page.goto('http://127.0.0.1/admin/production');
|
|
await page.waitForTimeout(3000);
|
|
|
|
// =====================
|
|
// 1. 页面基本加载
|
|
// =====================
|
|
console.log('\n========== 1. 页面基本加载 ==========');
|
|
|
|
const title = await page.title();
|
|
log('页面', '页面标题', title.length > 0, `标题: ${title}`);
|
|
|
|
const url = page.url();
|
|
log('页面', 'URL正确', url.includes('production'), `URL: ${url}`);
|
|
|
|
// =====================
|
|
// 2. 日期选择器
|
|
// =====================
|
|
console.log('\n========== 2. 日期选择器 ==========');
|
|
|
|
const dateInputs = await page.$$eval('.el-date-editor input', els => els.map(e => e.value));
|
|
const today = new Date();
|
|
const todayStr = `${today.getFullYear()}-${String(today.getMonth()+1).padStart(2,'0')}-${String(today.getDate()).padStart(2,'0')}`;
|
|
log('日期', '默认日期是今天', dateInputs[0] === todayStr && dateInputs[1] === todayStr, `开始=${dateInputs[0]}, 结束=${dateInputs[1]}, 今天=${todayStr}`);
|
|
|
|
// =====================
|
|
// 3. 汇总卡片
|
|
// =====================
|
|
console.log('\n========== 3. 汇总卡片 ==========');
|
|
|
|
const summaryCards = await page.evaluate(() => {
|
|
const cards = document.querySelectorAll('.el-card');
|
|
const results = [];
|
|
for (const card of cards) {
|
|
const text = card.textContent.trim();
|
|
if (text.includes('总产量') || text.includes('运行机床') || text.includes('切削总时') || text.includes('平均产量')) {
|
|
results.push(text.replace(/\n/g, ' ').substring(0, 80));
|
|
}
|
|
}
|
|
return results;
|
|
});
|
|
log('汇总', '总产量卡片有数据', summaryCards.some(c => c.includes('总产量')), summaryCards.filter(c => c.includes('总产量')).join(' | ') || '未找到');
|
|
log('汇总', '运行机床卡片', summaryCards.some(c => c.includes('运行机床')), summaryCards.filter(c => c.includes('运行机床')).join(' | ') || '未找到');
|
|
log('汇总', '切削总时卡片', summaryCards.some(c => c.includes('切削总时')), summaryCards.filter(c => c.includes('切削总时')).join(' | ') || '未找到');
|
|
log('汇总', '平均产量卡片', summaryCards.some(c => c.includes('平均产量')), summaryCards.filter(c => c.includes('平均产量')).join(' | ') || '未找到');
|
|
|
|
// =====================
|
|
// 4. 筛选控件
|
|
// =====================
|
|
console.log('\n========== 4. 筛选控件 ==========');
|
|
|
|
// 车间下拉
|
|
const workshopOptions = await page.evaluate(() => {
|
|
const sel = document.querySelectorAll('.el-select');
|
|
// 第一个是车间
|
|
return sel.length;
|
|
});
|
|
log('筛选', '下拉控件存在', workshopOptions >= 3, `找到${workshopOptions}个下拉`);
|
|
|
|
// 查询按钮
|
|
const queryBtn = await page.$('button:has-text("查询")');
|
|
log('筛选', '查询按钮存在', queryBtn !== null, queryBtn ? '存在' : '不存在');
|
|
|
|
// 重置按钮
|
|
const resetBtn = await page.$('button:has-text("重置")');
|
|
log('筛选', '重置按钮存在', resetBtn !== null, resetBtn ? '存在' : '不存在');
|
|
|
|
// =====================
|
|
// 5. 数据表格
|
|
// =====================
|
|
console.log('\n========== 5. 数据表格 ==========');
|
|
|
|
const tableHeaders = await page.$$eval('.el-table__header th .cell', els => els.map(e => e.textContent.trim()));
|
|
log('表格', '列头完整', tableHeaders.length >= 7, `列头: ${tableHeaders.join(', ')}`);
|
|
|
|
const expectedHeaders = ['日期', '机床', '程序名', '产量', '运行时间', '切削时间', '日状态'];
|
|
expectedHeaders.forEach(h => {
|
|
log('表格', `列头含"${h}"`, tableHeaders.includes(h), tableHeaders.includes(h) ? '存在' : `缺失! 现有: ${tableHeaders.join(',')}`);
|
|
});
|
|
|
|
// 检查表格数据
|
|
const tableRows = await page.$$eval('.el-table__body tr', trs =>
|
|
trs.slice(0, 5).map(tr => {
|
|
const cells = tr.querySelectorAll('td .cell');
|
|
return Array.from(cells).map(c => c.textContent.trim());
|
|
})
|
|
);
|
|
log('表格', '有数据行', tableRows.length > 0, `${tableRows.length}行`);
|
|
|
|
if (tableRows.length > 0) {
|
|
// 检查每列是否有数据
|
|
const dateCol = tableRows.map(r => r[0]).filter(v => v && v !== '');
|
|
log('表格', '日期列有数据', dateCol.length > 0, `${dateCol.length}/${tableRows.length}行有日期, 样例: ${dateCol[0]}`);
|
|
|
|
const machineCol = tableRows.map(r => r[1]).filter(v => v && v !== '');
|
|
log('表格', '机床列有数据', machineCol.length > 0, `${machineCol.length}/${tableRows.length}行有机床, 样例: ${machineCol[0]}`);
|
|
|
|
const programCol = tableRows.map(r => r[2]).filter(v => v && v !== '');
|
|
log('表格', '程序名列有数据', programCol.length > 0, `${programCol.length}/${tableRows.length}行有程序名, 样例: ${programCol[0]}`);
|
|
|
|
const qtyCol = tableRows.map(r => r[3]).filter(v => v && v !== '' && v !== '-');
|
|
log('表格', '产量列有数据', qtyCol.length > 0, `${qtyCol.length}/${tableRows.length}行有产量, 样例: ${qtyCol.slice(0, 3).join(',')}`);
|
|
|
|
const statusCol = tableRows.map(r => r[6]).filter(v => v && v !== '');
|
|
log('表格', '日状态列有数据', statusCol.length > 0, `${statusCol.length}/${tableRows.length}行有状态, 样例: ${statusCol.slice(0, 3).join(',')}`);
|
|
|
|
// 打印前3行完整数据
|
|
console.log('\n 前3行完整数据:');
|
|
tableRows.slice(0, 3).forEach((row, i) => console.log(` 行${i+1}: ${JSON.stringify(row)}`));
|
|
}
|
|
|
|
// =====================
|
|
// 6. 分页
|
|
// =====================
|
|
console.log('\n========== 6. 分页 ==========');
|
|
|
|
const pagination = await page.$('.el-pagination');
|
|
log('分页', '分页组件存在', pagination !== null, pagination ? '存在' : '不存在');
|
|
|
|
const totalText = await page.evaluate(() => {
|
|
const total = document.querySelector('.el-pagination__total');
|
|
return total ? total.textContent.trim() : '未找到';
|
|
});
|
|
log('分页', '总数显示', totalText !== '未找到', totalText);
|
|
|
|
// =====================
|
|
// 7. 操作按钮
|
|
// =====================
|
|
console.log('\n========== 7. 操作按钮 ==========');
|
|
|
|
const adjustBtns = await page.$$('button:has-text("修正")');
|
|
log('操作', '修正按钮存在', adjustBtns.length > 0, `${adjustBtns.length}个修正按钮`);
|
|
|
|
const historyBtns = await page.$$('button:has-text("修正历史")');
|
|
log('操作', '修正历史按钮存在', historyBtns.length > 0, `${historyBtns.length}个修正历史按钮`);
|
|
|
|
// =====================
|
|
// 8. 交互测试:点击修正
|
|
// =====================
|
|
console.log('\n========== 8. 交互测试:修正 ==========');
|
|
|
|
if (adjustBtns.length > 0) {
|
|
await adjustBtns[0].click();
|
|
await page.waitForTimeout(1000);
|
|
|
|
const dialog = await page.$('.el-dialog');
|
|
const dialogVisible = dialog && await dialog.isVisible();
|
|
log('交互', '点击修正弹出弹窗', dialogVisible, dialogVisible ? '弹窗可见' : '弹窗不可见');
|
|
|
|
if (dialogVisible) {
|
|
const dialogTitle = await page.evaluate(() => {
|
|
const t = document.querySelector('.el-dialog__title');
|
|
return t ? t.textContent.trim() : '无标题';
|
|
});
|
|
log('交互', '弹窗标题', true, dialogTitle);
|
|
|
|
// 检查弹窗内的表单元素
|
|
const dialogInputs = await page.$$eval('.el-dialog input', els => els.map(e => ({ type: e.type, placeholder: e.placeholder, value: e.value })));
|
|
log('交互', '弹窗表单元素', dialogInputs.length > 0, `${JSON.stringify(dialogInputs)}`);
|
|
|
|
// 关闭弹窗
|
|
const closeBtn = await page.$('.el-dialog__headerbtn');
|
|
if (closeBtn) { await closeBtn.click(); await page.waitForTimeout(500); }
|
|
}
|
|
}
|
|
|
|
// =====================
|
|
// 9. 交互测试:点击修正历史
|
|
// =====================
|
|
console.log('\n========== 9. 交互测试:修正历史 ==========');
|
|
|
|
if (historyBtns.length > 0) {
|
|
await historyBtns[0].click();
|
|
await page.waitForTimeout(1000);
|
|
|
|
const dialog = await page.$('.el-dialog');
|
|
const dialogVisible = dialog && await dialog.isVisible();
|
|
log('交互', '点击修正历史弹出弹窗', dialogVisible, dialogVisible ? '弹窗可见' : '弹窗不可见');
|
|
|
|
if (dialogVisible) {
|
|
const dialogTitle = await page.evaluate(() => {
|
|
const t = document.querySelector('.el-dialog__title');
|
|
return t ? t.textContent.trim() : '无标题';
|
|
});
|
|
log('交互', '弹窗标题', true, dialogTitle);
|
|
|
|
// 关闭
|
|
const closeBtn = await page.$('.el-dialog__headerbtn');
|
|
if (closeBtn) { await closeBtn.click(); await page.waitForTimeout(500); }
|
|
}
|
|
}
|
|
|
|
// =====================
|
|
// 10. 交互测试:重置按钮
|
|
// =====================
|
|
console.log('\n========== 10. 交互测试:重置 ==========');
|
|
|
|
if (resetBtn) {
|
|
await resetBtn.click();
|
|
await page.waitForTimeout(3000);
|
|
|
|
const dateAfterReset = await page.$$eval('.el-date-editor input', els => els.map(e => e.value));
|
|
log('交互', '重置后日期变化', true, `重置后: ${dateAfterReset.join(' - ')}`);
|
|
|
|
const rowsAfterReset = await page.$$eval('.el-table__body tr', trs => trs.length);
|
|
log('交互', '重置后有数据', rowsAfterReset > 0, `${rowsAfterReset}行`);
|
|
}
|
|
|
|
// =====================
|
|
// 11. 交互测试:查询按钮
|
|
// =====================
|
|
console.log('\n========== 11. 交互测试:查询 ==========');
|
|
|
|
if (queryBtn) {
|
|
await queryBtn.click();
|
|
await page.waitForTimeout(3000);
|
|
|
|
const rowsAfterQuery = await page.$$eval('.el-table__body tr', trs => trs.length);
|
|
log('交互', '查询后有数据', rowsAfterQuery > 0, `${rowsAfterQuery}行`);
|
|
}
|
|
|
|
// =====================
|
|
// 12. 交互测试:分页切换
|
|
// // =====================
|
|
console.log('\n========== 12. 交互测试:分页 ==========');
|
|
|
|
const nextBtn = await page.$('.el-pagination .btn-next');
|
|
if (nextBtn) {
|
|
const isEnabled = await nextBtn.isEnabled();
|
|
if (isEnabled) {
|
|
await nextBtn.click();
|
|
await page.waitForTimeout(2000);
|
|
const page2Rows = await page.$$eval('.el-table__body tr', trs => trs.length);
|
|
log('交互', '翻页后有数据', page2Rows > 0, `第2页${page2Rows}行`);
|
|
} else {
|
|
log('交互', '翻页', false, '下一页按钮不可用(可能只有1页)');
|
|
}
|
|
}
|
|
|
|
// =====================
|
|
// 汇总
|
|
// =====================
|
|
console.log('\n========================================');
|
|
const passed = results.filter(r => r.pass).length;
|
|
const failed = results.filter(r => !r.pass).length;
|
|
console.log(`总计: ${results.length}项, 通过: ${passed}, 失败: ${failed}`);
|
|
|
|
if (failed > 0) {
|
|
console.log('\n失败项:');
|
|
results.filter(r => !r.pass).forEach(r => console.log(` ❌ [${r.category}] ${r.name}: ${r.detail}`));
|
|
}
|
|
|
|
// 截图
|
|
await page.screenshot({ path: 'test-screenshots/production-full-test.png', fullPage: true });
|
|
console.log('\n截图已保存');
|
|
|
|
await browser.close();
|
|
})();
|