summaryrefslogtreecommitdiffstats
path: root/dom/tests/mochitest/general/test_img_mutations.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/tests/mochitest/general/test_img_mutations.html')
-rw-r--r--dom/tests/mochitest/general/test_img_mutations.html239
1 files changed, 239 insertions, 0 deletions
diff --git a/dom/tests/mochitest/general/test_img_mutations.html b/dom/tests/mochitest/general/test_img_mutations.html
new file mode 100644
index 0000000000..88cb40e181
--- /dev/null
+++ b/dom/tests/mochitest/general/test_img_mutations.html
@@ -0,0 +1,239 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Image srcset mutations</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ // Tests the relevant mutations part of the spec for img src and srcset
+ // and that img.src still behaves by the older spec. (Bug 1076583)
+ // https://html.spec.whatwg.org/#relevant-mutations
+ SimpleTest.waitForExplicitFinish();
+
+ // 50x50 png
+ var testPNG50 = new URL("image_50.png?noCache=" + Math.random(), location).href;
+ // 100x100 png
+ var testPNG100 = new URL("image_100.png?noCache=" + Math.random(), location).href;
+ // 200x200 png
+ var testPNG200 = new URL("image_200.png?noCache=" + Math.random(), location).href;
+
+ var tests = [];
+ var img;
+ var expectingErrors = 0;
+ var expectingLoads = 0;
+ var afterExpectCallback;
+
+ function onImgLoad() {
+ ok(expectingLoads > 0, "expected load");
+ if (expectingLoads > 0) {
+ expectingLoads--;
+ }
+ if (!expectingLoads && !expectingErrors && afterExpectCallback) {
+ setTimeout(afterExpectCallback, 0);
+ afterExpectCallback = null;
+ }
+ }
+ function onImgError() {
+ ok(expectingErrors > 0, "expected error");
+ if (expectingErrors > 0) {
+ expectingErrors--;
+ }
+ if (!expectingLoads && !expectingErrors && afterExpectCallback) {
+ setTimeout(afterExpectCallback, 0);
+ afterExpectCallback = null;
+ }
+ }
+ function expectEvents(loads, errors, callback) {
+ if (!loads && !errors) {
+ setTimeout(callback, 0);
+ } else {
+ expectingLoads += loads;
+ expectingErrors += errors;
+ info("Waiting for " + expectingLoads + " load and " + expectingErrors + " error events");
+ afterExpectCallback = callback;
+ }
+ }
+
+ //
+ // Test that img.src still does some work synchronously per the older spec (bug 1076583)
+ //
+ tests.push(function test1() {
+ info("test 1");
+ img.src = testPNG50;
+ is(img.currentSrc, testPNG50, "Should have synchronously selected source");
+
+ // Assigning a wrong URL should not trigger error event (bug 1321300).
+ img.src = '//:0'; // Wrong URL
+
+ img.src = "non_existent_image.404";
+ ok(img.currentSrc.endsWith("non_existent_image.404"), "Should have synchronously selected source");
+
+ img.removeAttribute("src");
+ is(img.currentSrc, '', "Should have dropped currentSrc");
+
+ // Load another image while previous load is still pending
+ img.src = testPNG200;
+ is(img.currentSrc, testPNG200, "Should have synchronously selected source");
+
+ // No events should have fired synchronously, now we should get just one load (and no 404 error)
+ expectEvents(1, 0, nextTest);
+ });
+
+
+ // Setting srcset should be async
+ tests.push(function () {
+ info("test 2");
+ img.srcset = testPNG100;
+ is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
+
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
+ nextTest();
+ });
+ });
+
+ // Setting srcset, even to no ultimate effect, should trigger a reload
+ tests.push(function () {
+ info("test 3");
+ img.srcset = testPNG100 + " 1x, " + testPNG200 + " 2x";
+ is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
+
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
+ nextTest();
+ });
+ });
+
+ // Should switch to src as 1x source
+ tests.push(function () {
+ info("test 4");
+ img.srcset = testPNG50 + " 2x";
+ is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
+
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG200, "Should now have testPNG200 as current request");
+ nextTest();
+ });
+ });
+
+ // Changing src while we have responsive attributes should not be sync
+ tests.push(function () {
+ info("test 5");
+ img.src = testPNG100;
+ is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
+
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
+
+ // Switch to using srcset again for next test
+ img.srcset = testPNG100;
+ expectEvents(1, 0, nextTest);
+ });
+ });
+
+ // img.src = img.src should trigger an async event even in responsive mode
+ tests.push(function () {
+ info("test 6");
+ is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
+ // eslint-disable-next-line no-self-assign
+ img.src = img.src;
+ is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
+
+ expectEvents(1, 0, nextTest);
+ });
+
+ // img.srcset = img.srcset should be a no-op
+ tests.push(function () {
+ info("test 7");
+ // eslint-disable-next-line no-self-assign
+ img.srcset = img.srcset;
+ is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
+
+ expectEvents(0, 0, nextTest);
+ });
+
+ // re-binding the image to the document should be a no-op
+ tests.push(function () {
+ info("test 8");
+ document.body.appendChild(img);
+ is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
+
+ expectEvents(0, 0, nextTest);
+ });
+
+ // We should re-run our selection algorithm when any load event occurs
+ tests.push(function () {
+ info("test 9");
+ img.srcset = testPNG50 + " 1x, " + testPNG200 + " 2x";
+ is(img.currentSrc, testPNG100, "Should still have testPNG100 as current request");
+
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG50, "Should now have testPNG50 as current request");
+
+ // The preference change will trigger a load, as the image will change
+ SpecialPowers.pushPrefEnv({'set': [ ["layout.css.devPixelsPerPx", "2.0"] ] });
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG200, "Should now have testPNG200 as current request");
+ // eslint-disable-next-line no-self-assign
+ img.src = img.src;
+ is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
+ // img.src = img.src is special-cased by the spec. It should always
+ // trigger an load event
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
+ expectEvents(0, 0, nextTest);
+ });
+ })
+ });
+ });
+
+ // Removing srcset attr should async switch back to src
+ tests.push(function () {
+ info("test 10");
+ is(img.currentSrc, testPNG200, "Should have testPNG200 as current request");
+
+ img.removeAttribute("srcset");
+ is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
+
+ expectEvents(1, 0, function() {
+ is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request");
+
+ expectEvents(0, 0, nextTest);
+ });
+ });
+
+ function nextTest() {
+ if (tests.length) {
+ // Spin event loop to make sure no unexpected image events are
+ // pending (unexpected events will assert in the handlers)
+ setTimeout(function() {
+ (tests.shift())();
+ }, 0);
+ } else {
+ // Remove the event listeners to prevent the prefenv being popped from
+ // causing test failures.
+ img.removeEventListener("load", onImgLoad);
+ img.removeEventListener("error", onImgError);
+ SimpleTest.finish();
+ }
+ }
+
+ addEventListener("load", function() {
+ SpecialPowers.pushPrefEnv({'set': [["layout.css.devPixelsPerPx", "1.0"]] },
+ function() {
+ // Create this after the pref is set, as it is guarding webIDL attributes
+ img = document.createElement("img");
+ img.addEventListener("load", onImgLoad);
+ img.addEventListener("error", onImgError);
+ document.body.appendChild(img);
+ setTimeout(nextTest, 0);
+ });
+ });
+ </script>
+</body>
+</html>