1558 lines
43 KiB
JavaScript
1558 lines
43 KiB
JavaScript
|
|
/**
|
|||
|
|
* 集成测试和性能优化模块
|
|||
|
|
* 对所有事件处理器进行集成测试、性能监控和优化建议
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { eventBus } from '../eventBus.js';
|
|||
|
|
import { panelHandler, PANEL_EVENT_TYPES } from './PanelHandler.js';
|
|||
|
|
import tabPageHandler, { TABPAGE_EVENT_TYPES } from './TabPageHandler.js';
|
|||
|
|
import areaHandler, { AREA_EVENT_TYPES } from './AreaHandler.js';
|
|||
|
|
import globalEventManager, { GLOBAL_EVENT_TYPES, globalEventActions } from './GlobalEventManager.js';
|
|||
|
|
import dragStateManager, { DRAG_STATE_TYPES, dragStateActions } from './DragStateManager.js';
|
|||
|
|
|
|||
|
|
// 测试配置
|
|||
|
|
export const TEST_CONFIG = {
|
|||
|
|
// 测试环境配置
|
|||
|
|
testEnvironment: 'development',
|
|||
|
|
|
|||
|
|
// 性能阈值配置
|
|||
|
|
performanceThresholds: {
|
|||
|
|
eventEmitTime: 10, // 事件发射时间阈值(毫秒)
|
|||
|
|
eventHandleTime: 50, // 事件处理时间阈值(毫秒)
|
|||
|
|
memoryUsage: 50 * 1024 * 1024, // 内存使用阈值(50MB)
|
|||
|
|
cpuUsage: 80, // CPU使用率阈值(%)
|
|||
|
|
dragFPS: 30, // 拖拽帧率阈值
|
|||
|
|
dragDuration: 3000, // 拖拽持续时间阈值(毫秒)
|
|||
|
|
concurrentEvents: 100 // 并发事件数量阈值
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 测试用例配置
|
|||
|
|
testCases: {
|
|||
|
|
// Panel相关测试用例
|
|||
|
|
panel: {
|
|||
|
|
createPanel: { priority: 1, timeout: 5000 },
|
|||
|
|
destroyPanel: { priority: 1, timeout: 5000 },
|
|||
|
|
maximizePanel: { priority: 1, timeout: 3000 },
|
|||
|
|
minimizePanel: { priority: 1, timeout: 3000 },
|
|||
|
|
restorePanel: { priority: 1, timeout: 3000 },
|
|||
|
|
closePanel: { priority: 1, timeout: 5000 }
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// TabPage相关测试用例
|
|||
|
|
tabpage: {
|
|||
|
|
createTabPage: { priority: 1, timeout: 5000 },
|
|||
|
|
destroyTabPage: { priority: 1, timeout: 5000 },
|
|||
|
|
switchTabPage: { priority: 1, timeout: 3000 },
|
|||
|
|
closeTabPage: { priority: 1, timeout: 5000 },
|
|||
|
|
moveTabPage: { priority: 1, timeout: 5000 }
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// Area相关测试用例
|
|||
|
|
area: {
|
|||
|
|
createArea: { priority: 1, timeout: 5000 },
|
|||
|
|
destroyArea: { priority: 1, timeout: 5000 },
|
|||
|
|
dockArea: { priority: 1, timeout: 8000 },
|
|||
|
|
mergeArea: { priority: 1, timeout: 10000 },
|
|||
|
|
splitArea: { priority: 1, timeout: 8000 }
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 拖拽相关测试用例
|
|||
|
|
drag: {
|
|||
|
|
panelDrag: { priority: 1, timeout: 10000 },
|
|||
|
|
tabpageDrag: { priority: 1, timeout: 10000 },
|
|||
|
|
areaDrag: { priority: 1, timeout: 15000 },
|
|||
|
|
multiDrag: { priority: 1, timeout: 20000 }
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 集成测试用例
|
|||
|
|
integration: {
|
|||
|
|
panelTabpage: { priority: 1, timeout: 10000 },
|
|||
|
|
areaPanel: { priority: 1, timeout: 15000 },
|
|||
|
|
crossComponent: { priority: 1, timeout: 20000 },
|
|||
|
|
concurrentEvents: { priority: 1, timeout: 30000 }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 测试结果类
|
|||
|
|
class TestResult {
|
|||
|
|
constructor(testName, testType) {
|
|||
|
|
this.testName = testName;
|
|||
|
|
this.testType = testType;
|
|||
|
|
this.startTime = Date.now();
|
|||
|
|
this.endTime = null;
|
|||
|
|
this.duration = 0;
|
|||
|
|
this.status = 'pending'; // pending, running, passed, failed, timeout
|
|||
|
|
this.error = null;
|
|||
|
|
this.metrics = {
|
|||
|
|
eventCount: 0,
|
|||
|
|
handledEvents: 0,
|
|||
|
|
failedEvents: 0,
|
|||
|
|
averageHandleTime: 0,
|
|||
|
|
maxHandleTime: 0,
|
|||
|
|
minHandleTime: Infinity,
|
|||
|
|
memoryUsage: {
|
|||
|
|
before: null,
|
|||
|
|
after: null,
|
|||
|
|
delta: null
|
|||
|
|
},
|
|||
|
|
performance: {
|
|||
|
|
eventEmitTimes: [],
|
|||
|
|
eventHandleTimes: [],
|
|||
|
|
fps: []
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
this.events = [];
|
|||
|
|
this.assertions = [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 添加事件
|
|||
|
|
* @param {Object} event - 事件对象
|
|||
|
|
*/
|
|||
|
|
addEvent(event) {
|
|||
|
|
this.events.push({
|
|||
|
|
...event,
|
|||
|
|
timestamp: Date.now()
|
|||
|
|
});
|
|||
|
|
this.metrics.eventCount++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 记录事件处理
|
|||
|
|
* @param {boolean} success - 是否成功
|
|||
|
|
* @param {number} handleTime - 处理时间
|
|||
|
|
* @param {Object} data - 附加数据
|
|||
|
|
*/
|
|||
|
|
recordHandle(success, handleTime, data = {}) {
|
|||
|
|
this.metrics.handledEvents++;
|
|||
|
|
if (!success) {
|
|||
|
|
this.metrics.failedEvents++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.metrics.eventHandleTimes.push(handleTime);
|
|||
|
|
this.metrics.maxHandleTime = Math.max(this.metrics.maxHandleTime, handleTime);
|
|||
|
|
this.metrics.minHandleTime = Math.min(this.metrics.minHandleTime, handleTime);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 记录性能指标
|
|||
|
|
* @param {Object} performance - 性能数据
|
|||
|
|
*/
|
|||
|
|
recordPerformance(performance) {
|
|||
|
|
Object.assign(this.metrics.performance, performance);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 添加断言
|
|||
|
|
* @param {boolean} condition - 断言条件
|
|||
|
|
* @param {string} message - 断言消息
|
|||
|
|
* @param {Object} expected - 期望值
|
|||
|
|
* @param {Object} actual - 实际值
|
|||
|
|
*/
|
|||
|
|
addAssertion(condition, message, expected = null, actual = null) {
|
|||
|
|
this.assertions.push({
|
|||
|
|
condition,
|
|||
|
|
message,
|
|||
|
|
expected,
|
|||
|
|
actual,
|
|||
|
|
timestamp: Date.now()
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!condition) {
|
|||
|
|
this.status = 'failed';
|
|||
|
|
this.error = `断言失败: ${message}`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 标记为完成
|
|||
|
|
* @param {string} status - 完成状态
|
|||
|
|
* @param {Error} error - 错误信息
|
|||
|
|
*/
|
|||
|
|
complete(status = 'passed', error = null) {
|
|||
|
|
this.endTime = Date.now();
|
|||
|
|
this.duration = this.endTime - this.startTime;
|
|||
|
|
this.status = status;
|
|||
|
|
this.error = error;
|
|||
|
|
|
|||
|
|
// 计算平均处理时间
|
|||
|
|
if (this.metrics.eventHandleTimes.length > 0) {
|
|||
|
|
this.metrics.averageHandleTime =
|
|||
|
|
this.metrics.eventHandleTimes.reduce((sum, time) => sum + time, 0) /
|
|||
|
|
this.metrics.eventHandleTimes.length;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取测试摘要
|
|||
|
|
* @returns {Object} 测试摘要
|
|||
|
|
*/
|
|||
|
|
getSummary() {
|
|||
|
|
const passedAssertions = this.assertions.filter(a => a.condition).length;
|
|||
|
|
const totalAssertions = this.assertions.length;
|
|||
|
|
const successRate = totalAssertions > 0 ? (passedAssertions / totalAssertions) * 100 : 100;
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
testName: this.testName,
|
|||
|
|
testType: this.testType,
|
|||
|
|
status: this.status,
|
|||
|
|
duration: this.duration,
|
|||
|
|
error: this.error,
|
|||
|
|
metrics: {
|
|||
|
|
...this.metrics,
|
|||
|
|
eventCount: this.events.length,
|
|||
|
|
successRate: successRate,
|
|||
|
|
assertionResults: {
|
|||
|
|
passed: passedAssertions,
|
|||
|
|
failed: totalAssertions - passedAssertions,
|
|||
|
|
total: totalAssertions
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 性能监控器
|
|||
|
|
class PerformanceMonitor {
|
|||
|
|
constructor() {
|
|||
|
|
this.metrics = new Map();
|
|||
|
|
this.alerts = [];
|
|||
|
|
this.monitoringActive = false;
|
|||
|
|
this.memorySamples = [];
|
|||
|
|
this.performanceObserver = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 开始监控
|
|||
|
|
*/
|
|||
|
|
start() {
|
|||
|
|
if (this.monitoringActive) return;
|
|||
|
|
|
|||
|
|
this.monitoringActive = true;
|
|||
|
|
|
|||
|
|
// 启动性能观察器
|
|||
|
|
if (typeof PerformanceObserver !== 'undefined') {
|
|||
|
|
this.performanceObserver = new PerformanceObserver((list) => {
|
|||
|
|
const entries = list.getEntries();
|
|||
|
|
entries.forEach(entry => {
|
|||
|
|
this._recordPerformanceEntry(entry);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
this.performanceObserver.observe({ entryTypes: ['measure', 'navigation', 'paint'] });
|
|||
|
|
} catch (error) {
|
|||
|
|
console.warn('⚠️ 性能观察器不支持某些观察类型:', error.message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 启动内存监控
|
|||
|
|
this._startMemoryMonitoring();
|
|||
|
|
|
|||
|
|
console.log('📊 性能监控已启动');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 停止监控
|
|||
|
|
*/
|
|||
|
|
stop() {
|
|||
|
|
this.monitoringActive = false;
|
|||
|
|
|
|||
|
|
if (this.performanceObserver) {
|
|||
|
|
this.performanceObserver.disconnect();
|
|||
|
|
this.performanceObserver = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('📊 性能监控已停止');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 记录性能条目
|
|||
|
|
* @param {PerformanceEntry} entry - 性能条目
|
|||
|
|
*/
|
|||
|
|
_recordPerformanceEntry(entry) {
|
|||
|
|
if (!this.monitoringActive) return;
|
|||
|
|
|
|||
|
|
const key = `${entry.name}-${entry.entryType}`;
|
|||
|
|
const currentMetrics = this.metrics.get(key) || {
|
|||
|
|
count: 0,
|
|||
|
|
total: 0,
|
|||
|
|
average: 0,
|
|||
|
|
min: Infinity,
|
|||
|
|
max: 0,
|
|||
|
|
samples: []
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
currentMetrics.count++;
|
|||
|
|
if (entry.duration) {
|
|||
|
|
currentMetrics.total += entry.duration;
|
|||
|
|
currentMetrics.average = currentMetrics.total / currentMetrics.count;
|
|||
|
|
currentMetrics.min = Math.min(currentMetrics.min, entry.duration);
|
|||
|
|
currentMetrics.max = Math.max(currentMetrics.max, entry.duration);
|
|||
|
|
currentMetrics.samples.push(entry.duration);
|
|||
|
|
|
|||
|
|
// 限制样本数量
|
|||
|
|
if (currentMetrics.samples.length > 100) {
|
|||
|
|
currentMetrics.samples.shift();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.metrics.set(key, currentMetrics);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动内存监控
|
|||
|
|
*/
|
|||
|
|
_startMemoryMonitoring() {
|
|||
|
|
setInterval(() => {
|
|||
|
|
if (!this.monitoringActive) return;
|
|||
|
|
|
|||
|
|
// 获取内存信息(如果支持)
|
|||
|
|
if (performance.memory) {
|
|||
|
|
const memoryInfo = {
|
|||
|
|
used: performance.memory.usedJSHeapSize,
|
|||
|
|
total: performance.memory.totalJSHeapSize,
|
|||
|
|
limit: performance.memory.jsHeapSizeLimit,
|
|||
|
|
timestamp: Date.now()
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
this.memorySamples.push(memoryInfo);
|
|||
|
|
|
|||
|
|
// 限制样本数量
|
|||
|
|
if (this.memorySamples.length > 100) {
|
|||
|
|
this.memorySamples.shift();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查内存阈值
|
|||
|
|
if (memoryInfo.used > TEST_CONFIG.performanceThresholds.memoryUsage) {
|
|||
|
|
this._createAlert('memory_threshold', '内存使用量超过阈值', {
|
|||
|
|
current: memoryInfo.used,
|
|||
|
|
threshold: TEST_CONFIG.performanceThresholds.memoryUsage
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}, 5000); // 每5秒检查一次
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 创建告警
|
|||
|
|
* @param {string} type - 告警类型
|
|||
|
|
* @param {string} message - 告警消息
|
|||
|
|
* @param {Object} data - 告警数据
|
|||
|
|
*/
|
|||
|
|
_createAlert(type, message, data) {
|
|||
|
|
const alert = {
|
|||
|
|
id: `alert-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|||
|
|
type,
|
|||
|
|
message,
|
|||
|
|
data,
|
|||
|
|
timestamp: Date.now(),
|
|||
|
|
acknowledged: false
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
this.alerts.push(alert);
|
|||
|
|
|
|||
|
|
// 限制告警数量
|
|||
|
|
if (this.alerts.length > 50) {
|
|||
|
|
this.alerts.shift();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.warn(`🚨 性能告警 [${type}]: ${message}`, data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取性能摘要
|
|||
|
|
* @returns {Object} 性能摘要
|
|||
|
|
*/
|
|||
|
|
getPerformanceSummary() {
|
|||
|
|
const summary = {
|
|||
|
|
metrics: Object.fromEntries(this.metrics),
|
|||
|
|
memory: {
|
|||
|
|
current: this.memorySamples.length > 0 ? this.memorySamples[this.memorySamples.length - 1] : null,
|
|||
|
|
samples: this.memorySamples.length,
|
|||
|
|
trend: this._calculateMemoryTrend()
|
|||
|
|
},
|
|||
|
|
alerts: {
|
|||
|
|
total: this.alerts.length,
|
|||
|
|
unacknowledged: this.alerts.filter(a => !a.acknowledged).length,
|
|||
|
|
recent: this.alerts.slice(-10)
|
|||
|
|
},
|
|||
|
|
monitoring: {
|
|||
|
|
active: this.monitoringActive,
|
|||
|
|
uptime: Date.now() - (this.startTime || Date.now())
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return summary;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 计算内存趋势
|
|||
|
|
* @returns {Object} 内存趋势
|
|||
|
|
*/
|
|||
|
|
_calculateMemoryTrend() {
|
|||
|
|
if (this.memorySamples.length < 2) return { direction: 'unknown', change: 0 };
|
|||
|
|
|
|||
|
|
const recent = this.memorySamples.slice(-10);
|
|||
|
|
const first = recent[0];
|
|||
|
|
const last = recent[recent.length - 1];
|
|||
|
|
|
|||
|
|
const change = last.used - first.used;
|
|||
|
|
const direction = change > 1024 * 1024 ? 'increasing' : change < -1024 * 1024 ? 'decreasing' : 'stable';
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
direction,
|
|||
|
|
change,
|
|||
|
|
changeMB: change / (1024 * 1024),
|
|||
|
|
period: last.timestamp - first.timestamp
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 确认告警
|
|||
|
|
* @param {string} alertId - 告警ID
|
|||
|
|
*/
|
|||
|
|
acknowledgeAlert(alertId) {
|
|||
|
|
const alert = this.alerts.find(a => a.id === alertId);
|
|||
|
|
if (alert) {
|
|||
|
|
alert.acknowledged = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清除告警
|
|||
|
|
* @param {string} alertId - 告警ID
|
|||
|
|
*/
|
|||
|
|
clearAlert(alertId) {
|
|||
|
|
const index = this.alerts.findIndex(a => a.id === alertId);
|
|||
|
|
if (index > -1) {
|
|||
|
|
this.alerts.splice(index, 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清除所有告警
|
|||
|
|
*/
|
|||
|
|
clearAllAlerts() {
|
|||
|
|
this.alerts = [];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 集成测试器主类
|
|||
|
|
class IntegrationTester {
|
|||
|
|
constructor() {
|
|||
|
|
this.testResults = new Map();
|
|||
|
|
this.performanceMonitor = new PerformanceMonitor();
|
|||
|
|
this.isRunning = false;
|
|||
|
|
this.testSuites = new Map();
|
|||
|
|
|
|||
|
|
this._initializeTestSuites();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 初始化测试套件
|
|||
|
|
*/
|
|||
|
|
_initializeTestSuites() {
|
|||
|
|
// Panel测试套件
|
|||
|
|
this.testSuites.set('panel', {
|
|||
|
|
name: 'Panel组件测试套件',
|
|||
|
|
tests: Object.keys(TEST_CONFIG.testCases.panel)
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// TabPage测试套件
|
|||
|
|
this.testSuites.set('tabpage', {
|
|||
|
|
name: 'TabPage组件测试套件',
|
|||
|
|
tests: Object.keys(TEST_CONFIG.testCases.tabpage)
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Area测试套件
|
|||
|
|
this.testSuites.set('area', {
|
|||
|
|
name: 'Area组件测试套件',
|
|||
|
|
tests: Object.keys(TEST_CONFIG.testCases.area)
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 拖拽测试套件
|
|||
|
|
this.testSuites.set('drag', {
|
|||
|
|
name: '拖拽功能测试套件',
|
|||
|
|
tests: Object.keys(TEST_CONFIG.testCases.drag)
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 集成测试套件
|
|||
|
|
this.testSuites.set('integration', {
|
|||
|
|
name: '集成测试套件',
|
|||
|
|
tests: Object.keys(TEST_CONFIG.testCases.integration)
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行所有测试
|
|||
|
|
* @param {Array} suiteNames - 要运行的测试套件名称
|
|||
|
|
* @returns {Promise} 测试结果
|
|||
|
|
*/
|
|||
|
|
async runAllTests(suiteNames = null) {
|
|||
|
|
if (this.isRunning) {
|
|||
|
|
throw new Error('测试已在运行中');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.isRunning = true;
|
|||
|
|
console.log('🚀 开始运行集成测试...');
|
|||
|
|
|
|||
|
|
// 启动性能监控
|
|||
|
|
this.performanceMonitor.start();
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const results = {};
|
|||
|
|
const suitesToRun = suiteNames || Array.from(this.testSuites.keys());
|
|||
|
|
|
|||
|
|
for (const suiteName of suitesToRun) {
|
|||
|
|
console.log(`\n📋 运行测试套件: ${suiteName}`);
|
|||
|
|
results[suiteName] = await this._runTestSuite(suiteName);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成测试报告
|
|||
|
|
const report = this._generateTestReport(results);
|
|||
|
|
|
|||
|
|
// 显示结果
|
|||
|
|
this._displayTestResults(report);
|
|||
|
|
|
|||
|
|
return report;
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('❌ 测试执行失败:', error);
|
|||
|
|
throw error;
|
|||
|
|
} finally {
|
|||
|
|
this.isRunning = false;
|
|||
|
|
this.performanceMonitor.stop();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行单个测试套件
|
|||
|
|
* @param {string} suiteName - 测试套件名称
|
|||
|
|
* @returns {Promise} 测试结果
|
|||
|
|
*/
|
|||
|
|
async _runTestSuite(suiteName) {
|
|||
|
|
const suite = this.testSuites.get(suiteName);
|
|||
|
|
if (!suite) {
|
|||
|
|
throw new Error(`未知测试套件: ${suiteName}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const suiteResults = [];
|
|||
|
|
|
|||
|
|
for (const testName of suite.tests) {
|
|||
|
|
console.log(` 🧪 运行测试: ${testName}`);
|
|||
|
|
const result = await this._runSingleTest(suiteName, testName);
|
|||
|
|
suiteResults.push(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return suiteResults;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行单个测试
|
|||
|
|
* @param {string} suiteName - 测试套件名称
|
|||
|
|
* @param {string} testName - 测试名称
|
|||
|
|
* @returns {Promise} 测试结果
|
|||
|
|
*/
|
|||
|
|
async _runSingleTest(suiteName, testName) {
|
|||
|
|
const testConfig = TEST_CONFIG.testCases[suiteName][testName];
|
|||
|
|
const result = new TestResult(testName, suiteName);
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 记录开始时间
|
|||
|
|
result.startTime = Date.now();
|
|||
|
|
|
|||
|
|
// 根据测试类型执行相应测试
|
|||
|
|
switch (suiteName) {
|
|||
|
|
case 'panel':
|
|||
|
|
await this._runPanelTest(testName, testConfig, result);
|
|||
|
|
break;
|
|||
|
|
case 'tabpage':
|
|||
|
|
await this._runTabPageTest(testName, testConfig, result);
|
|||
|
|
break;
|
|||
|
|
case 'area':
|
|||
|
|
await this._runAreaTest(testName, testConfig, result);
|
|||
|
|
break;
|
|||
|
|
case 'drag':
|
|||
|
|
await this._runDragTest(testName, testConfig, result);
|
|||
|
|
break;
|
|||
|
|
case 'integration':
|
|||
|
|
await this._runIntegrationTest(testName, testConfig, result);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 完成测试
|
|||
|
|
result.complete('passed');
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
result.complete('failed', error);
|
|||
|
|
console.error(`❌ 测试失败 [${suiteName}.${testName}]:`, error.message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.testResults.set(`${suiteName}.${testName}`, result);
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行Panel测试
|
|||
|
|
* @param {string} testName - 测试名称
|
|||
|
|
* @param {Object} config - 测试配置
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _runPanelTest(testName, config, result) {
|
|||
|
|
switch (testName) {
|
|||
|
|
case 'createPanel':
|
|||
|
|
await this._testCreatePanel(result);
|
|||
|
|
break;
|
|||
|
|
case 'destroyPanel':
|
|||
|
|
await this._testDestroyPanel(result);
|
|||
|
|
break;
|
|||
|
|
case 'maximizePanel':
|
|||
|
|
await this._testMaximizePanel(result);
|
|||
|
|
break;
|
|||
|
|
case 'minimizePanel':
|
|||
|
|
await this._testMinimizePanel(result);
|
|||
|
|
break;
|
|||
|
|
case 'restorePanel':
|
|||
|
|
await this._testRestorePanel(result);
|
|||
|
|
break;
|
|||
|
|
case 'closePanel':
|
|||
|
|
await this._testClosePanel(result);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行TabPage测试
|
|||
|
|
* @param {string} testName - 测试名称
|
|||
|
|
* @param {Object} config - 测试配置
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _runTabPageTest(testName, config, result) {
|
|||
|
|
switch (testName) {
|
|||
|
|
case 'createTabPage':
|
|||
|
|
await this._testCreateTabPage(result);
|
|||
|
|
break;
|
|||
|
|
case 'destroyTabPage':
|
|||
|
|
await this._testDestroyTabPage(result);
|
|||
|
|
break;
|
|||
|
|
case 'switchTabPage':
|
|||
|
|
await this._testSwitchTabPage(result);
|
|||
|
|
break;
|
|||
|
|
case 'closeTabPage':
|
|||
|
|
await this._testCloseTabPage(result);
|
|||
|
|
break;
|
|||
|
|
case 'moveTabPage':
|
|||
|
|
await this._testMoveTabPage(result);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行Area测试
|
|||
|
|
* @param {string} testName - 测试名称
|
|||
|
|
* @param {Object} config - 测试配置
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _runAreaTest(testName, config, result) {
|
|||
|
|
switch (testName) {
|
|||
|
|
case 'createArea':
|
|||
|
|
await this._testCreateArea(result);
|
|||
|
|
break;
|
|||
|
|
case 'destroyArea':
|
|||
|
|
await this._testDestroyArea(result);
|
|||
|
|
break;
|
|||
|
|
case 'dockArea':
|
|||
|
|
await this._testDockArea(result);
|
|||
|
|
break;
|
|||
|
|
case 'mergeArea':
|
|||
|
|
await this._testMergeArea(result);
|
|||
|
|
break;
|
|||
|
|
case 'splitArea':
|
|||
|
|
await this._testSplitArea(result);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行拖拽测试
|
|||
|
|
* @param {string} testName - 测试名称
|
|||
|
|
* @param {Object} config - 测试配置
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _runDragTest(testName, config, result) {
|
|||
|
|
switch (testName) {
|
|||
|
|
case 'panelDrag':
|
|||
|
|
await this._testPanelDrag(result);
|
|||
|
|
break;
|
|||
|
|
case 'tabpageDrag':
|
|||
|
|
await this._testTabPageDrag(result);
|
|||
|
|
break;
|
|||
|
|
case 'areaDrag':
|
|||
|
|
await this._testAreaDrag(result);
|
|||
|
|
break;
|
|||
|
|
case 'multiDrag':
|
|||
|
|
await this._testMultiDrag(result);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行集成测试
|
|||
|
|
* @param {string} testName - 测试名称
|
|||
|
|
* @param {Object} config - 测试配置
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _runIntegrationTest(testName, config, result) {
|
|||
|
|
switch (testName) {
|
|||
|
|
case 'panelTabpage':
|
|||
|
|
await this._testPanelTabPageIntegration(result);
|
|||
|
|
break;
|
|||
|
|
case 'areaPanel':
|
|||
|
|
await this._testAreaPanelIntegration(result);
|
|||
|
|
break;
|
|||
|
|
case 'crossComponent':
|
|||
|
|
await this._testCrossComponentIntegration(result);
|
|||
|
|
break;
|
|||
|
|
case 'concurrentEvents':
|
|||
|
|
await this._testConcurrentEvents(result);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试创建Panel
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testCreatePanel(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
// 模拟Panel创建事件
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_CREATE_REQUEST, {
|
|||
|
|
panelId: `test-panel-${Date.now()}`,
|
|||
|
|
title: '测试Panel',
|
|||
|
|
content: '测试内容'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 等待处理完成
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
// 添加断言
|
|||
|
|
result.addAssertion(true, 'Panel创建事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试销毁Panel
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testDestroyPanel(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_DESTROY_REQUEST, {
|
|||
|
|
panelId: 'test-panel-destroy'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Panel销毁事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试最大化Panel
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testMaximizePanel(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_MAXIMIZE, {
|
|||
|
|
panelId: 'test-panel-maximize'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Panel最大化事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试最小化Panel
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testMinimizePanel(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_MINIMIZE, {
|
|||
|
|
panelId: 'test-panel-minimize'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Panel最小化事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试还原Panel
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testRestorePanel(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_RESTORE, {
|
|||
|
|
panelId: 'test-panel-restore'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Panel还原事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试关闭Panel
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testClosePanel(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_CLOSE_REQUEST, {
|
|||
|
|
panelId: 'test-panel-close'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Panel关闭事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试创建TabPage
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testCreateTabPage(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CREATE_REQUEST, {
|
|||
|
|
tabPageId: `test-tabpage-${Date.now()}`,
|
|||
|
|
title: '测试TabPage',
|
|||
|
|
content: '测试内容'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'TabPage创建事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试销毁TabPage
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testDestroyTabPage(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_DESTROY_REQUEST, {
|
|||
|
|
tabPageId: 'test-tabpage-destroy'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'TabPage销毁事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试切换TabPage
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testSwitchTabPage(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_SWITCH, {
|
|||
|
|
tabPageId: 'test-tabpage-switch',
|
|||
|
|
targetIndex: 1
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'TabPage切换事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试关闭TabPage
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testCloseTabPage(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CLOSE_REQUEST, {
|
|||
|
|
tabPageId: 'test-tabpage-close'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'TabPage关闭事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试移动TabPage
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testMoveTabPage(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_MOVE, {
|
|||
|
|
tabPageId: 'test-tabpage-move',
|
|||
|
|
targetPosition: { x: 100, y: 200 }
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'TabPage移动事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试创建Area
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testCreateArea(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(AREA_EVENT_TYPES.AREA_CREATE_REQUEST, {
|
|||
|
|
areaId: `test-area-${Date.now()}`,
|
|||
|
|
type: 'dockable'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Area创建事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试销毁Area
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testDestroyArea(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(AREA_EVENT_TYPES.AREA_DESTROY_REQUEST, {
|
|||
|
|
areaId: 'test-area-destroy'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Area销毁事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试停靠Area
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testDockArea(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(AREA_EVENT_TYPES.AREA_DOCK_CENTER, {
|
|||
|
|
areaId: 'test-area-dock',
|
|||
|
|
targetAreaId: 'target-area'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Area停靠事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试合并Area
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testMergeArea(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(AREA_EVENT_TYPES.AREA_MERGE, {
|
|||
|
|
sourceAreaId: 'source-area',
|
|||
|
|
targetAreaId: 'target-area',
|
|||
|
|
mergeType: 'horizontal'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Area合并事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试分割Area
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testSplitArea(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit(AREA_EVENT_TYPES.AREA_SPLIT, {
|
|||
|
|
areaId: 'test-area-split',
|
|||
|
|
splitType: 'vertical',
|
|||
|
|
splitRatio: 0.5
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Area分割事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试Panel拖拽
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testPanelDrag(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
// 模拟拖拽开始
|
|||
|
|
eventBus.emit('panel.drag.start', {
|
|||
|
|
dragId: 'test-panel-drag',
|
|||
|
|
panelId: 'test-panel-drag-id',
|
|||
|
|
startPosition: { x: 100, y: 100 }
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 模拟拖拽移动
|
|||
|
|
for (let i = 0; i < 10; i++) {
|
|||
|
|
eventBus.emit('panel.drag.move', {
|
|||
|
|
dragId: 'test-panel-drag',
|
|||
|
|
currentPosition: { x: 100 + i * 10, y: 100 + i * 5 }
|
|||
|
|
});
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 16)); // 模拟60fps
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 模拟拖拽结束
|
|||
|
|
eventBus.emit('panel.drag.end', {
|
|||
|
|
dragId: 'test-panel-drag',
|
|||
|
|
finalPosition: { x: 200, y: 150 },
|
|||
|
|
success: true
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Panel拖拽事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试TabPage拖拽
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testTabPageDrag(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit('tabpage.drag.start', {
|
|||
|
|
dragId: 'test-tabpage-drag',
|
|||
|
|
tabPageId: 'test-tabpage-drag-id',
|
|||
|
|
startPosition: { x: 50, y: 50 }
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
eventBus.emit('tabpage.drag.move', {
|
|||
|
|
dragId: 'test-tabpage-drag',
|
|||
|
|
currentPosition: { x: 150, y: 100 }
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
eventBus.emit('tabpage.drag.end', {
|
|||
|
|
dragId: 'test-tabpage-drag',
|
|||
|
|
finalPosition: { x: 150, y: 100 },
|
|||
|
|
success: true
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'TabPage拖拽事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试Area拖拽
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testAreaDrag(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
eventBus.emit('area.drag.start', {
|
|||
|
|
dragId: 'test-area-drag',
|
|||
|
|
areaId: 'test-area-drag-id',
|
|||
|
|
startPosition: { x: 200, y: 200 }
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
eventBus.emit('area.drag.move', {
|
|||
|
|
dragId: 'test-area-drag',
|
|||
|
|
currentPosition: { x: 300, y: 250 }
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
eventBus.emit('area.drag.end', {
|
|||
|
|
dragId: 'test-area-drag',
|
|||
|
|
finalPosition: { x: 300, y: 250 },
|
|||
|
|
success: true
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Area拖拽事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试多拖拽
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testMultiDrag(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
const dragIds = ['test-multi-drag-1', 'test-multi-drag-2', 'test-multi-drag-3'];
|
|||
|
|
|
|||
|
|
// 同时启动多个拖拽
|
|||
|
|
dragIds.forEach((dragId, index) => {
|
|||
|
|
eventBus.emit('panel.drag.start', {
|
|||
|
|
dragId,
|
|||
|
|
panelId: `panel-${index}`,
|
|||
|
|
startPosition: { x: 50 + index * 100, y: 50 }
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 模拟同时移动
|
|||
|
|
for (let i = 0; i < 5; i++) {
|
|||
|
|
dragIds.forEach((dragId, index) => {
|
|||
|
|
eventBus.emit('panel.drag.move', {
|
|||
|
|
dragId,
|
|||
|
|
currentPosition: { x: 50 + index * 100 + i * 20, y: 50 + i * 10 }
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 33)); // 模拟30fps
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 结束所有拖拽
|
|||
|
|
dragIds.forEach((dragId, index) => {
|
|||
|
|
eventBus.emit('panel.drag.end', {
|
|||
|
|
dragId,
|
|||
|
|
finalPosition: { x: 50 + index * 100 + 100, y: 50 + 50 },
|
|||
|
|
success: true
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, '多拖拽事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试Panel和TabPage集成
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testPanelTabPageIntegration(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
// 创建Panel,然后在其中创建TabPage
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_CREATE_REQUEST, {
|
|||
|
|
panelId: 'integration-panel',
|
|||
|
|
title: '集成测试Panel',
|
|||
|
|
content: '包含TabPage的Panel'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CREATE_REQUEST, {
|
|||
|
|
tabPageId: 'integration-tabpage',
|
|||
|
|
title: '集成测试TabPage',
|
|||
|
|
parentPanelId: 'integration-panel'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Panel和TabPage集成应正确工作', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试Area和Panel集成
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testAreaPanelIntegration(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
// 创建Area,然后在其中创建Panel
|
|||
|
|
eventBus.emit(AREA_EVENT_TYPES.AREA_CREATE_REQUEST, {
|
|||
|
|
areaId: 'integration-area',
|
|||
|
|
type: 'container'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_CREATE_REQUEST, {
|
|||
|
|
panelId: 'integration-area-panel',
|
|||
|
|
title: 'Area中的Panel',
|
|||
|
|
parentAreaId: 'integration-area'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, 'Area和Panel集成应正确工作', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试跨组件通信
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testCrossComponentIntegration(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
// 发送跨组件请求
|
|||
|
|
eventBus.emit(GLOBAL_EVENT_TYPES.CROSS_COMPONENT_REQUEST, {
|
|||
|
|
requestId: 'test-request',
|
|||
|
|
targetComponent: 'panel',
|
|||
|
|
action: 'createPanel',
|
|||
|
|
payload: { title: '跨组件创建的Panel' }
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, '跨组件通信应正确工作', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 测试并发事件
|
|||
|
|
* @param {TestResult} result - 测试结果
|
|||
|
|
*/
|
|||
|
|
async _testConcurrentEvents(result) {
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
const promises = [];
|
|||
|
|
|
|||
|
|
// 并发发送多个事件
|
|||
|
|
for (let i = 0; i < 20; i++) {
|
|||
|
|
promises.push(Promise.resolve().then(() => {
|
|||
|
|
eventBus.emit(PANEL_EVENT_TYPES.PANEL_CREATE_REQUEST, {
|
|||
|
|
panelId: `concurrent-panel-${i}`,
|
|||
|
|
title: `并发Panel ${i}`
|
|||
|
|
});
|
|||
|
|
}));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
await Promise.all(promises);
|
|||
|
|
|
|||
|
|
const handleTime = performance.now() - startTime;
|
|||
|
|
result.recordHandle(true, handleTime);
|
|||
|
|
|
|||
|
|
result.addAssertion(true, '并发事件应被正确处理', true, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成测试报告
|
|||
|
|
* @param {Object} results - 测试结果
|
|||
|
|
* @returns {Object} 测试报告
|
|||
|
|
*/
|
|||
|
|
_generateTestReport(results) {
|
|||
|
|
const allResults = Object.values(results).flat();
|
|||
|
|
const performanceSummary = this.performanceMonitor.getPerformanceSummary();
|
|||
|
|
|
|||
|
|
const report = {
|
|||
|
|
timestamp: new Date().toISOString(),
|
|||
|
|
summary: {
|
|||
|
|
total: allResults.length,
|
|||
|
|
passed: allResults.filter(r => r.status === 'passed').length,
|
|||
|
|
failed: allResults.filter(r => r.status === 'failed').length,
|
|||
|
|
timeout: allResults.filter(r => r.status === 'timeout').length,
|
|||
|
|
successRate: allResults.length > 0 ?
|
|||
|
|
(allResults.filter(r => r.status === 'passed').length / allResults.length * 100).toFixed(2) : 0
|
|||
|
|
},
|
|||
|
|
performance: performanceSummary,
|
|||
|
|
suites: {},
|
|||
|
|
issues: [],
|
|||
|
|
recommendations: []
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 为每个套件生成报告
|
|||
|
|
for (const [suiteName, suiteResults] of Object.entries(results)) {
|
|||
|
|
const passed = suiteResults.filter(r => r.status === 'passed').length;
|
|||
|
|
const total = suiteResults.length;
|
|||
|
|
|
|||
|
|
report.suites[suiteName] = {
|
|||
|
|
name: this.testSuites.get(suiteName)?.name || suiteName,
|
|||
|
|
total,
|
|||
|
|
passed,
|
|||
|
|
failed: total - passed,
|
|||
|
|
successRate: total > 0 ? (passed / total * 100).toFixed(2) : 0,
|
|||
|
|
averageDuration: suiteResults.reduce((sum, r) => sum + r.duration, 0) / total || 0,
|
|||
|
|
results: suiteResults.map(r => r.getSummary())
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 分析问题和建议
|
|||
|
|
this._analyzeIssuesAndRecommendations(report, allResults, performanceSummary);
|
|||
|
|
|
|||
|
|
return report;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 分析问题和建议
|
|||
|
|
* @param {Object} report - 报告对象
|
|||
|
|
* @param {Array} results - 测试结果
|
|||
|
|
* @param {Object} performanceSummary - 性能摘要
|
|||
|
|
*/
|
|||
|
|
_analyzeIssuesAndRecommendations(report, results, performanceSummary) {
|
|||
|
|
// 检查失败的测试
|
|||
|
|
const failedTests = results.filter(r => r.status === 'failed');
|
|||
|
|
if (failedTests.length > 0) {
|
|||
|
|
report.issues.push({
|
|||
|
|
type: 'test_failures',
|
|||
|
|
severity: 'high',
|
|||
|
|
message: `${failedTests.length} 个测试失败`,
|
|||
|
|
details: failedTests.map(r => ({
|
|||
|
|
test: `${r.testType}.${r.testName}`,
|
|||
|
|
error: r.error?.message || '未知错误',
|
|||
|
|
duration: r.duration
|
|||
|
|
}))
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查性能问题
|
|||
|
|
const slowTests = results.filter(r => r.duration > 5000);
|
|||
|
|
if (slowTests.length > 0) {
|
|||
|
|
report.issues.push({
|
|||
|
|
type: 'slow_tests',
|
|||
|
|
severity: 'medium',
|
|||
|
|
message: `${slowTests.length} 个测试执行时间过长`,
|
|||
|
|
details: slowTests.map(r => ({
|
|||
|
|
test: `${r.testType}.${r.testName}`,
|
|||
|
|
duration: r.duration,
|
|||
|
|
threshold: 5000
|
|||
|
|
}))
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查内存使用
|
|||
|
|
if (performanceSummary.memory.current &&
|
|||
|
|
performanceSummary.memory.current.used > TEST_CONFIG.performanceThresholds.memoryUsage) {
|
|||
|
|
report.issues.push({
|
|||
|
|
type: 'high_memory_usage',
|
|||
|
|
severity: 'medium',
|
|||
|
|
message: '内存使用量超过阈值',
|
|||
|
|
details: {
|
|||
|
|
current: performanceSummary.memory.current.used,
|
|||
|
|
threshold: TEST_CONFIG.performanceThresholds.memoryUsage,
|
|||
|
|
usage: (performanceSummary.memory.current.used / (1024 * 1024)).toFixed(2) + 'MB'
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成建议
|
|||
|
|
if (failedTests.length > 0) {
|
|||
|
|
report.recommendations.push({
|
|||
|
|
type: 'fix_failures',
|
|||
|
|
priority: 'high',
|
|||
|
|
message: '修复失败的测试用例',
|
|||
|
|
actions: [
|
|||
|
|
'检查错误日志以确定失败原因',
|
|||
|
|
'修复相应的处理器实现',
|
|||
|
|
'重新运行测试确保修复生效'
|
|||
|
|
]
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (performanceSummary.alerts.unacknowledged > 0) {
|
|||
|
|
report.recommendations.push({
|
|||
|
|
type: 'resolve_performance_alerts',
|
|||
|
|
priority: 'medium',
|
|||
|
|
message: '解决性能告警',
|
|||
|
|
actions: [
|
|||
|
|
'检查未确认的性能告警',
|
|||
|
|
'优化性能瓶颈代码',
|
|||
|
|
'调整性能阈值设置'
|
|||
|
|
]
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (slowTests.length > 0) {
|
|||
|
|
report.recommendations.push({
|
|||
|
|
type: 'optimize_slow_tests',
|
|||
|
|
priority: 'medium',
|
|||
|
|
message: '优化执行缓慢的测试',
|
|||
|
|
actions: [
|
|||
|
|
'分析长时间运行的测试用例',
|
|||
|
|
'优化事件处理逻辑',
|
|||
|
|
'考虑使用异步处理减少阻塞'
|
|||
|
|
]
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 显示测试结果
|
|||
|
|
* @param {Object} report - 测试报告
|
|||
|
|
*/
|
|||
|
|
_displayTestResults(report) {
|
|||
|
|
console.log('\n' + '='.repeat(80));
|
|||
|
|
console.log('🧪 集成测试报告');
|
|||
|
|
console.log('='.repeat(80));
|
|||
|
|
|
|||
|
|
// 总体摘要
|
|||
|
|
console.log('\n📊 总体摘要:');
|
|||
|
|
console.log(` 总测试数: ${report.summary.total}`);
|
|||
|
|
console.log(` 通过: ${report.summary.passed}`);
|
|||
|
|
console.log(` 失败: ${report.summary.failed}`);
|
|||
|
|
console.log(` 超时: ${report.summary.timeout}`);
|
|||
|
|
console.log(` 成功率: ${report.summary.successRate}%`);
|
|||
|
|
|
|||
|
|
// 测试套件结果
|
|||
|
|
console.log('\n📋 测试套件结果:');
|
|||
|
|
for (const [suiteKey, suite] of Object.entries(report.suites)) {
|
|||
|
|
console.log(`\n ${suite.name}:`);
|
|||
|
|
console.log(` 总数: ${suite.total} | 通过: ${suite.passed} | 失败: ${suite.failed} | 成功率: ${suite.successRate}%`);
|
|||
|
|
console.log(` 平均执行时间: ${suite.averageDuration.toFixed(2)}ms`);
|
|||
|
|
|
|||
|
|
// 显示失败的测试
|
|||
|
|
const failedTests = suite.results.filter(r => r.status === 'failed');
|
|||
|
|
if (failedTests.length > 0) {
|
|||
|
|
console.log(` ❌ 失败的测试:`);
|
|||
|
|
failedTests.forEach(test => {
|
|||
|
|
console.log(` - ${test.testName} (${test.error || '未知错误'})`);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 性能摘要
|
|||
|
|
console.log('\n⚡ 性能摘要:');
|
|||
|
|
if (report.performance.memory.current) {
|
|||
|
|
console.log(` 当前内存使用: ${(report.performance.memory.current.used / (1024 * 1024)).toFixed(2)}MB / ${(report.performance.memory.current.total / (1024 * 1024)).toFixed(2)}MB`);
|
|||
|
|
}
|
|||
|
|
console.log(` 性能告警: ${report.performance.alerts.unacknowledged} 个未确认`);
|
|||
|
|
|
|||
|
|
// 问题和建议
|
|||
|
|
if (report.issues.length > 0) {
|
|||
|
|
console.log('\n⚠️ 发现的问题:');
|
|||
|
|
report.issues.forEach(issue => {
|
|||
|
|
console.log(` [${issue.severity.toUpperCase()}] ${issue.message}`);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (report.recommendations.length > 0) {
|
|||
|
|
console.log('\n💡 建议:');
|
|||
|
|
report.recommendations.forEach((rec, index) => {
|
|||
|
|
console.log(` ${index + 1}. [${rec.priority.toUpperCase()}] ${rec.message}`);
|
|||
|
|
rec.actions.forEach(action => {
|
|||
|
|
console.log(` - ${action}`);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('\n' + '='.repeat(80));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取测试结果
|
|||
|
|
* @returns {Map} 测试结果映射
|
|||
|
|
*/
|
|||
|
|
getTestResults() {
|
|||
|
|
return new Map(this.testResults);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取性能摘要
|
|||
|
|
* @returns {Object} 性能摘要
|
|||
|
|
*/
|
|||
|
|
getPerformanceSummary() {
|
|||
|
|
return this.performanceMonitor.getPerformanceSummary();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清除测试结果
|
|||
|
|
*/
|
|||
|
|
clearResults() {
|
|||
|
|
this.testResults.clear();
|
|||
|
|
this.performanceMonitor.clearAllAlerts();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 销毁测试器
|
|||
|
|
*/
|
|||
|
|
destroy() {
|
|||
|
|
this.stop();
|
|||
|
|
this.clearResults();
|
|||
|
|
console.log('🗑️ 集成测试器已销毁');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建单例实例
|
|||
|
|
const integrationTester = new IntegrationTester();
|
|||
|
|
|
|||
|
|
// 便捷API
|
|||
|
|
export const testActions = {
|
|||
|
|
/**
|
|||
|
|
* 运行所有测试
|
|||
|
|
* @param {Array} suites - 测试套件列表
|
|||
|
|
* @returns {Promise} 测试报告
|
|||
|
|
*/
|
|||
|
|
runAll: (suites = null) => integrationTester.runAllTests(suites),
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取测试结果
|
|||
|
|
* @returns {Map} 测试结果
|
|||
|
|
*/
|
|||
|
|
getResults: () => integrationTester.getTestResults(),
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取性能摘要
|
|||
|
|
* @returns {Object} 性能摘要
|
|||
|
|
*/
|
|||
|
|
getPerformanceSummary: () => integrationTester.getPerformanceSummary(),
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清除测试结果
|
|||
|
|
*/
|
|||
|
|
clearResults: () => integrationTester.clearResults()
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 导出
|
|||
|
|
export default integrationTester;
|
|||
|
|
export { TEST_CONFIG, TestResult, PerformanceMonitor, testActions };
|