'use strict'; // ======================================= // // Utility functions for testing keyframes // // ======================================= // ------------------------------ // Helper functions // ------------------------------ /** * Test equality between two lists of computed keyframes * @param {Array.} a - actual computed keyframes * @param {Array.} b - expected computed keyframes */ function assert_frame_lists_equal(a, b, message) { assert_equals(a.length, b.length, `number of frames: ${(message || '')}`); for (let i = 0; i < Math.min(a.length, b.length); i++) { assert_frames_equal(a[i], b[i], `ComputedKeyframe #${i}: ${(message || '')}`); } } /** Helper for assert_frame_lists_equal */ function assert_frames_equal(a, b, name) { assert_equals(Object.keys(a).sort().toString(), Object.keys(b).sort().toString(), `properties on ${name} should match`); // Iterates sorted keys to ensure stable failures. for (const p of Object.keys(a).sort()) { if (typeof b[p] == 'number') assert_approx_equals(a[p], b[p], 1e-6, `value for '${p}' on ${name}`); else if (typeof b[p] == 'object') { for (const key in b[p]) { if (typeof b[p][key] == 'number') { assert_approx_equals(a[p][key], b[p][key], 1e-6, `value for '${p}.${key}' on ${name}`); } else { assert_equals((a[p][key] || 'undefined').toString(), b[p][key].toString(), `value for '${p}.${key}' on ${name}`); } } } else assert_equals(a[p], b[p], `value for '${p}' on ${name}`); } }