Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests for ResizeObserver #6878

Merged
merged 4 commits into from
Oct 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lint.whitelist
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ SET TIMEOUT: payment-request/allowpaymentrequest/setting-allowpaymentrequest-tim
SET TIMEOUT: payment-request/payment-request-response-id.html
SET TIMEOUT: pointerevents/pointerevent_support.js
SET TIMEOUT: preload/single-download-preload.html
SET TIMEOUT: resize-observer/resources/iframe.html
SET TIMEOUT: resource-timing/resource-timing.js
SET TIMEOUT: screen-orientation/lock-bad-argument.html
SET TIMEOUT: screen-orientation/onchange-event.html
Expand Down
2 changes: 2 additions & 0 deletions resize-observer/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@atotic
@dholbert
259 changes: 259 additions & 0 deletions resize-observer/eventloop.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/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 => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err will be bound to an event, and in any case it's not used, so _ or () would be more clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do.

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(helper.rafCount, 1, "new loop");
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;
test(_ => {
assert_own_property(window, "ResizeObserver");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guard is a bit curious, why is it needed? new ResizeTestHelper will throw an exception anyway because it tried to do new ResizeOberserver. Tests shouldn't pass if the feature isn't implemented, but the explicit guard for it is a bit unusual.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Without the guard, tests used to timeout because ResizeTestHelper would fail in constructor before async tests were created. I can fix this.

guard = async_test('guard');
}, "ResizeObserver implemented")

test0()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want the tests to be run in sequence, have you tried promise_test? They are run one after another by default. Is it that it's pointless to run the following tests if the first does not pass?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pointer. I was unaware that promise_tests are sequential.

My existing framework works well with RO callback pattern. It is not immediately obvious to me how to map chained RO callbacks into promise_test pattern. I'll think about it....

.then(() => { return test1(); })
.then(() => { return test2(); })
.then(() => { guard.done(); });

</script>

Loading