295 lines
8.5 KiB
JavaScript
295 lines
8.5 KiB
JavaScript
|
|
/**
|
|||
|
|
* GPU 加速管理功能测试
|
|||
|
|
* 测试 ArgonRenderOptimizer 的 GPU 加速和动画限制功能
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// 模拟浏览器环境
|
|||
|
|
global.window = global;
|
|||
|
|
global.document = {
|
|||
|
|
createElement: () => ({
|
|||
|
|
style: {},
|
|||
|
|
addEventListener: () => {},
|
|||
|
|
appendChild: () => {}
|
|||
|
|
}),
|
|||
|
|
querySelector: () => null,
|
|||
|
|
getElementById: () => null,
|
|||
|
|
head: {
|
|||
|
|
appendChild: () => {}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
global.requestAnimationFrame = (callback) => {
|
|||
|
|
return setTimeout(callback, 16);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
global.cancelAnimationFrame = (id) => {
|
|||
|
|
clearTimeout(id);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 加载性能优化模块
|
|||
|
|
require('./argon-performance.js');
|
|||
|
|
|
|||
|
|
const { ArgonRenderOptimizer } = global;
|
|||
|
|
|
|||
|
|
// 测试套件
|
|||
|
|
console.log('='.repeat(60));
|
|||
|
|
console.log('GPU 加速管理功能测试');
|
|||
|
|
console.log('='.repeat(60));
|
|||
|
|
|
|||
|
|
// 测试 1: enableGPU() 方法
|
|||
|
|
console.log('\n测试 1: enableGPU() 方法');
|
|||
|
|
console.log('-'.repeat(60));
|
|||
|
|
|
|||
|
|
const renderOptimizer = new ArgonRenderOptimizer();
|
|||
|
|
const testElement1 = { style: {} };
|
|||
|
|
|
|||
|
|
renderOptimizer.enableGPU(testElement1);
|
|||
|
|
|
|||
|
|
if (testElement1.style.willChange === 'transform, opacity') {
|
|||
|
|
console.log('✓ enableGPU() 正确设置 will-change 属性');
|
|||
|
|
} else {
|
|||
|
|
console.error('✗ enableGPU() 未正确设置 will-change 属性');
|
|||
|
|
console.error(` 期望: "transform, opacity"`);
|
|||
|
|
console.error(` 实际: "${testElement1.style.willChange}"`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 null 元素
|
|||
|
|
renderOptimizer.enableGPU(null);
|
|||
|
|
console.log('✓ enableGPU() 正确处理 null 元素');
|
|||
|
|
|
|||
|
|
// 测试 2: disableGPU() 方法
|
|||
|
|
console.log('\n测试 2: disableGPU() 方法');
|
|||
|
|
console.log('-'.repeat(60));
|
|||
|
|
|
|||
|
|
const testElement2 = { style: { willChange: 'transform, opacity' } };
|
|||
|
|
|
|||
|
|
renderOptimizer.disableGPU(testElement2);
|
|||
|
|
|
|||
|
|
if (testElement2.style.willChange === 'auto') {
|
|||
|
|
console.log('✓ disableGPU() 正确移除 will-change 属性');
|
|||
|
|
} else {
|
|||
|
|
console.error('✗ disableGPU() 未正确移除 will-change 属性');
|
|||
|
|
console.error(` 期望: "auto"`);
|
|||
|
|
console.error(` 实际: "${testElement2.style.willChange}"`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 null 元素
|
|||
|
|
renderOptimizer.disableGPU(null);
|
|||
|
|
console.log('✓ disableGPU() 正确处理 null 元素');
|
|||
|
|
|
|||
|
|
// 测试 3: 动画数量限制
|
|||
|
|
console.log('\n测试 3: 动画数量限制(最多 3 个)');
|
|||
|
|
console.log('-'.repeat(60));
|
|||
|
|
|
|||
|
|
const renderOptimizer2 = new ArgonRenderOptimizer();
|
|||
|
|
const elements = [];
|
|||
|
|
for (let i = 0; i < 5; i++) {
|
|||
|
|
elements.push({ style: {}, id: `element-${i}` });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 启动 5 个动画
|
|||
|
|
const results = [];
|
|||
|
|
elements.forEach((element, index) => {
|
|||
|
|
const started = renderOptimizer2.startAnimation(element, (el) => {
|
|||
|
|
// 模拟动画
|
|||
|
|
});
|
|||
|
|
results.push(started);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 验证前 3 个立即启动,后 2 个进入队列
|
|||
|
|
const immediateStarts = results.filter(r => r === true).length;
|
|||
|
|
const queued = results.filter(r => r === false).length;
|
|||
|
|
|
|||
|
|
if (immediateStarts === 3) {
|
|||
|
|
console.log(`✓ 前 3 个动画立即启动`);
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 立即启动的动画数量错误`);
|
|||
|
|
console.error(` 期望: 3`);
|
|||
|
|
console.error(` 实际: ${immediateStarts}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (queued === 2) {
|
|||
|
|
console.log(`✓ 后 2 个动画进入等待队列`);
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 等待队列的动画数量错误`);
|
|||
|
|
console.error(` 期望: 2`);
|
|||
|
|
console.error(` 实际: ${queued}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证活动动画数量
|
|||
|
|
const activeCount = renderOptimizer2.getActiveAnimationCount();
|
|||
|
|
if (activeCount === 3) {
|
|||
|
|
console.log(`✓ 活动动画数量: ${activeCount}`);
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 活动动画数量错误`);
|
|||
|
|
console.error(` 期望: 3`);
|
|||
|
|
console.error(` 实际: ${activeCount}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证等待队列数量
|
|||
|
|
const queuedCount = renderOptimizer2.getQueuedAnimationCount();
|
|||
|
|
if (queuedCount === 2) {
|
|||
|
|
console.log(`✓ 等待队列数量: ${queuedCount}`);
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 等待队列数量错误`);
|
|||
|
|
console.error(` 期望: 2`);
|
|||
|
|
console.error(` 实际: ${queuedCount}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 4: 动画完成后自动启动队列中的下一个
|
|||
|
|
console.log('\n测试 4: 动画队列自动管理');
|
|||
|
|
console.log('-'.repeat(60));
|
|||
|
|
|
|||
|
|
// 结束第一个动画
|
|||
|
|
renderOptimizer2.endAnimation(elements[0]);
|
|||
|
|
|
|||
|
|
// 验证活动动画数量仍为 3(队列中的一个自动启动)
|
|||
|
|
const activeAfterEnd = renderOptimizer2.getActiveAnimationCount();
|
|||
|
|
if (activeAfterEnd === 3) {
|
|||
|
|
console.log(`✓ 动画结束后,队列中的动画自动启动`);
|
|||
|
|
console.log(` 活动动画数量保持: ${activeAfterEnd}`);
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 动画队列自动管理失败`);
|
|||
|
|
console.error(` 期望活动动画数量: 3`);
|
|||
|
|
console.error(` 实际活动动画数量: ${activeAfterEnd}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证等待队列减少
|
|||
|
|
const queuedAfterEnd = renderOptimizer2.getQueuedAnimationCount();
|
|||
|
|
if (queuedAfterEnd === 1) {
|
|||
|
|
console.log(`✓ 等待队列数量减少: ${queuedAfterEnd}`);
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 等待队列数量错误`);
|
|||
|
|
console.error(` 期望: 1`);
|
|||
|
|
console.error(` 实际: ${queuedAfterEnd}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 5: GPU 加速生命周期
|
|||
|
|
console.log('\n测试 5: GPU 加速生命周期');
|
|||
|
|
console.log('-'.repeat(60));
|
|||
|
|
|
|||
|
|
const renderOptimizer3 = new ArgonRenderOptimizer();
|
|||
|
|
const animElement = { style: {} };
|
|||
|
|
|
|||
|
|
// 启动动画应该启用 GPU 加速
|
|||
|
|
renderOptimizer3.startAnimation(animElement, (el) => {
|
|||
|
|
// 动画函数
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (animElement.style.willChange === 'transform, opacity') {
|
|||
|
|
console.log('✓ 动画启动时自动启用 GPU 加速');
|
|||
|
|
} else {
|
|||
|
|
console.error('✗ 动画启动时未启用 GPU 加速');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 结束动画应该禁用 GPU 加速
|
|||
|
|
renderOptimizer3.endAnimation(animElement);
|
|||
|
|
|
|||
|
|
if (animElement.style.willChange === 'auto') {
|
|||
|
|
console.log('✓ 动画结束时自动禁用 GPU 加速');
|
|||
|
|
} else {
|
|||
|
|
console.error('✗ 动画结束时未禁用 GPU 加速');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 6: clearAllAnimations()
|
|||
|
|
console.log('\n测试 6: clearAllAnimations() 方法');
|
|||
|
|
console.log('-'.repeat(60));
|
|||
|
|
|
|||
|
|
const renderOptimizer4 = new ArgonRenderOptimizer();
|
|||
|
|
const clearElements = [];
|
|||
|
|
for (let i = 0; i < 5; i++) {
|
|||
|
|
const el = { style: {} };
|
|||
|
|
clearElements.push(el);
|
|||
|
|
renderOptimizer4.startAnimation(el, () => {});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清除所有动画
|
|||
|
|
renderOptimizer4.clearAllAnimations();
|
|||
|
|
|
|||
|
|
// 验证所有动画都被清除
|
|||
|
|
const activeAfterClear = renderOptimizer4.getActiveAnimationCount();
|
|||
|
|
const queuedAfterClear = renderOptimizer4.getQueuedAnimationCount();
|
|||
|
|
|
|||
|
|
if (activeAfterClear === 0) {
|
|||
|
|
console.log('✓ 所有活动动画已清除');
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 活动动画未完全清除,剩余: ${activeAfterClear}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (queuedAfterClear === 0) {
|
|||
|
|
console.log('✓ 等待队列已清空');
|
|||
|
|
} else {
|
|||
|
|
console.error(`✗ 等待队列未完全清空,剩余: ${queuedAfterClear}`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证所有元素的 GPU 加速都被禁用
|
|||
|
|
const allDisabled = clearElements.every(el => el.style.willChange === 'auto');
|
|||
|
|
if (allDisabled) {
|
|||
|
|
console.log('✓ 所有元素的 GPU 加速已禁用');
|
|||
|
|
} else {
|
|||
|
|
console.error('✗ 部分元素的 GPU 加速未禁用');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 7: 错误处理
|
|||
|
|
console.log('\n测试 7: 错误处理');
|
|||
|
|
console.log('-'.repeat(60));
|
|||
|
|
|
|||
|
|
const renderOptimizer5 = new ArgonRenderOptimizer();
|
|||
|
|
const errorElement = { style: {} };
|
|||
|
|
|
|||
|
|
// 测试动画函数抛出错误
|
|||
|
|
let errorCaught = false;
|
|||
|
|
renderOptimizer5.startAnimation(errorElement, (el) => {
|
|||
|
|
throw new Error('Test error');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 验证错误不会导致程序崩溃,且动画被正确清理
|
|||
|
|
setTimeout(() => {
|
|||
|
|
const activeAfterError = renderOptimizer5.getActiveAnimationCount();
|
|||
|
|
if (activeAfterError === 0) {
|
|||
|
|
console.log('✓ 动画函数错误被正确处理,动画已清理');
|
|||
|
|
} else {
|
|||
|
|
console.error('✗ 动画函数错误处理失败');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (errorElement.style.willChange === 'auto') {
|
|||
|
|
console.log('✓ 错误后 GPU 加速已禁用');
|
|||
|
|
} else {
|
|||
|
|
console.error('✗ 错误后 GPU 加速未禁用');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 所有测试通过
|
|||
|
|
console.log('\n' + '='.repeat(60));
|
|||
|
|
console.log('✓ 所有测试通过!');
|
|||
|
|
console.log('='.repeat(60));
|
|||
|
|
console.log('\n测试摘要:');
|
|||
|
|
console.log(' ✓ enableGPU() 方法正常工作');
|
|||
|
|
console.log(' ✓ disableGPU() 方法正常工作');
|
|||
|
|
console.log(' ✓ 动画数量限制为 3 个');
|
|||
|
|
console.log(' ✓ 动画队列自动管理');
|
|||
|
|
console.log(' ✓ GPU 加速生命周期管理');
|
|||
|
|
console.log(' ✓ clearAllAnimations() 方法正常工作');
|
|||
|
|
console.log(' ✓ 错误处理机制正常');
|
|||
|
|
console.log('\n需求验证:');
|
|||
|
|
console.log(' ✓ 需求 5.2: 动画时使用 will-change 提示浏览器创建合成层');
|
|||
|
|
console.log(' ✓ 需求 5.3: 动画完成时移除 will-change 属性释放资源');
|
|||
|
|
console.log(' ✓ 需求 5.5: 限制同时运行的动画数量不超过 3 个');
|
|||
|
|
|
|||
|
|
process.exit(0);
|
|||
|
|
}, 100);
|