tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_img_mutations.html (8878B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <meta charset="utf-8">
      5  <title>Image srcset mutations</title>
      6  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      7  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
      8 </head>
      9 <body>
     10  <script type="application/javascript">
     11    "use strict";
     12 
     13    // Tests the relevant mutations part of the spec for img src and srcset
     14    // and that img.src still behaves by the older spec. (Bug 1076583)
     15    // https://html.spec.whatwg.org/#relevant-mutations
     16    SimpleTest.waitForExplicitFinish();
     17 
     18    // 50x50 png
     19    var testPNG50 = new URL("image_50.png?noCache=" + Math.random(), location).href;
     20    // 100x100 png
     21    var testPNG100 = new URL("image_100.png?noCache=" + Math.random(), location).href;
     22    // 200x200 png
     23    var testPNG200 = new URL("image_200.png?noCache=" + Math.random(), location).href;
     24 
     25    var tests = [];
     26    var img;
     27    var expectingErrors = 0;
     28    var expectingLoads = 0;
     29    var afterExpectCallback;
     30 
     31    function onImgLoad() {
     32      ok(expectingLoads > 0, "expected load");
     33      if (expectingLoads > 0) {
     34        expectingLoads--;
     35      }
     36      if (!expectingLoads && !expectingErrors && afterExpectCallback) {
     37        setTimeout(afterExpectCallback, 0);
     38        afterExpectCallback = null;
     39      }
     40    }
     41    function onImgError() {
     42      ok(expectingErrors > 0, "expected error");
     43      if (expectingErrors > 0) {
     44        expectingErrors--;
     45      }
     46      if (!expectingLoads && !expectingErrors && afterExpectCallback) {
     47        setTimeout(afterExpectCallback, 0);
     48        afterExpectCallback = null;
     49      }
     50    }
     51    function expectEvents(loads, errors, callback) {
     52      let p = new Promise(resolve => {
     53        if (!loads && !errors) {
     54          setTimeout(resolve, 0);
     55        } else {
     56          expectingLoads += loads;
     57          expectingErrors += errors;
     58          info("Waiting for " + expectingLoads + " load and " + expectingErrors + " error events");
     59          afterExpectCallback = resolve;
     60        }
     61      });
     62      return p.then(() => callback && callback());
     63    }
     64 
     65    //
     66    // Test that img.src still does some work synchronously per the older spec (bug 1076583)
     67    //
     68    tests.push(async function test1() {
     69      info("test 1");
     70      img.src = testPNG50;
     71      is(img.currentSrc, "", "Should not have synchronously selected source");
     72 
     73      await expectEvents(1, 0);
     74      is(img.currentSrc, testPNG50, "Should now have testPNG50 as current request");
     75 
     76      // Assigning a wrong URL should not trigger error event (bug 1321300).
     77      img.src = '//:0'; // Wrong URL
     78      is(img.currentSrc, "", "Should have dropped current request sync");
     79 
     80      img.src = "non_existent_image.404";
     81      is(img.currentSrc, "", "Should still have empty current request");
     82 
     83      await expectEvents(0, 1);
     84      ok(img.currentSrc.endsWith("non_existent_image.404"), "Should have asynchronously selected source");
     85 
     86      img.removeAttribute("src");
     87      is(img.currentSrc, "", "Should have dropped currentSrc sync");
     88 
     89      // Load another image while previous load is still pending
     90      img.src = testPNG200;
     91      is(img.currentSrc, "", "Should asynchronously load selected source");
     92 
     93      await expectEvents(1, 0);
     94      is(img.currentSrc, testPNG200, "Should have asynchronously loaded selected source");
     95      nextTest();
     96    });
     97 
     98 
     99    // Setting srcset should be async
    100    tests.push(function () {
    101      info("test 2");
    102      img.srcset = testPNG100;
    103      is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
    104 
    105      expectEvents(1, 0, function() {
    106        is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
    107        nextTest();
    108      });
    109    });
    110 
    111    // Setting srcset, even to no ultimate effect, should trigger a reload
    112    tests.push(function () {
    113      info("test 3");
    114      img.srcset = testPNG100 + " 1x, " + testPNG200 + " 2x";
    115      is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
    116 
    117      expectEvents(1, 0, function() {
    118        is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
    119        nextTest();
    120      });
    121    });
    122 
    123    // Should switch to src as 1x source
    124    tests.push(function () {
    125      info("test 4");
    126      img.srcset = testPNG50 + " 2x";
    127      is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
    128 
    129      expectEvents(1, 0, function() {
    130        is(img.currentSrc, testPNG200, "Should now have testPNG200 as current request");
    131        nextTest();
    132      });
    133    });
    134 
    135    // Changing src while we have responsive attributes should not be sync
    136    tests.push(function () {
    137      info("test 5");
    138      img.src = testPNG100;
    139      is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
    140 
    141      expectEvents(1, 0, function() {
    142        is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
    143 
    144        // Switch to using srcset again for next test
    145        img.srcset = testPNG100;
    146        expectEvents(1, 0, nextTest);
    147      });
    148    });
    149 
    150    // img.src = img.src should trigger an async event even in responsive mode
    151    tests.push(function () {
    152      info("test 6");
    153      is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
    154      // eslint-disable-next-line no-self-assign
    155      img.src = img.src;
    156      is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
    157 
    158      expectEvents(1, 0, nextTest);
    159    });
    160 
    161    // img.srcset = img.srcset should be a no-op
    162    tests.push(function () {
    163      info("test 7");
    164      // eslint-disable-next-line no-self-assign
    165      img.srcset = img.srcset;
    166      is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
    167 
    168      expectEvents(0, 0, nextTest);
    169    });
    170 
    171    // re-binding the image to the document should be a no-op
    172    tests.push(function () {
    173      info("test 8");
    174      document.body.appendChild(img);
    175      is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
    176 
    177      expectEvents(0, 0, nextTest);
    178    });
    179 
    180    // We should re-run our selection algorithm when any load event occurs
    181    tests.push(function () {
    182      info("test 9");
    183      img.srcset = testPNG50 + " 1x, " + testPNG200 + " 2x";
    184      is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
    185 
    186      expectEvents(1, 0, function() {
    187        is(img.currentSrc, testPNG50, "Should now have testPNG50 as current request");
    188 
    189        // The preference change will trigger a load, as the image will change
    190        SpecialPowers.pushPrefEnv({'set': [ ["layout.css.devPixelsPerPx", "2.0"] ] });
    191        expectEvents(1, 0, function() {
    192          is(img.currentSrc, testPNG200, "Should now have testPNG200 as current request");
    193          // eslint-disable-next-line no-self-assign
    194          img.src = img.src;
    195          is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
    196          // img.src = img.src is special-cased by the spec. It should always
    197          // trigger an load event
    198          expectEvents(1, 0, function() {
    199            is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
    200            expectEvents(0, 0, nextTest);
    201          });
    202        })
    203      });
    204    });
    205 
    206    // Removing srcset attr should async switch back to src
    207    tests.push(async function () {
    208      info("test 10");
    209      is(img.currentSrc, testPNG200, "Should have testPNG200 as current request");
    210 
    211      img.removeAttribute("srcset");
    212      is(img.currentSrc, testPNG100, "Should testPNG100 as current request (hits sync load case for src)");
    213 
    214      await expectEvents(1, 0);
    215      is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
    216 
    217      expectEvents(0, 0, nextTest);
    218    });
    219 
    220    function nextTest() {
    221      if (tests.length) {
    222        // Spin event loop to make sure no unexpected image events are
    223        // pending (unexpected events will assert in the handlers)
    224        setTimeout(async function() {
    225          await (tests.shift())();
    226        }, 0);
    227      } else {
    228        // Remove the event listeners to prevent the prefenv being popped from
    229        // causing test failures.
    230        img.removeEventListener("load", onImgLoad);
    231        img.removeEventListener("error", onImgError);
    232        SimpleTest.finish();
    233      }
    234    }
    235 
    236    addEventListener("load", function() {
    237      SpecialPowers.pushPrefEnv({'set': [["layout.css.devPixelsPerPx", "1.0"]] },
    238                                function() {
    239        // Create this after the pref is set, as it is guarding webIDL attributes
    240        img = document.createElement("img");
    241        img.addEventListener("load", onImgLoad);
    242        img.addEventListener("error", onImgError);
    243        document.body.appendChild(img);
    244        setTimeout(nextTest, 0);
    245      });
    246    });
    247  </script>
    248 </body>
    249 </html>