- 实现 enableGPU() 方法设置 will-change 属性 - 实现 disableGPU() 方法移除 will-change 属性 - 实现动画数量限制逻辑(最多 3 个同时运行) - 实现动画队列自动管理 - 添加 startAnimation() 和 endAnimation() 方法 - 添加 getActiveAnimationCount() 和 getQueuedAnimationCount() 查询方法 - 添加 clearAllAnimations() 清理方法 - 添加错误处理机制 - 创建交互式测试页面和自动化测试 - 创建详细的使用文档 验证需求: - 需求 5.2: 动画时使用 will-change 提示浏览器创建合成层 - 需求 5.3: 动画完成时移除 will-change 属性释放资源 - 需求 5.5: 限制同时运行的动画数量不超过 3 个
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);
|