1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/image/test/mochitest/animationPolling.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,413 @@ 1.4 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +var currentTest; 1.6 +var gIsRefImageLoaded = false; 1.7 +const gShouldOutputDebugInfo = false; 1.8 + 1.9 +function pollForSuccess() 1.10 +{ 1.11 + if (!currentTest.isTestFinished) { 1.12 + if (!currentTest.reusingReferenceImage || (currentTest.reusingReferenceImage 1.13 + && gRefImageLoaded)) { 1.14 + currentTest.checkImage(); 1.15 + } 1.16 + 1.17 + setTimeout(pollForSuccess, currentTest.pollFreq); 1.18 + } 1.19 +}; 1.20 + 1.21 +function referencePoller() 1.22 +{ 1.23 + currentTest.takeReferenceSnapshot(); 1.24 +} 1.25 + 1.26 +function reuseImageCallback() 1.27 +{ 1.28 + gIsRefImageLoaded = true; 1.29 +} 1.30 + 1.31 +function failTest() 1.32 +{ 1.33 + if (currentTest.isTestFinished || currentTest.closeFunc) { 1.34 + return; 1.35 + } 1.36 + 1.37 + ok(false, "timing out after " + currentTest.timeout + "ms. " 1.38 + + "Animated image still doesn't look correct, after poll #" 1.39 + + currentTest.pollCounter); 1.40 + currentTest.wereFailures = true; 1.41 + 1.42 + if (currentTest.currentSnapshotDataURI) { 1.43 + currentTest.outputDebugInfo("Snapshot #" + currentTest.pollCounter, 1.44 + "snapNum" + currentTest.pollCounter, 1.45 + currentTest.currentSnapshotDataURI); 1.46 + } 1.47 + 1.48 + currentTest.enableDisplay(document.getElementById(currentTest.debugElementId)); 1.49 + 1.50 + currentTest.cleanUpAndFinish(); 1.51 +}; 1.52 + 1.53 +/** 1.54 + * Create a new AnimationTest object. 1.55 + * 1.56 + * @param pollFreq The amount of time (in ms) to wait between consecutive 1.57 + * snapshots if the reference image and the test image don't match. 1.58 + * @param timeout The total amount of time (in ms) to wait before declaring the 1.59 + * test as failed. 1.60 + * @param referenceElementId The id attribute of the reference image element, or 1.61 + * the source of the image to change to, once the reference snapshot has 1.62 + * been successfully taken. This latter option could be used if you don't 1.63 + * want the image to become invisible at any time during the test. 1.64 + * @param imageElementId The id attribute of the test image element. 1.65 + * @param debugElementId The id attribute of the div where links should be 1.66 + * appended if the test fails. 1.67 + * @param cleanId The id attribute of the div or element to use as the 'clean' 1.68 + * test. This element is only enabled when we are testing to verify that 1.69 + * the reference image has been loaded. It can be undefined. 1.70 + * @param srcAttr The location of the source of the image, for preloading. This 1.71 + * is usually not required, but it useful for preloading reference 1.72 + * images. 1.73 + * @param xulTest A boolean value indicating whether or not this is a XUL test 1.74 + * (uses hidden=true/false rather than display: none to hide/show 1.75 + * elements). 1.76 + * @param closeFunc A function that should be called when this test is finished. 1.77 + * If null, then cleanUpAndFinish() will be called. This can be used to 1.78 + * chain tests together, so they are all finished exactly once. 1.79 + * @returns {AnimationTest} 1.80 + */ 1.81 +function AnimationTest(pollFreq, timeout, referenceElementId, imageElementId, 1.82 + debugElementId, cleanId, srcAttr, xulTest, closeFunc) 1.83 +{ 1.84 + // We want to test the cold loading behavior, so clear cache in case an 1.85 + // earlier test got our image in there already. 1.86 + clearImageCache(); 1.87 + 1.88 + this.wereFailures = false; 1.89 + this.pollFreq = pollFreq; 1.90 + this.timeout = timeout; 1.91 + this.imageElementId = imageElementId; 1.92 + this.referenceElementId = referenceElementId; 1.93 + 1.94 + if (!document.getElementById(referenceElementId)) { 1.95 + // In this case, we're assuming the user passed in a string that 1.96 + // indicates the source of the image they want to change to, 1.97 + // after the reference image has been taken. 1.98 + this.reusingImageAsReference = true; 1.99 + } 1.100 + 1.101 + this.srcAttr = srcAttr; 1.102 + this.debugElementId = debugElementId; 1.103 + this.referenceSnapshot = ""; // value will be set in takeReferenceSnapshot() 1.104 + this.pollCounter = 0; 1.105 + this.isTestFinished = false; 1.106 + this.numRefsTaken = 0; 1.107 + this.blankWaitTime = 0; 1.108 + 1.109 + this.cleanId = cleanId ? cleanId : ''; 1.110 + this.xulTest = xulTest ? xulTest : ''; 1.111 + this.closeFunc = closeFunc ? closeFunc : ''; 1.112 +}; 1.113 + 1.114 +AnimationTest.prototype.preloadImage = function() 1.115 +{ 1.116 + if (this.srcAttr) { 1.117 + this.myImage = new Image(); 1.118 + this.myImage.onload = function() { currentTest.continueTest(); }; 1.119 + this.myImage.src = this.srcAttr; 1.120 + } else { 1.121 + this.continueTest(); 1.122 + } 1.123 +}; 1.124 + 1.125 +AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri) 1.126 +{ 1.127 + if (!gShouldOutputDebugInfo) { 1.128 + return; 1.129 + } 1.130 + var debugElement = document.getElementById(this.debugElementId); 1.131 + var newDataUriElement = document.createElement("a"); 1.132 + newDataUriElement.setAttribute("id", id); 1.133 + newDataUriElement.setAttribute("href", dataUri); 1.134 + newDataUriElement.appendChild(document.createTextNode(message)); 1.135 + debugElement.appendChild(newDataUriElement); 1.136 + var brElement = document.createElement("br"); 1.137 + debugElement.appendChild(brElement); 1.138 + todo(false, "Debug (" + id + "): " + message + " " + dataUri); 1.139 +}; 1.140 + 1.141 +AnimationTest.prototype.isFinished = function() 1.142 +{ 1.143 + return this.isTestFinished; 1.144 +}; 1.145 + 1.146 +AnimationTest.prototype.takeCleanSnapshot = function() 1.147 +{ 1.148 + var cleanElement; 1.149 + if (this.cleanId) { 1.150 + cleanElement = document.getElementById(this.cleanId); 1.151 + } 1.152 + 1.153 + // Enable clean page comparison element 1.154 + if (cleanElement) { 1.155 + this.enableDisplay(cleanElement); 1.156 + } 1.157 + 1.158 + // Take a snapshot of the initial (clean) page 1.159 + this.cleanSnapshot = snapshotWindow(window, false); 1.160 + 1.161 + // Disable the clean page comparison element 1.162 + if (cleanElement) { 1.163 + this.disableDisplay(cleanElement); 1.164 + } 1.165 + 1.166 + var dataString1 = "Clean Snapshot"; 1.167 + this.outputDebugInfo(dataString1, 'cleanSnap', 1.168 + this.cleanSnapshot.toDataURL()); 1.169 +}; 1.170 + 1.171 +AnimationTest.prototype.takeBlankSnapshot = function() 1.172 +{ 1.173 + // Take a snapshot of the initial (essentially blank) page 1.174 + this.blankSnapshot = snapshotWindow(window, false); 1.175 + 1.176 + var dataString1 = "Initial Blank Snapshot"; 1.177 + this.outputDebugInfo(dataString1, 'blank1Snap', 1.178 + this.blankSnapshot.toDataURL()); 1.179 +}; 1.180 + 1.181 +/** 1.182 + * Begin the AnimationTest. This will utilize the information provided in the 1.183 + * constructor to invoke a mochitest on animated images. It will automatically 1.184 + * fail if allowed to run past the timeout. This will attempt to preload an 1.185 + * image, if applicable, and then asynchronously call continueTest(), or if not 1.186 + * applicable, synchronously trigger a call to continueTest(). 1.187 + */ 1.188 +AnimationTest.prototype.beginTest = function() 1.189 +{ 1.190 + SimpleTest.waitForExplicitFinish(); 1.191 + 1.192 + currentTest = this; 1.193 + this.preloadImage(); 1.194 +}; 1.195 + 1.196 +/** 1.197 + * This is the second part of the test. It is triggered (eventually) from 1.198 + * beginTest() either synchronously or asynchronously, as an image load 1.199 + * callback. 1.200 + */ 1.201 +AnimationTest.prototype.continueTest = function() 1.202 +{ 1.203 + // In case something goes wrong, fail earlier than mochitest timeout, 1.204 + // and with more information. 1.205 + setTimeout(failTest, this.timeout); 1.206 + 1.207 + if (!this.reusingImageAsReference) { 1.208 + this.disableDisplay(document.getElementById(this.imageElementId)); 1.209 + } 1.210 + 1.211 + this.takeReferenceSnapshot(); 1.212 + this.setupPolledImage(); 1.213 + SimpleTest.executeSoon(pollForSuccess); 1.214 +}; 1.215 + 1.216 +AnimationTest.prototype.setupPolledImage = function () 1.217 +{ 1.218 + // Make sure the image is visible 1.219 + if (!this.reusingImageAsReference) { 1.220 + this.enableDisplay(document.getElementById(this.imageElementId)); 1.221 + var currentSnapshot = snapshotWindow(window, false); 1.222 + var result = compareSnapshots(currentSnapshot, 1.223 + this.referenceSnapshot, true); 1.224 + 1.225 + this.currentSnapshotDataURI = currentSnapshot.toDataURL(); 1.226 + 1.227 + if (result[0]) { 1.228 + // SUCCESS! 1.229 + ok(true, "Animated image looks correct, at poll #" 1.230 + + this.pollCounter); 1.231 + 1.232 + this.cleanUpAndFinish(); 1.233 + } 1.234 + } else { 1.235 + if (!gIsRefImageLoaded) { 1.236 + this.myImage = new Image(); 1.237 + this.myImage.onload = reuseImageCallback; 1.238 + document.getElementById(this.imageElementId).setAttribute('src', 1.239 + this.referenceElementId); 1.240 + } 1.241 + } 1.242 +} 1.243 + 1.244 +AnimationTest.prototype.checkImage = function () 1.245 +{ 1.246 + if (this.isTestFinished) { 1.247 + return; 1.248 + } 1.249 + 1.250 + this.pollCounter++; 1.251 + 1.252 + // We need this for some tests, because we need to force the 1.253 + // test image to be visible. 1.254 + if (!this.reusingImageAsReference) { 1.255 + this.enableDisplay(document.getElementById(this.imageElementId)); 1.256 + } 1.257 + 1.258 + var currentSnapshot = snapshotWindow(window, false); 1.259 + var result = compareSnapshots(currentSnapshot, this.referenceSnapshot, true); 1.260 + 1.261 + this.currentSnapshotDataURI = currentSnapshot.toDataURL(); 1.262 + 1.263 + if (result[0]) { 1.264 + // SUCCESS! 1.265 + ok(true, "Animated image looks correct, at poll #" 1.266 + + this.pollCounter); 1.267 + 1.268 + this.cleanUpAndFinish(); 1.269 + } 1.270 +}; 1.271 + 1.272 +AnimationTest.prototype.takeReferenceSnapshot = function () 1.273 +{ 1.274 + this.numRefsTaken++; 1.275 + 1.276 + // Test to make sure the reference image doesn't match a clean snapshot 1.277 + if (!this.cleanSnapshot) { 1.278 + this.takeCleanSnapshot(); 1.279 + } 1.280 + 1.281 + // Used later to verify that the reference div disappeared 1.282 + if (!this.blankSnapshot) { 1.283 + this.takeBlankSnapshot(); 1.284 + } 1.285 + 1.286 + if (this.reusingImageAsReference) { 1.287 + // Show reference elem (which is actually our image), & take a snapshot 1.288 + var referenceElem = document.getElementById(this.imageElementId); 1.289 + this.enableDisplay(referenceElem); 1.290 + 1.291 + this.referenceSnapshot = snapshotWindow(window, false); 1.292 + 1.293 + var snapResult = compareSnapshots(this.cleanSnapshot, 1.294 + this.referenceSnapshot, false); 1.295 + if (!snapResult[0]) { 1.296 + if (this.blankWaitTime > 2000) { 1.297 + // if it took longer than two seconds to load the image, we probably 1.298 + // have a problem. 1.299 + this.wereFailures = true; 1.300 + ok(snapResult[0], 1.301 + "Reference snapshot shouldn't match clean (non-image) snapshot"); 1.302 + } else { 1.303 + this.blankWaitTime += currentTest.pollFreq; 1.304 + // let's wait a bit and see if it clears up 1.305 + setTimeout(referencePoller, currentTest.pollFreq); 1.306 + return; 1.307 + } 1.308 + } 1.309 + 1.310 + ok(snapResult[0], 1.311 + "Reference snapshot shouldn't match clean (non-image) snapshot"); 1.312 + 1.313 + var dataString = "Reference Snapshot #" + this.numRefsTaken; 1.314 + this.outputDebugInfo(dataString, 'refSnapId', 1.315 + this.referenceSnapshot.toDataURL()); 1.316 + } else { 1.317 + // Make sure the animation section is hidden 1.318 + this.disableDisplay(document.getElementById(this.imageElementId)); 1.319 + 1.320 + // Show reference div, & take a snapshot 1.321 + var referenceDiv = document.getElementById(this.referenceElementId); 1.322 + this.enableDisplay(referenceDiv); 1.323 + 1.324 + this.referenceSnapshot = snapshotWindow(window, false); 1.325 + var snapResult = compareSnapshots(this.cleanSnapshot, 1.326 + this.referenceSnapshot, false); 1.327 + if (!snapResult[0]) { 1.328 + if (this.blankWaitTime > 2000) { 1.329 + // if it took longer than two seconds to load the image, we probably 1.330 + // have a problem. 1.331 + this.wereFailures = true; 1.332 + ok(snapResult[0], 1.333 + "Reference snapshot shouldn't match clean (non-image) snapshot"); 1.334 + } else { 1.335 + this.blankWaitTime += 20; 1.336 + // let's wait a bit and see if it clears up 1.337 + setTimeout(referencePoller, 20); 1.338 + return; 1.339 + } 1.340 + } 1.341 + 1.342 + ok(snapResult[0], 1.343 + "Reference snapshot shouldn't match clean (non-image) snapshot"); 1.344 + 1.345 + var dataString = "Reference Snapshot #" + this.numRefsTaken; 1.346 + this.outputDebugInfo(dataString, 'refSnapId', 1.347 + this.referenceSnapshot.toDataURL()); 1.348 + 1.349 + // Re-hide reference div, and take another snapshot to be sure it's gone 1.350 + this.disableDisplay(referenceDiv); 1.351 + this.testBlankCameBack(); 1.352 + } 1.353 +}; 1.354 + 1.355 +AnimationTest.prototype.enableDisplay = function(element) 1.356 +{ 1.357 + if (!element) { 1.358 + return; 1.359 + } 1.360 + 1.361 + if (!this.xulTest) { 1.362 + element.style.display = ''; 1.363 + } else { 1.364 + element.setAttribute('hidden', 'false'); 1.365 + } 1.366 +}; 1.367 + 1.368 +AnimationTest.prototype.disableDisplay = function(element) 1.369 +{ 1.370 + if (!element) { 1.371 + return; 1.372 + } 1.373 + 1.374 + if (!this.xulTest) { 1.375 + element.style.display = 'none'; 1.376 + } else { 1.377 + element.setAttribute('hidden', 'true'); 1.378 + } 1.379 +}; 1.380 + 1.381 +AnimationTest.prototype.testBlankCameBack = function() 1.382 +{ 1.383 + var blankSnapshot2 = snapshotWindow(window, false); 1.384 + var result = compareSnapshots(this.blankSnapshot, blankSnapshot2, true); 1.385 + ok(result[0], "Reference image should disappear when it becomes display:none"); 1.386 + 1.387 + if (!result[0]) { 1.388 + this.wereFailures = true; 1.389 + var dataString = "Second Blank Snapshot"; 1.390 + this.outputDebugInfo(dataString, 'blank2SnapId', result[2]); 1.391 + } 1.392 +}; 1.393 + 1.394 +AnimationTest.prototype.cleanUpAndFinish = function () 1.395 +{ 1.396 + // On the off chance that failTest and checkImage are triggered 1.397 + // back-to-back, use a flag to prevent multiple calls to SimpleTest.finish. 1.398 + if (this.isTestFinished) { 1.399 + return; 1.400 + } 1.401 + 1.402 + this.isTestFinished = true; 1.403 + 1.404 + // Call our closing function, if one exists 1.405 + if (this.closeFunc) { 1.406 + this.closeFunc(); 1.407 + return; 1.408 + } 1.409 + 1.410 + if (this.wereFailures) { 1.411 + document.getElementById(this.debugElementId).style.display = 'block'; 1.412 + } 1.413 + 1.414 + SimpleTest.finish(); 1.415 + document.getElementById(this.debugElementId).style.display = ""; 1.416 +};