--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -12413,16 +12413,32 @@
"path": "IndexedDB/value.htm",
"url": "/IndexedDB/value.htm"
},
{
"path": "IndexedDB/value_recursive.htm",
"url": "/IndexedDB/value_recursive.htm"
},
{
+ "path": "ResizeObserver/ResizeObserver-eventloop.html",
+ "url": "/ResizeObserver/ResizeObserver-eventloop.html"
+ },
+ {
+ "path": "ResizeObserver/ResizeObserver-notify.html",
+ "url": "/ResizeObserver/ResizeObserver-notify.html"
+ },
+ {
+ "path": "ResizeObserver/ResizeObserver-observe.html",
+ "url": "/ResizeObserver/ResizeObserver-observe.html"
+ },
+ {
+ "path": "ResizeObserver/ResizeObserver-svg.html",
+ "url": "/ResizeObserver/ResizeObserver-svg.html"
+ },
+ {
"path": "WebCryptoAPI/digest/digest.worker.js",
"url": "/WebCryptoAPI/digest/digest.worker"
},
{
"path": "WebCryptoAPI/encrypt_decrypt/aes_cbc.worker.js",
"url": "/WebCryptoAPI/encrypt_decrypt/aes_cbc.worker"
},
{
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/ResizeObserver/ResizeObserver-eventloop.html
@@ -0,0 +1,256 @@
+<!doctype html>
+<!--
+Source:
+https://github.com/WICG/ResizeObserver/blob/master/test/eventloop.html
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resizeTestHelper.js"></script>
+<style>
+ div {
+ border: 1px dotted gray
+ }
+</style>
+<p>ResizeObserver notification event loop tests</p>
+<div id="target1" style="width:100px;height:100px;">t1
+</div>
+<div id="container">
+ <div id="a1" style="width:100px;height:100px">
+ <div id="a2" style="width:100px;height:100px">
+ </div>
+ </div>
+ <div id="b1" style="width:100px;height:100px">
+ <div id="b2" style="width:100px;height:100px">
+ </div>
+ </div>
+</div>
+<script>
+'use strict';
+
+let t1 = document.querySelector('#target1');
+
+// allow uncaught exception because ResizeObserver posts exceptions
+// to window error handler when limit is exceeded.
+// This codepath is tested in this file.
+
+setup({allow_uncaught_exception: true});
+
+function template() {
+ let helper = new ResizeTestHelper(
+ "test0: title",
+ [
+ {
+ setup: observer => {
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+var onErrorCalled = false;
+
+window.onerror = err => {
+ onErrorCalled = true;
+}
+
+function test0() {
+
+ let divs = [t1];
+ let rAF = 0;
+ let helper = new ResizeTestHelper(
+ "test0: multiple notifications inside same event loop",
+ [
+ {
+ setup: observer => {
+ onErrorCalled = false;
+ let t2 = document.createElement('div');
+ let t3 = document.createElement('div');
+ t2.appendChild(t3);
+ t1.appendChild(t2);
+ divs.push(t2);
+ divs.push(t3);
+ observer.observe(t1);
+ observer.observe(t2);
+ observer.observe(t3);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 3, "3 notifications");
+ }
+ },
+ {
+ setup: observer => {
+ helper.startCountingRaf();
+ divs.forEach( el => { el.style.width = "101px";});
+ },
+ notify: (entries, observer) => {
+ // t1 is not delivered
+ assert_equals(entries.length, 2, "2 notifications");
+ assert_equals(helper.rafCount, 0, "still in same loop");
+ }
+ },
+ {
+ setup: observer => {
+ divs.forEach( el => { el.style.width = "102px";});
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1, "1 notifications");
+ assert_equals(helper.rafCount, 0, "same loop");
+ }
+ },
+ { // t1 and t2 get notified
+ setup: observer => {
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 2, "2 notifications");
+ assert_equals(onErrorCalled, true, "error was fired");
+ observer.disconnect();
+ while (t1.childNodes.length > 0)
+ t1.removeChild(t1.childNodes[0]);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test1() {
+
+ var resizers = [t1];
+ // Testing depths of shadow roots
+ // DOM: t1 <- t2 <- t3 <-shadow- t4 <- t5
+ let helper = new ResizeTestHelper(
+ "test1: depths of shadow roots",
+ [
+ {
+ setup: observer => {
+ onErrorCalled = false;
+ let t2 = document.createElement('div');
+ t1.appendChild(t2);
+ resizers.push(t2);
+ let t3 = document.createElement('div');
+ resizers.push(t3);
+ t2.appendChild(t3);
+ let shadow = t3.createShadowRoot();
+ let t4 = document.createElement('div');
+ resizers.push(t4);
+ shadow.appendChild(t4);
+ let t5 = document.createElement('div');
+ resizers.push(t5);
+ t4.appendChild(t5);
+ resizers.forEach( el => observer.observe(el) );
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 5, "all entries resized");
+ }
+ },
+ {
+ setup: observer => {
+ resizers.forEach( el => el.style.width = "111px" );
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 4, "depth limited");
+ }
+ },
+ {
+ setup: observer => {
+ resizers.forEach( el => el.style.width = "112px" );
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 3, "depth limited");
+ }
+ },
+ {
+ setup: observer => {
+ resizers.forEach( el => el.style.width = "113px" );
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 2, "depth limited");
+ }
+ },
+ {
+ setup: observer => {
+ resizers.forEach( el => el.style.width = "114px" );
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1, "depth limited");
+ }
+ },
+ {
+ setup: observer => {
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 4, "limit notifications");
+ assert_equals(onErrorCalled, true, "breached limit");
+ observer.disconnect();
+ t1.removeChild(t1.firstChild);
+ }
+ },
+ ]);
+ return helper.start();
+}
+
+function test2() {
+ let container = document.querySelector('#container');
+ let a1 = document.querySelector('#a1');
+ let a2 = document.querySelector('#a2');
+ let b1 = document.querySelector('#b1');
+ let b2 = document.querySelector('#b2');
+ let targets = [a1, a2, b1, b2];
+
+ let helper = new ResizeTestHelper(
+ "test2: move target in dom while inside event loop",
+ [
+ {
+ setup: observer => {
+ for (let t of targets)
+ observer.observe(t);
+ },
+ notify: (entries, observer) => {
+ return true; // delay next observation
+ }
+ },
+ { // resize them all
+ setup: observer => {
+ for (let t of targets)
+ t.style.width = "110px";
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, targets.length, "all targets observed");
+ }
+ },
+ { // resize all, move dom upwards
+ setup: observer => {
+ for (let t of targets)
+ t.style.width = "130px";
+ container.appendChild(b2);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1, "b2 moved upwards");
+ assert_equals(entries[0].target, a2);
+ }
+ },
+ { // resize all, move dom downwards
+ setup: observer => {
+ for (let t of targets)
+ t.style.width = "130px";
+ a2.appendChild(b2);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1, "b2 moved downwards");
+ assert_equals(entries[0].target, b2);
+ a1.appendChild(a2);
+ }
+ },
+ ]);
+ return helper.start();
+}
+
+let guard = async_test('guard');
+test0()
+ .then(() => { return test1(); })
+ .then(() => { return test2(); })
+ .then(() => { guard.done(); });
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/ResizeObserver/ResizeObserver-notify.html
@@ -0,0 +1,362 @@
+<!doctype html>
+<!--
+Source:
+https://github.com/WICG/ResizeObserver/blob/master/test/notify.html
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resizeTestHelper.js"></script>
+<style>
+ div {
+ border: 1px dotted gray
+ }
+ .transform {
+ transform: scale(2,2) rotate(90deg)
+ }
+</style>
+<p>ResizeObserver tests</p>
+<div id="target1" style="width:100px;height:100px;">t1
+ <div id="target2" style="width:100px;height:100px;">t2
+ <div id="target3" style="width:100px;height:100px;">t3
+ <span id="inline">inline</span>
+ </div>
+ </div>
+</div>
+<div id="absolute"
+ style="width:100.5px;height:100.5px;position:absolute;
+ top:10.3px;left:10.3px">
+</div>
+<script>
+'use strict';
+
+let t1 = document.querySelector('#target1');
+let t2 = document.querySelector('#target2');
+let t3 = document.querySelector('#target3');
+let abs = document.querySelector('#absolute');
+let inline = document.querySelector('#inline');
+
+function test0() {
+ let helper = new ResizeTestHelper(
+ "test0: notification ordering",
+ [
+ {
+ setup: observer => {
+ observer.observe(t3);
+ observer.observe(t2);
+ observer.observe(t1);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 3, "3 resizes");
+ assert_equals(entries[0].target, t3, "ordering");
+ assert_equals(entries[1].target, t2, "ordering");
+ assert_equals(entries[2].target, t1, "ordering");
+ observer.disconnect();
+ t1.style.width = "100px";
+ t2.style.width = "100px";
+ t3.style.width = "100px";
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test1() {
+ let helper = new ResizeTestHelper(
+ "test1: display:none triggers notification",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ t1.style.display = "none";
+ },
+ notify: (entries, observer) => {
+ t1.style.display = "";
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+
+function test2() {
+ let helper = new ResizeTestHelper(
+ "test2: remove/appendChild trigger notification",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ { // "removeChild triggers notification"
+ setup: observer => {
+ t1.parentNode.removeChild(t1);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries[0].target, t1);
+ return true; // Delay next step
+ }
+ },
+ { // "appendChild triggers notification",
+ setup: observer => {
+ document.body.appendChild(t1);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries[0].target, t1)
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+
+function test3() {
+ let helper = new ResizeTestHelper(
+ "test3: dimensions match",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ t1.style.width = "200.5px";
+ t1.style.height = "100px";
+ t1.style.paddingLeft = "20px";
+ t1.style.paddingTop = "10px";
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries[0].contentRect.left,20);
+ assert_equals(entries[0].contentRect.top,10);
+ assert_between_inclusive(entries[0].contentRect.width, 200.4, 200.6,
+ "width is not rounded");
+ assert_equals(entries[0].contentRect.height, 100);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test4() {
+ let helper = new ResizeTestHelper(
+ "test4: transform do not cause notifications",
+ [
+ {
+ setup: observer => {
+ observer.observe(t2);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ t2.classList.add("transform");
+ },
+ notify: (entries, observer) => {
+ assert_unreached("transform must not trigger notifications");
+ },
+ timeout: () => {
+ t2.classList.remove("transform");
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test5() {
+ let helper = new ResizeTestHelper(
+ "test5: moving an element does not trigger notifications",
+ [
+ {
+ setup: observer => {
+ observer.observe(abs);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ abs.style.top = "20.33px";
+ abs.style.left = "20.33px";
+ },
+ notify: (entries, observer) => {
+ assert_unreached("movement should not cause resize notifications");
+ },
+ timeout: () => {
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test6() {
+ let helper = new ResizeTestHelper(
+ "test6: observe non-replaced inline element",
+ [
+ {
+ setup: observer => {
+ observer.observe(inline);
+ observer.observe(t1);
+ t1.style.width = "66px";
+ inline.style.width = "66px";
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1,
+ "inline elements must not trigger notifications");
+ assert_equals(entries[0].target, t1,
+ "inline elements must not trigger notifications");
+ return true; // Delay next step
+ }
+ },
+ { // "inline element that becomes block should notify",
+ setup: observer => {
+ inline.style.display = "block";
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries[0].target, inline);
+ return true; // Delay next step
+ }
+ },
+ { // "block element that becomes inline should notify",
+ setup: observer => {
+ inline.style.display = "inline";
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries[0].target, inline);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test7() {
+ let helper = new ResizeTestHelper(
+ "test7: unobserve inside notify callback",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ observer.observe(t2);
+ },
+ notify: (entries, observer) => {
+ t1.style.width = "777px";
+ t2.style.width = "777px";
+ observer.unobserve(t1);
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1, "only t2 is observed");
+ assert_equals(entries[0].target, t2, "only t2 is observed");
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test8() {
+ let helper = new ResizeTestHelper(
+ "test8: observe inside notify callback",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ },
+ notify: (entries, observer) => {
+ observer.observe(t2);
+ t2.style.width = "888px";
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1, "only t2 is observed");
+ assert_equals(entries[0].target, t2, "only t2 is observed");
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test9() {
+ let helper = new ResizeTestHelper(
+ "test9: disconnect inside notify callback",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ },
+ notify: (entries, observer) => {
+ t1.style.width = "999px";
+ observer.disconnect();
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ },
+ notify: (entries, observer) => {
+ assert_unreached("there should be no notifications after disconnect");
+ },
+ timeout: () => {
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test10() {
+ var parent = t1.parentNode;
+ let helper = new ResizeTestHelper(
+ "test10: element notifies when parent removed",
+ [
+ {
+ setup: observer => {
+ observer.observe(t3);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ t1.parentNode.removeChild(t1);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].target, t3);
+ parent.appendChild(t1);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+let guard = async_test('guard');
+test0()
+ .then(() => { return test1(); })
+ .then(() => { return test2(); })
+ .then(() => { return test3(); })
+ .then(() => { return test4(); })
+ .then(() => { return test5(); })
+ .then(() => { return test6(); })
+ .then(() => { return test7(); })
+ .then(() => { return test8(); })
+ .then(() => { return test9(); })
+ .then(() => { return test10(); })
+ .then(() => { guard.done(); });
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/ResizeObserver/ResizeObserver-observe.html
@@ -0,0 +1,183 @@
+<!doctype html>
+<!--
+Source:
+https://github.com/WICG/ResizeObserver/blob/master/test/observe.html
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resizeTestHelper.js"></script>
+<p>ResizeObserver tests</p>
+<div id="target1" style="width:100px;height:100px;">t1</div>
+<div id="target2" style="width:100px;height:100px;">t2</div>
+<img id="target3" style="width:100px;height:100px;" src="imghelper.png">
+<iframe src="iframe.html" width="300px" height="100px" style="display:block">
+</iframe>
+<script>
+'use strict';
+
+let t1 = document.querySelector('#target1');
+let t2 = document.querySelector('#target2');
+
+// allow uncaught exception because ResizeObserver posts exceptions
+// to window error handler when limit is exceeded.
+setup({allow_uncaught_exception: true});
+
+function test0() {
+ let helper = new ResizeTestHelper(
+ "test0: simple observation",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ t1.style.width = "5px";
+ },
+ notify: entries => {
+ assert_equals(entries.length, 1, "1 pending notification");
+ assert_equals(entries[0].target, t1, "target is t1");
+ assert_equals(entries[0].contentRect.width, 5, "target width");
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test1() {
+ let helper = new ResizeTestHelper(
+ "test1: multiple observation on same element trigger only one",
+ [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ observer.observe(t1);
+ t1.style.width = "10px";
+ },
+ notify: entries => {
+ assert_equals(entries.length, 1, "1 pending notification");
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test2() {
+ test(() => {
+ assert_throws(null, _=> {
+ let ro = new ResizeObserver(() => {});
+ ro.observe({});
+ });
+ },
+ "test2: throw exception when observing non-element"
+ );
+ return Promise.resolve();
+}
+
+function test3() {
+ let helper = new ResizeTestHelper(
+ "test3: disconnect stops all notifications", [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ observer.observe(t2);
+ observer.disconnect();
+ t1.style.width = "30px";
+ },
+ notify: entries => {
+ assert_unreached("no entries should be observed");
+ },
+ timeout: () => {
+ // expected
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test4() {
+ let helper = new ResizeTestHelper(
+ "test4: unobserve target stops notifications, unobserve non-observed does nothing", [
+ {
+ setup: observer => {
+ observer.observe(t1);
+ observer.observe(t2);
+ observer.unobserve(t1);
+ observer.unobserve(document.body);
+ t1.style.width = "40px";
+ t2.style.width = "40px";
+ },
+ notify: entries => {
+ assert_equals(entries.length, 1, "only t2");
+ assert_equals(entries[0].target, t2, "t2 was observed");
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test5() {
+ let t3 = document.querySelector('#target3');
+ var helper = new ResizeTestHelper("test5: observe img",[
+ {
+ setup: observer => {
+ observer.observe(t3);
+ },
+ notify: entries => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ t3.style.width = "100.5px";
+ },
+ notify: entries => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 100.5);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test6() {
+ let resolvePromise;
+ let promise = new Promise((resolve) => {
+ resolvePromise = resolve;
+ });
+ let test = async_test('test6: iframe notifications');
+ let testRequested = false;
+ let iframe = document.querySelector('iframe');
+ window.addEventListener('message', event => {
+ switch(event.data) {
+ case 'readyToTest':
+ if (!testRequested) {
+ //iframe.contentWindow.postMessage('startTest', '*');
+ testRequested = true;
+ test.step(()=>{test.done()});
+ resolvePromise();
+ }
+ break;
+ case 'success':
+ case 'fail':
+ window.requestAnimationFrame(() => {
+ test.step( () => {
+ assert_equals(event.data, 'success');
+ test.done();
+ resolvePromise();
+ });
+ });
+ break;
+ }
+ }, false);
+ return promise;
+}
+
+let guard = async_test('guard');
+test0()
+ .then(() => { return test1(); })
+ .then(() => { return test2(); })
+ .then(() => { return test3(); })
+ .then(() => { return test4(); })
+ .then(() => { return test5(); })
+ .then(() => { return test6(); })
+ .then(() => { guard.done(); });
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/ResizeObserver/ResizeObserver-svg.html
@@ -0,0 +1,314 @@
+<!doctype html>
+<!--
+Source:
+https://github.com/WICG/ResizeObserver/blob/master/test/svg.html
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resizeTestHelper.js"></script>
+<p>ResizeObserver svg tests</p>
+<svg height="430" width="500">
+ <circle cx="10" cy="10" r="5" style="fill:orange;stroke:black;stroke-width:1" />
+ <ellipse cx="10" cy="30" rx="5" ry="5"
+ style="fill:orange;stroke:black;stroke-width:1"/>
+ <foreignObject cy="50" width="100" height="20">
+ <body>
+ <p>Here is a paragraph that requires word wrap</p>
+ </body>
+ </foreignObject>
+ <image xlink:href="" x="0" y="100" height="30" width="100" />
+ <line x1="0" y1="50" x2="20" y2="70" stroke="black" stroke-width="2"/>
+ <path d="M 0 100 L 100 100 L 50 150 z"
+ style="fill:orange;stroke:black;stroke-width:1" />
+ <polygon points="0,200 100,200 50,250"
+ style="fill:orange;stroke:black;stroke-width:1" />
+ <polyline points="0,300 100,300 50,350"
+ style="fill:orange;stroke:black;stroke-width:1"/>
+ <rect x="0" y="380" width="10" height="10"
+ style="fill:orange; stroke:black; stroke-width:1" />
+ <text x="0" y="400" font-size="20">svg text tag</text>
+</svg>
+<script>
+'use strict';
+
+setup({allow_uncaught_exception: true});
+
+function test0() {
+ let target = document.querySelector('circle');
+ let helper = new ResizeTestHelper(
+ "test0: observe svg:circle",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('r', 10);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test1() {
+ let target = document.querySelector('ellipse');
+ let helper = new ResizeTestHelper(
+ "test1: observe svg:ellipse",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('rx', 10);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 20);
+ assert_equals(entries[0].contentRect.height, 10);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test2() {
+ let target = document.querySelector('foreignObject');
+ let helper = new ResizeTestHelper(
+ "test2: observe svg:foreignObject",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('width', 200);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 200);
+ assert_equals(entries[0].contentRect.height, 20);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test3() {
+ let target = document.querySelector('image');
+ let helper = new ResizeTestHelper(
+ "test3: observe svg:image",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('height', 40);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 100);
+ assert_equals(entries[0].contentRect.height, 40);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test4() {
+ let target = document.querySelector('line');
+ let helper = new ResizeTestHelper(
+ "test4: observe svg:line",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('y2', 80);
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 20);
+ assert_equals(entries[0].contentRect.height, 30);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test5() {
+ let target = document.querySelector('path');
+ let helper = new ResizeTestHelper(
+ "test5: observe svg:path",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('d', "M 0 100 L 100 100 L 50 160 z");
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 100);
+ assert_equals(entries[0].contentRect.height, 60);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test6() {
+ let target = document.querySelector('polygon');
+ let helper = new ResizeTestHelper(
+ "test6: observe svg:path",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('points', "0,200 100,200 50,260");
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 100);
+ assert_equals(entries[0].contentRect.height, 60);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test7() {
+ let target = document.querySelector('polyline');
+ let helper = new ResizeTestHelper(
+ "test7: observe svg:polyline",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('points', "0,300 100,300 50,360");
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 100);
+ assert_equals(entries[0].contentRect.height, 60);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test8() {
+ let target = document.querySelector('rect');
+ let helper = new ResizeTestHelper(
+ "test8: observe svg:rect",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('width', "20");
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ assert_equals(entries[0].contentRect.width, 20);
+ assert_equals(entries[0].contentRect.height, 10);
+ }
+ }
+ ]);
+ return helper.start();
+}
+
+function test9() {
+ let target = document.querySelector('text');
+ let helper = new ResizeTestHelper(
+ "test9: observe svg:text",
+ [
+ {
+ setup: observer => {
+ observer.observe(target);
+ },
+ notify: (entries, observer) => {
+ return true; // Delay next step
+ }
+ },
+ {
+ setup: observer => {
+ target.setAttribute('font-size', "25");
+ },
+ notify: (entries, observer) => {
+ assert_equals(entries.length, 1);
+ }
+ }
+ ]);
+ return helper.start();
+}
+let guard = async_test('guard');
+test0()
+ .then(() => { return test1(); })
+ .then(() => { return test2(); })
+ .then(() => { return test3(); })
+ .then(() => { return test4(); })
+ .then(() => { return test5(); })
+ .then(() => { return test6(); })
+ .then(() => { return test7(); })
+ .then(() => { return test8(); })
+ .then(() => { return test9(); })
+ .then(() => { guard.done(); });
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/ResizeObserver/iframe.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<head>
+ <script src="resizeTestHelper.js"></script>
+</head>
+<p>iframe test</p>
+<div id="itarget1" style="width:100px;height:100px;">t1</div>
+<script>
+'use strict';
+let t1 = document.querySelector('#itarget1');
+function test0() {
+ let timeoutId = window.setTimeout( () => {
+ window.parent.postMessage('fail', '*');
+ }, ResizeTestHelper.TIMEOUT);
+ let ro = new ResizeObserver(function(entries) {
+ window.clearTimeout(timeoutId);
+ window.parent.postMessage('success', '*');
+ });
+ ro.observe(t1);
+}
+let testStarted = false;
+window.addEventListener('message', function(ev) {
+ switch(ev.data) {
+ case 'startTest':
+ testStarted = true;
+ test0();
+ break;
+ }
+});
+// How does parent know we've loaded problem is solved by
+// broadcasting readyToTest message.
+function broadcastReady() {
+ if (!testStarted) {
+ window.parent.postMessage('readyToTest', '*');
+ window.requestAnimationFrame(broadcastReady);
+ }
+}
+broadcastReady();
+</script>
+<!-- https://github.com/WICG/ResizeObserver/blob/master/test/resources/iframe.html -->
\ No newline at end of file
new file mode 100644
index 0000000000000000000000000000000000000000..87d86edc17b6ce37f0cdfddbd03e58d60e196d6e
GIT binary patch
literal 150
zc%17D@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryoCO|{#S9GG!XV7ZFl&wkP>{XE
z)7O>#0VlhVisFlsTppm1Y-UJAiF1B#Zfaf$0|+=5r6!i7rYMwWmSiZnd-?{X=%um)
m#d$nk978y+C;#~W-=2Z>AJe}(XCj}2G<drDxvX<aXaWGzX(f#S
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/ResizeObserver/resizeTestHelper.js
@@ -0,0 +1,153 @@
+/**
+ Source:
+ https://github.com/WICG/ResizeObserver/blob/master/test/resources/resizeTestHelper.js
+*/
+
+'use strict';
+
+/**
+ ResizeTestHelper is a framework to test ResizeObserver
+ notifications. Use it to make assertions about ResizeObserverEntries.
+ This framework is needed because ResizeObservations are
+ delivered asynchronously inside the event loop.
+
+ Features:
+ - can queue multiple notification steps in a test
+ - handles timeouts
+ - returns Promise that is fullfilled when test completes.
+ Use to chain tests (since parallel async ResizeObserver tests
+ would conflict if reusing same DOM elements).
+
+ Usage:
+
+ create ResizeTestHelper for every test.
+ Make assertions inside notify, timeout callbacks.
+ Start tests with helper.start()
+ Chain tests with Promises.
+ Counts animation frames, see startCountingRaf
+*/
+
+/*
+ @param name: test name
+ @param steps:
+ {
+ setup: function(ResizeObserver) {
+ // called at the beginning of the test step
+ // your observe/resize code goes here
+ },
+ notify: function(entries, observer) {
+ // ResizeObserver callback.
+ // Make assertions here.
+ // Return true if next step should start on the next event loop.
+ },
+ timeout: function() {
+ // Define this if your test expects to time out.
+ // If undefined, timeout is assert_unreached.
+ }
+ }
+*/
+function ResizeTestHelper(name, steps)
+{
+ this._name = name;
+ this._steps = steps || [];
+ this._stepIdx = -1;
+ this._harnessTest = null;
+ this._observer = new ResizeObserver(this._handleNotification.bind(this));
+ this._timeoutBind = this._handleTimeout.bind(this);
+ this._nextStepBind = this._nextStep.bind(this);
+}
+
+ResizeTestHelper.TIMEOUT = 100;
+
+ResizeTestHelper.prototype = {
+ get _currentStep() {
+ return this._steps[this._stepIdx];
+ },
+
+ _nextStep: function() {
+ if (++this._stepIdx == this._steps.length)
+ return this._done();
+ this._timeoutId = this._harnessTest.step_timeout(
+ this._timeoutBind, ResizeTestHelper.TIMEOUT);
+ try {
+ this._steps[this._stepIdx].setup(this._observer);
+ }
+ catch(err) {
+ this._harnessTest.step(() => {
+ assert_unreached("Caught a throw, possible syntax error");
+ });
+ }
+ },
+
+ _handleNotification: function(entries) {
+ if (this._timeoutId) {
+ window.clearTimeout(this._timeoutId);
+ delete this._timeoutId;
+ }
+ this._harnessTest.step(() => {
+ let rafDelay = this._currentStep.notify(entries, this._observer);
+ if (rafDelay)
+ window.requestAnimationFrame(this._nextStepBind);
+ else
+ this._nextStep();
+ });
+ },
+
+ _handleTimeout: function() {
+ delete this._timeoutId;
+ this._harnessTest.step(() => {
+ if (this._currentStep.timeout) {
+ this._currentStep.timeout();
+ }
+ else {
+ assert_unreached("Timed out waiting for notification. (" + ResizeTestHelper.TIMEOUT + "ms)");
+ }
+ this._nextStep();
+ });
+ },
+
+ _done: function() {
+ this._observer.disconnect();
+ delete this._observer;
+ this._harnessTest.done();
+ if (this._rafCountRequest) {
+ window.cancelAnimationFrame(this._rafCountRequest);
+ delete this._rafCountRequest;
+ }
+ window.requestAnimationFrame(() => { this._resolvePromise(); });
+ },
+
+ start: function() {
+ this._harnessTest = async_test(this._name);
+ this._harnessTest.step(() => {
+ assert_equals(this._stepIdx, -1, "start can only be called once");
+ this._nextStep();
+ });
+ return new Promise( (resolve, reject) => {
+ this._resolvePromise = resolve;
+ this._rejectPromise = reject;
+ });
+ },
+
+ get rafCount() {
+ if (!this._rafCountRequest)
+ throw "rAF count is not active";
+ return this._rafCount;
+ },
+
+ _incrementRaf: function() {
+ if (this._rafCountRequest) {
+ this._rafCount++;
+ this._rafCountRequest = window.requestAnimationFrame(this._incrementRafBind);
+ }
+ },
+
+ startCountingRaf: function() {
+ if (this._rafCountRequest)
+ window.cancelAnimationFrame(this._rafCountRequest);
+ if (!this._incrementRafBind)
+ this._incrementRafBind = this._incrementRaf.bind(this);
+ this._rafCount = 0;
+ this._rafCountRequest = window.requestAnimationFrame(this._incrementRafBind);
+ }
+}