image/test/mochitest/animationPolling.js

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 var currentTest;
     3 var gIsRefImageLoaded = false;
     4 const gShouldOutputDebugInfo = false;
     6 function pollForSuccess()
     7 {
     8   if (!currentTest.isTestFinished) {
     9     if (!currentTest.reusingReferenceImage || (currentTest.reusingReferenceImage
    10         && gRefImageLoaded)) {
    11       currentTest.checkImage();
    12     }
    14     setTimeout(pollForSuccess, currentTest.pollFreq);
    15   }
    16 };
    18 function referencePoller()
    19 {
    20   currentTest.takeReferenceSnapshot();
    21 }
    23 function reuseImageCallback()
    24 {
    25   gIsRefImageLoaded = true;
    26 }
    28 function failTest()
    29 {
    30   if (currentTest.isTestFinished || currentTest.closeFunc) {
    31     return;
    32   }
    34   ok(false, "timing out after " + currentTest.timeout + "ms.  "
    35      + "Animated image still doesn't look correct, after poll #"
    36      + currentTest.pollCounter);
    37   currentTest.wereFailures = true;
    39   if (currentTest.currentSnapshotDataURI) {
    40     currentTest.outputDebugInfo("Snapshot #" + currentTest.pollCounter,
    41                                 "snapNum" + currentTest.pollCounter,
    42                                 currentTest.currentSnapshotDataURI);
    43   }
    45   currentTest.enableDisplay(document.getElementById(currentTest.debugElementId));
    47   currentTest.cleanUpAndFinish();
    48 };
    50 /**
    51  * Create a new AnimationTest object.
    52  *
    53  * @param pollFreq The amount of time (in ms) to wait between consecutive
    54  *        snapshots if the reference image and the test image don't match.
    55  * @param timeout The total amount of time (in ms) to wait before declaring the
    56  *        test as failed.
    57  * @param referenceElementId The id attribute of the reference image element, or
    58  *        the source of the image to change to, once the reference snapshot has
    59  *        been successfully taken. This latter option could be used if you don't
    60  *        want the image to become invisible at any time during the test.
    61  * @param imageElementId The id attribute of the test image element.
    62  * @param debugElementId The id attribute of the div where links should be
    63  *        appended if the test fails.
    64  * @param cleanId The id attribute of the div or element to use as the 'clean'
    65  *        test. This element is only enabled when we are testing to verify that
    66  *        the reference image has been loaded. It can be undefined.
    67  * @param srcAttr The location of the source of the image, for preloading. This
    68  *        is usually not required, but it useful for preloading reference
    69  *        images.
    70  * @param xulTest A boolean value indicating whether or not this is a XUL test
    71  *        (uses hidden=true/false rather than display: none to hide/show
    72  *        elements).
    73  * @param closeFunc A function that should be called when this test is finished.
    74  *        If null, then cleanUpAndFinish() will be called. This can be used to
    75  *        chain tests together, so they are all finished exactly once.
    76  * @returns {AnimationTest}
    77  */
    78 function AnimationTest(pollFreq, timeout, referenceElementId, imageElementId,
    79                        debugElementId, cleanId, srcAttr, xulTest, closeFunc)
    80 {
    81   // We want to test the cold loading behavior, so clear cache in case an
    82   // earlier test got our image in there already.
    83   clearImageCache();
    85   this.wereFailures = false;
    86   this.pollFreq = pollFreq;
    87   this.timeout = timeout;
    88   this.imageElementId = imageElementId;
    89   this.referenceElementId = referenceElementId;
    91   if (!document.getElementById(referenceElementId)) {
    92     // In this case, we're assuming the user passed in a string that
    93     // indicates the source of the image they want to change to,
    94     // after the reference image has been taken.
    95     this.reusingImageAsReference = true;
    96   }
    98   this.srcAttr = srcAttr;
    99   this.debugElementId = debugElementId;
   100   this.referenceSnapshot = ""; // value will be set in takeReferenceSnapshot()
   101   this.pollCounter = 0;
   102   this.isTestFinished = false;
   103   this.numRefsTaken = 0;
   104   this.blankWaitTime = 0;
   106   this.cleanId = cleanId ? cleanId : '';
   107   this.xulTest = xulTest ? xulTest : '';
   108   this.closeFunc = closeFunc ? closeFunc : '';
   109 };
   111 AnimationTest.prototype.preloadImage = function()
   112 {
   113   if (this.srcAttr) {
   114     this.myImage = new Image();
   115     this.myImage.onload = function() { currentTest.continueTest(); };
   116     this.myImage.src = this.srcAttr;
   117   } else {
   118     this.continueTest();
   119   }
   120 };
   122 AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri)
   123 {
   124   if (!gShouldOutputDebugInfo) {
   125     return;
   126   }
   127   var debugElement = document.getElementById(this.debugElementId);
   128   var newDataUriElement = document.createElement("a");
   129   newDataUriElement.setAttribute("id", id);
   130   newDataUriElement.setAttribute("href", dataUri);
   131   newDataUriElement.appendChild(document.createTextNode(message));
   132   debugElement.appendChild(newDataUriElement);
   133   var brElement = document.createElement("br");
   134   debugElement.appendChild(brElement);
   135   todo(false, "Debug (" + id + "): " + message + " " + dataUri);
   136 };
   138 AnimationTest.prototype.isFinished = function()
   139 {
   140   return this.isTestFinished;
   141 };
   143 AnimationTest.prototype.takeCleanSnapshot = function()
   144 {
   145   var cleanElement;
   146   if (this.cleanId) {
   147     cleanElement = document.getElementById(this.cleanId);
   148   }
   150   // Enable clean page comparison element
   151   if (cleanElement) {
   152     this.enableDisplay(cleanElement);
   153   }
   155   // Take a snapshot of the initial (clean) page
   156   this.cleanSnapshot = snapshotWindow(window, false);
   158   // Disable the clean page comparison element
   159   if (cleanElement) {
   160     this.disableDisplay(cleanElement);
   161   }
   163   var dataString1 = "Clean Snapshot";
   164   this.outputDebugInfo(dataString1, 'cleanSnap',
   165                        this.cleanSnapshot.toDataURL());
   166 };
   168 AnimationTest.prototype.takeBlankSnapshot = function()
   169 {
   170   // Take a snapshot of the initial (essentially blank) page
   171   this.blankSnapshot = snapshotWindow(window, false);
   173   var dataString1 = "Initial Blank Snapshot";
   174   this.outputDebugInfo(dataString1, 'blank1Snap',
   175                        this.blankSnapshot.toDataURL());
   176 };
   178 /**
   179  * Begin the AnimationTest. This will utilize the information provided in the
   180  * constructor to invoke a mochitest on animated images. It will automatically
   181  * fail if allowed to run past the timeout. This will attempt to preload an
   182  * image, if applicable, and then asynchronously call continueTest(), or if not
   183  * applicable, synchronously trigger a call to continueTest().
   184  */
   185 AnimationTest.prototype.beginTest = function()
   186 {
   187   SimpleTest.waitForExplicitFinish();
   189   currentTest = this;
   190   this.preloadImage();
   191 };
   193 /**
   194  * This is the second part of the test. It is triggered (eventually) from
   195  * beginTest() either synchronously or asynchronously, as an image load
   196  * callback.
   197  */
   198 AnimationTest.prototype.continueTest = function()
   199 {
   200   // In case something goes wrong, fail earlier than mochitest timeout,
   201   // and with more information.
   202   setTimeout(failTest, this.timeout);
   204   if (!this.reusingImageAsReference) {
   205     this.disableDisplay(document.getElementById(this.imageElementId));
   206   }
   208   this.takeReferenceSnapshot();
   209   this.setupPolledImage();
   210   SimpleTest.executeSoon(pollForSuccess);
   211 };
   213 AnimationTest.prototype.setupPolledImage = function ()
   214 {
   215   // Make sure the image is visible
   216   if (!this.reusingImageAsReference) {
   217     this.enableDisplay(document.getElementById(this.imageElementId));
   218     var currentSnapshot = snapshotWindow(window, false);
   219     var result = compareSnapshots(currentSnapshot,
   220                                   this.referenceSnapshot, true);
   222     this.currentSnapshotDataURI = currentSnapshot.toDataURL();
   224     if (result[0]) {
   225       // SUCCESS!
   226       ok(true, "Animated image looks correct, at poll #"
   227          + this.pollCounter);
   229       this.cleanUpAndFinish();
   230     }
   231   } else {
   232     if (!gIsRefImageLoaded) {
   233       this.myImage = new Image();
   234       this.myImage.onload = reuseImageCallback;
   235       document.getElementById(this.imageElementId).setAttribute('src',
   236         this.referenceElementId);
   237     }
   238   }
   239 }
   241 AnimationTest.prototype.checkImage = function ()
   242 {
   243   if (this.isTestFinished) {
   244     return;
   245   }
   247   this.pollCounter++;
   249   // We need this for some tests, because we need to force the
   250   // test image to be visible.
   251   if (!this.reusingImageAsReference) {
   252     this.enableDisplay(document.getElementById(this.imageElementId));
   253   }
   255   var currentSnapshot = snapshotWindow(window, false);
   256   var result = compareSnapshots(currentSnapshot, this.referenceSnapshot, true);
   258   this.currentSnapshotDataURI = currentSnapshot.toDataURL();
   260   if (result[0]) {
   261     // SUCCESS!
   262     ok(true, "Animated image looks correct, at poll #"
   263        + this.pollCounter);
   265     this.cleanUpAndFinish();
   266   }
   267 };
   269 AnimationTest.prototype.takeReferenceSnapshot = function ()
   270 {
   271   this.numRefsTaken++;
   273   // Test to make sure the reference image doesn't match a clean snapshot
   274   if (!this.cleanSnapshot) {
   275     this.takeCleanSnapshot();
   276   }
   278   // Used later to verify that the reference div disappeared
   279   if (!this.blankSnapshot) {
   280     this.takeBlankSnapshot();
   281   }
   283   if (this.reusingImageAsReference) {
   284     // Show reference elem (which is actually our image), & take a snapshot
   285     var referenceElem = document.getElementById(this.imageElementId);
   286     this.enableDisplay(referenceElem);
   288     this.referenceSnapshot = snapshotWindow(window, false);
   290     var snapResult = compareSnapshots(this.cleanSnapshot,
   291                                       this.referenceSnapshot, false);
   292     if (!snapResult[0]) {
   293       if (this.blankWaitTime > 2000) {
   294         // if it took longer than two seconds to load the image, we probably
   295         // have a problem.
   296         this.wereFailures = true;
   297         ok(snapResult[0],
   298            "Reference snapshot shouldn't match clean (non-image) snapshot");
   299       } else {
   300         this.blankWaitTime += currentTest.pollFreq;
   301         // let's wait a bit and see if it clears up
   302         setTimeout(referencePoller, currentTest.pollFreq);
   303         return;
   304       }
   305     }
   307     ok(snapResult[0],
   308        "Reference snapshot shouldn't match clean (non-image) snapshot");
   310     var dataString = "Reference Snapshot #" + this.numRefsTaken;
   311     this.outputDebugInfo(dataString, 'refSnapId',
   312                          this.referenceSnapshot.toDataURL());
   313   } else {
   314     // Make sure the animation section is hidden
   315     this.disableDisplay(document.getElementById(this.imageElementId));
   317     // Show reference div, & take a snapshot
   318     var referenceDiv = document.getElementById(this.referenceElementId);
   319     this.enableDisplay(referenceDiv);
   321     this.referenceSnapshot = snapshotWindow(window, false);
   322     var snapResult = compareSnapshots(this.cleanSnapshot,
   323                                       this.referenceSnapshot, false);
   324     if (!snapResult[0]) {
   325       if (this.blankWaitTime > 2000) {
   326         // if it took longer than two seconds to load the image, we probably
   327         // have a problem.
   328         this.wereFailures = true;
   329         ok(snapResult[0],
   330            "Reference snapshot shouldn't match clean (non-image) snapshot");
   331       } else {
   332         this.blankWaitTime += 20;
   333         // let's wait a bit and see if it clears up
   334         setTimeout(referencePoller, 20);
   335         return;
   336       }
   337     }
   339     ok(snapResult[0],
   340        "Reference snapshot shouldn't match clean (non-image) snapshot");
   342     var dataString = "Reference Snapshot #" + this.numRefsTaken;
   343     this.outputDebugInfo(dataString, 'refSnapId',
   344                          this.referenceSnapshot.toDataURL());
   346     // Re-hide reference div, and take another snapshot to be sure it's gone
   347     this.disableDisplay(referenceDiv);
   348     this.testBlankCameBack();
   349   }
   350 };
   352 AnimationTest.prototype.enableDisplay = function(element)
   353 {
   354   if (!element) {
   355     return;
   356   }
   358   if (!this.xulTest) {
   359     element.style.display = '';
   360   } else {
   361     element.setAttribute('hidden', 'false');
   362   }
   363 };
   365 AnimationTest.prototype.disableDisplay = function(element)
   366 {
   367   if (!element) {
   368     return;
   369   }
   371   if (!this.xulTest) {
   372     element.style.display = 'none';
   373   } else {
   374     element.setAttribute('hidden', 'true');
   375   }
   376 };
   378 AnimationTest.prototype.testBlankCameBack = function()
   379 {
   380   var blankSnapshot2 = snapshotWindow(window, false);
   381   var result = compareSnapshots(this.blankSnapshot, blankSnapshot2, true);
   382   ok(result[0], "Reference image should disappear when it becomes display:none");
   384   if (!result[0]) {
   385     this.wereFailures = true;
   386     var dataString = "Second Blank Snapshot";
   387     this.outputDebugInfo(dataString, 'blank2SnapId', result[2]);
   388   }
   389 };
   391 AnimationTest.prototype.cleanUpAndFinish = function ()
   392 {
   393   // On the off chance that failTest and checkImage are triggered
   394   // back-to-back, use a flag to prevent multiple calls to SimpleTest.finish.
   395   if (this.isTestFinished) {
   396     return;
   397   }
   399   this.isTestFinished = true;
   401   // Call our closing function, if one exists
   402   if (this.closeFunc) {
   403     this.closeFunc();
   404     return;
   405   }
   407   if (this.wereFailures) {
   408     document.getElementById(this.debugElementId).style.display = 'block';
   409   }
   411   SimpleTest.finish();
   412   document.getElementById(this.debugElementId).style.display = "";
   413 };

mercurial