489 lines
14 KiB
JavaScript
489 lines
14 KiB
JavaScript
/**
|
||
* 员工导入状态持久化功能测试用例
|
||
*
|
||
* 测试目标:验证导入状态跨页面持久化功能
|
||
*
|
||
* 测试场景:
|
||
* 1. 导入成功场景(全部成功)
|
||
* 2. 导入部分失败场景
|
||
* 3. 刷新页面后状态恢复
|
||
* 4. localStorage过期处理
|
||
* 5. 清除导入历史功能
|
||
*/
|
||
|
||
const BASE_URL = 'http://localhost:8080';
|
||
|
||
// 测试账号
|
||
const TEST_CREDENTIALS = {
|
||
username: 'admin',
|
||
password: 'admin123'
|
||
};
|
||
|
||
let authToken = '';
|
||
|
||
/**
|
||
* 登录获取token
|
||
*/
|
||
async function login() {
|
||
console.log('\n=== 步骤1: 登录系统 ===');
|
||
const response = await fetch(`${BASE_URL}/login/test`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(TEST_CREDENTIALS)
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.code === 200) {
|
||
authToken = result.token;
|
||
console.log('✅ 登录成功,获取到token');
|
||
return true;
|
||
} else {
|
||
console.error('❌ 登录失败:', result.msg);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 模拟导入场景(不实际上传文件,直接构造数据)
|
||
*/
|
||
function simulateImportSuccess() {
|
||
console.log('\n=== 步骤2: 模拟导入成功场景 ===');
|
||
|
||
// 模拟后端返回的状态数据
|
||
const mockSuccessResult = {
|
||
taskId: 'task_' + Date.now(),
|
||
status: 'SUCCESS',
|
||
totalCount: 100,
|
||
successCount: 100,
|
||
failureCount: 0,
|
||
progress: 100,
|
||
message: '导入完成'
|
||
};
|
||
|
||
console.log('模拟数据:', mockSuccessResult);
|
||
|
||
// 模拟前端保存到localStorage
|
||
const taskData = {
|
||
taskId: mockSuccessResult.taskId,
|
||
status: mockSuccessResult.status,
|
||
hasFailures: mockSuccessResult.failureCount > 0,
|
||
totalCount: mockSuccessResult.totalCount,
|
||
successCount: mockSuccessResult.successCount,
|
||
failureCount: mockSuccessResult.failureCount,
|
||
saveTime: Date.now()
|
||
};
|
||
|
||
localStorage.setItem('employee_import_last_task', JSON.stringify(taskData));
|
||
console.log('✅ 已保存导入任务到localStorage');
|
||
console.log('保存的数据:', JSON.stringify(taskData, null, 2));
|
||
|
||
return mockSuccessResult;
|
||
}
|
||
|
||
/**
|
||
* 模拟导入部分失败场景
|
||
*/
|
||
function simulateImportWithFailures() {
|
||
console.log('\n=== 步骤3: 模拟导入部分失败场景 ===');
|
||
|
||
// 模拟后端返回的状态数据
|
||
const mockFailureResult = {
|
||
taskId: 'task_' + Date.now(),
|
||
status: 'SUCCESS',
|
||
totalCount: 100,
|
||
successCount: 95,
|
||
failureCount: 5,
|
||
progress: 100,
|
||
message: '导入完成'
|
||
};
|
||
|
||
console.log('模拟数据:', mockFailureResult);
|
||
|
||
// 模拟前端保存到localStorage
|
||
const taskData = {
|
||
taskId: mockFailureResult.taskId,
|
||
status: mockFailureResult.status,
|
||
hasFailures: mockFailureResult.failureCount > 0,
|
||
totalCount: mockFailureResult.totalCount,
|
||
successCount: mockFailureResult.successCount,
|
||
failureCount: mockFailureResult.failureCount,
|
||
saveTime: Date.now()
|
||
};
|
||
|
||
localStorage.setItem('employee_import_last_task', JSON.stringify(taskData));
|
||
console.log('✅ 已保存导入任务到localStorage(包含失败记录)');
|
||
console.log('保存的数据:', JSON.stringify(taskData, null, 2));
|
||
|
||
return mockFailureResult;
|
||
}
|
||
|
||
/**
|
||
* 验证localStorage中的数据
|
||
*/
|
||
function verifyStorageData() {
|
||
console.log('\n=== 步骤4: 验证localStorage数据 ===');
|
||
|
||
try {
|
||
const data = localStorage.getItem('employee_import_last_task');
|
||
|
||
if (!data) {
|
||
console.log('❌ localStorage中没有找到导入任务数据');
|
||
return null;
|
||
}
|
||
|
||
const task = JSON.parse(data);
|
||
console.log('✅ 成功读取localStorage中的数据');
|
||
console.log('读取的数据:', JSON.stringify(task, null, 2));
|
||
|
||
// 验证必要字段
|
||
const requiredFields = ['taskId', 'status', 'hasFailures', 'totalCount', 'successCount', 'failureCount', 'saveTime'];
|
||
const missingFields = requiredFields.filter(field => !(field in task));
|
||
|
||
if (missingFields.length > 0) {
|
||
console.error('❌ 缺少必要字段:', missingFields);
|
||
return null;
|
||
}
|
||
|
||
console.log('✅ 所有必要字段都存在');
|
||
|
||
// 验证字段类型
|
||
if (typeof task.taskId !== 'string') {
|
||
console.error('❌ taskId字段类型错误,期望string,实际:', typeof task.taskId);
|
||
return null;
|
||
}
|
||
|
||
if (typeof task.status !== 'string') {
|
||
console.error('❌ status字段类型错误,期望string,实际:', typeof task.status);
|
||
return null;
|
||
}
|
||
|
||
if (typeof task.hasFailures !== 'boolean') {
|
||
console.error('❌ hasFailures字段类型错误,期望boolean,实际:', typeof task.hasFailures);
|
||
return null;
|
||
}
|
||
|
||
if (typeof task.saveTime !== 'number') {
|
||
console.error('❌ saveTime字段类型错误,期望number,实际:', typeof task.saveTime);
|
||
return null;
|
||
}
|
||
|
||
console.log('✅ 所有字段类型正确');
|
||
|
||
// 验证时间戳合理性
|
||
const now = Date.now();
|
||
const timeDiff = now - task.saveTime;
|
||
|
||
if (timeDiff < 0 || timeDiff > 60000) { // 超过1分钟认为不合理
|
||
console.warn('⚠️ saveTime时间戳可能异常,当前时间:', now, 'saveTime:', task.saveTime);
|
||
} else {
|
||
console.log('✅ saveTime时间戳正常');
|
||
}
|
||
|
||
return task;
|
||
} catch (error) {
|
||
console.error('❌ 解析localStorage数据失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试状态恢复逻辑
|
||
*/
|
||
function testRestoreState() {
|
||
console.log('\n=== 步骤5: 测试状态恢复逻辑 ===');
|
||
|
||
const task = verifyStorageData();
|
||
|
||
if (!task) {
|
||
console.log('❌ 无法恢复状态:localStorage数据无效');
|
||
return false;
|
||
}
|
||
|
||
// 模拟restoreImportState()方法的逻辑
|
||
const restoredState = {
|
||
showFailureButton: false,
|
||
currentTaskId: null
|
||
};
|
||
|
||
if (task.hasFailures && task.taskId) {
|
||
restoredState.currentTaskId = task.taskId;
|
||
restoredState.showFailureButton = true;
|
||
console.log('✅ 检测到失败记录,应该显示"查看导入失败记录"按钮');
|
||
console.log(' - showFailureButton:', restoredState.showFailureButton);
|
||
console.log(' - currentTaskId:', restoredState.currentTaskId);
|
||
} else {
|
||
console.log('✅ 没有失败记录,不显示按钮');
|
||
console.log(' - showFailureButton:', restoredState.showFailureButton);
|
||
console.log(' - currentTaskId:', restoredState.currentTaskId);
|
||
}
|
||
|
||
return restoredState;
|
||
}
|
||
|
||
/**
|
||
* 测试过期数据处理
|
||
*/
|
||
function testExpiredData() {
|
||
console.log('\n=== 步骤6: 测试过期数据处理 ===');
|
||
|
||
// 创建一个8天前的过期数据
|
||
const eightDaysAgo = Date.now() - (8 * 24 * 60 * 60 * 1000);
|
||
|
||
const expiredTask = {
|
||
taskId: 'expired_task',
|
||
status: 'SUCCESS',
|
||
hasFailures: true,
|
||
totalCount: 100,
|
||
successCount: 90,
|
||
failureCount: 10,
|
||
saveTime: eightDaysAgo
|
||
};
|
||
|
||
localStorage.setItem('employee_import_last_task', JSON.stringify(expiredTask));
|
||
console.log('已创建过期数据(8天前)');
|
||
|
||
// 模拟getImportTaskFromStorage()的过期检查逻辑
|
||
const sevenDays = 7 * 24 * 60 * 60 * 1000;
|
||
const isExpired = Date.now() - expiredTask.saveTime > sevenDays;
|
||
|
||
if (isExpired) {
|
||
localStorage.removeItem('employee_import_last_task');
|
||
console.log('✅ 检测到过期数据,已清除');
|
||
return true;
|
||
} else {
|
||
console.log('❌ 过期检查逻辑异常');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试清除导入历史功能
|
||
*/
|
||
function testClearHistory() {
|
||
console.log('\n=== 步骤7: 测试清除导入历史功能 ===');
|
||
|
||
// 先保存一些测试数据
|
||
const testTask = {
|
||
taskId: 'test_clear_task',
|
||
status: 'SUCCESS',
|
||
hasFailures: true,
|
||
totalCount: 50,
|
||
successCount: 45,
|
||
failureCount: 5,
|
||
saveTime: Date.now()
|
||
};
|
||
|
||
localStorage.setItem('employee_import_last_task', JSON.stringify(testTask));
|
||
console.log('已创建测试数据');
|
||
|
||
// 模拟clearImportHistory()方法
|
||
localStorage.removeItem('employee_import_last_task');
|
||
console.log('✅ 已清除导入历史');
|
||
|
||
// 验证是否真的清除了
|
||
const data = localStorage.getItem('employee_import_last_task');
|
||
if (data === null) {
|
||
console.log('✅ 验证成功:导入历史已完全清除');
|
||
return true;
|
||
} else {
|
||
console.error('❌ 清除失败:localStorage中仍有数据');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试字段名一致性
|
||
*/
|
||
function testFieldConsistency() {
|
||
console.log('\n=== 步骤8: 测试字段名一致性 ===');
|
||
|
||
// 模拟ImportStatusVO返回的数据(后端)
|
||
const backendData = {
|
||
taskId: 'task_test',
|
||
status: 'SUCCESS',
|
||
totalCount: 100,
|
||
successCount: 95,
|
||
failureCount: 5,
|
||
progress: 100
|
||
};
|
||
|
||
console.log('后端返回的数据:', backendData);
|
||
|
||
// 模拟saveImportTaskToStorage()调用的数据(前端)
|
||
const frontendSaveData = {
|
||
taskId: backendData.taskId,
|
||
status: backendData.status,
|
||
hasFailures: backendData.failureCount > 0,
|
||
totalCount: backendData.totalCount,
|
||
successCount: backendData.successCount,
|
||
failureCount: backendData.failureCount
|
||
};
|
||
|
||
console.log('前端保存的数据:', frontendSaveData);
|
||
|
||
// 验证字段映射
|
||
const fieldMappings = [
|
||
{ backend: 'taskId', frontend: 'taskId' },
|
||
{ backend: 'status', frontend: 'status' },
|
||
{ backend: 'totalCount', frontend: 'totalCount' },
|
||
{ backend: 'successCount', frontend: 'successCount' },
|
||
{ backend: 'failureCount', frontend: 'failureCount' }
|
||
];
|
||
|
||
let allMatch = true;
|
||
fieldMappings.forEach(mapping => {
|
||
const backendValue = backendData[mapping.backend];
|
||
const frontendValue = frontendSaveData[mapping.frontend];
|
||
|
||
if (backendValue === frontendValue) {
|
||
console.log(`✅ ${mapping.backend} → ${mapping.frontend}: 值一致 (${backendValue})`);
|
||
} else {
|
||
console.error(`❌ ${mapping.backend} → ${mapping.frontend}: 值不一致`);
|
||
allMatch = false;
|
||
}
|
||
});
|
||
|
||
// 验证saveTime字段
|
||
if (frontendSaveData.saveTime || typeof frontendSaveData.saveTime === 'number') {
|
||
console.log('✅ saveTime字段存在且为number类型');
|
||
} else {
|
||
console.error('❌ saveTime字段缺失或类型错误');
|
||
allMatch = false;
|
||
}
|
||
|
||
return allMatch;
|
||
}
|
||
|
||
/**
|
||
* 运行所有测试
|
||
*/
|
||
async function runAllTests() {
|
||
console.log('╔════════════════════════════════════════════════════════════╗');
|
||
console.log('║ 员工导入状态持久化功能 - 完整测试套件 ║');
|
||
console.log('╚════════════════════════════════════════════════════════════╝');
|
||
|
||
// 清理环境
|
||
localStorage.removeItem('employee_import_last_task');
|
||
console.log('✅ 测试环境已清理');
|
||
|
||
// 登录
|
||
const loginSuccess = await login();
|
||
if (!loginSuccess) {
|
||
console.error('\n❌ 测试终止:登录失败');
|
||
return;
|
||
}
|
||
|
||
const results = {
|
||
login: true,
|
||
importSuccess: false,
|
||
importWithFailures: false,
|
||
verifyStorage: false,
|
||
restoreState: false,
|
||
expiredData: false,
|
||
clearHistory: false,
|
||
fieldConsistency: false
|
||
};
|
||
|
||
// 测试1: 导入成功场景
|
||
try {
|
||
simulateImportSuccess();
|
||
const task = verifyStorageData();
|
||
results.importSuccess = (task !== null && !task.hasFailures);
|
||
} catch (error) {
|
||
console.error('❌ 导入成功场景测试失败:', error);
|
||
}
|
||
|
||
// 测试2: 导入部分失败场景
|
||
try {
|
||
localStorage.removeItem('employee_import_last_task'); // 清理
|
||
simulateImportWithFailures();
|
||
const task = verifyStorageData();
|
||
results.importWithFailures = (task !== null && task.hasFailures);
|
||
} catch (error) {
|
||
console.error('❌ 导入部分失败场景测试失败:', error);
|
||
}
|
||
|
||
// 测试3: 状态恢复
|
||
try {
|
||
const state = testRestoreState();
|
||
results.restoreState = (state !== false && state.showFailureButton === true);
|
||
} catch (error) {
|
||
console.error('❌ 状态恢复测试失败:', error);
|
||
}
|
||
|
||
// 测试4: 过期数据处理
|
||
try {
|
||
localStorage.removeItem('employee_import_last_task'); // 清理
|
||
results.expiredData = testExpiredData();
|
||
} catch (error) {
|
||
console.error('❌ 过期数据处理测试失败:', error);
|
||
}
|
||
|
||
// 测试5: 清除导入历史
|
||
try {
|
||
results.clearHistory = testClearHistory();
|
||
} catch (error) {
|
||
console.error('❌ 清除导入历史测试失败:', error);
|
||
}
|
||
|
||
// 测试6: 字段名一致性
|
||
try {
|
||
results.fieldConsistency = testFieldConsistency();
|
||
} catch (error) {
|
||
console.error('❌ 字段名一致性测试失败:', error);
|
||
}
|
||
|
||
// 输出测试报告
|
||
console.log('\n╔════════════════════════════════════════════════════════════╗');
|
||
console.log('║ 测试结果汇总 ║');
|
||
console.log('╚════════════════════════════════════════════════════════════╝\n');
|
||
|
||
const testNames = {
|
||
login: '用户登录',
|
||
importSuccess: '导入成功场景',
|
||
importWithFailures: '导入部分失败场景',
|
||
restoreState: '状态恢复逻辑',
|
||
expiredData: '过期数据处理',
|
||
clearHistory: '清除导入历史',
|
||
fieldConsistency: '字段名一致性'
|
||
};
|
||
|
||
let passCount = 0;
|
||
let failCount = 0;
|
||
|
||
Object.keys(results).forEach(key => {
|
||
const status = results[key] ? '✅ PASS' : '❌ FAIL';
|
||
const testName = testNames[key] || key;
|
||
console.log(`${status} - ${testName}`);
|
||
|
||
if (results[key]) {
|
||
passCount++;
|
||
} else {
|
||
failCount++;
|
||
}
|
||
});
|
||
|
||
console.log('\n--------------------------------------------------------');
|
||
console.log(`总计: ${passCount + failCount} 个测试`);
|
||
console.log(`通过: ${passCount} 个`);
|
||
console.log(`失败: ${failCount} 个`);
|
||
console.log('--------------------------------------------------------\n');
|
||
|
||
if (failCount === 0) {
|
||
console.log('🎉 所有测试通过!导入状态持久化功能正常工作。');
|
||
} else {
|
||
console.log('⚠️ 部分测试失败,请检查相关功能。');
|
||
}
|
||
|
||
// 清理测试数据
|
||
localStorage.removeItem('employee_import_last_task');
|
||
console.log('✅ 测试数据已清理\n');
|
||
}
|
||
|
||
// 运行测试
|
||
runAllTests().catch(error => {
|
||
console.error('❌ 测试执行异常:', error);
|
||
process.exit(1);
|
||
});
|