|  | function imageLoadedPromise(image) { | 
|  | return new Promise(function(resolve, reject) { | 
|  | if (image.complete) | 
|  | resolve(); | 
|  | image.addEventListener("load", resolve, { once: true }); | 
|  | }); | 
|  | } | 
|  |  | 
|  | function videoLoadedPromise(video) { | 
|  | return new Promise(function(resolve, reject) { | 
|  | if (video.readyState == 4) | 
|  | resolve(); | 
|  | else { | 
|  | video.addEventListener("loadeddata", resolve, { once: true }); | 
|  | video.addEventListener("error", reject, { once: true }); | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | function waitForNFrames(count) { | 
|  | if (count <= 0) | 
|  | return Promise.reject(new TypeError("count should be greater than 0!")); | 
|  |  | 
|  | return new Promise(resolve => { | 
|  | function tick() { | 
|  | (--count) ? requestAnimationFrame(tick) : resolve(); | 
|  | } | 
|  | requestAnimationFrame(tick); | 
|  | }); | 
|  | } | 
|  |  | 
|  | function seekTo(video, time) { | 
|  | return new Promise(function(resolve, reject) { | 
|  | video.addEventListener("seeked", async function() { | 
|  | /* Work around flakiness in video players... */ | 
|  | await waitForNFrames(3); | 
|  | resolve(); | 
|  | }, { once: true }); | 
|  | video.currentTime = time; | 
|  | }); | 
|  | } | 
|  |  | 
|  | function checkBoundingBox(actual, expected, fuzziness) { | 
|  | assert_equals(actual.constructor.name, "DOMRectReadOnly"); | 
|  | assert_approx_equals(actual.left, expected.left, fuzziness); | 
|  | assert_approx_equals(actual.right, expected.right, fuzziness); | 
|  | assert_approx_equals(actual.top, expected.top, fuzziness); | 
|  | assert_approx_equals(actual.bottom, expected.bottom, fuzziness); | 
|  | } | 
|  |  | 
|  | function checkPointsLieWithinBoundingBox(points, boundingBox) { | 
|  | for (point of points) { | 
|  | assert_between_inclusive(point.x, boundingBox.left, boundingBox.right); | 
|  | assert_between_inclusive(point.y, boundingBox.top, boundingBox.bottom); | 
|  | } | 
|  | } | 
|  |  | 
|  | function checkPointIsNear(actual, expected, fuzzinessX, fuzzinessY) { | 
|  | assert_approx_equals(actual.x, expected.x, fuzzinessX); | 
|  | assert_approx_equals(actual.y, expected.y, fuzzinessY); | 
|  | } | 
|  |  | 
|  | function checkPointsAreNear(actual, expected, fuzzinessX, fuzzinessY) { | 
|  | for (point of actual) | 
|  | checkPointIsNear(point, expected, fuzzinessX, fuzzinessY); | 
|  | } |