-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Add test for wheel event groups #37445
Add test for wheel event groups #37445
Conversation
As stated in w3c/uievents#338 the WebKit failure in my local tests is due to a webdriver exception, but follows the expected behavior with manual tests. |
.scroll(40, 2, 0, 20, {origin: firstSpacer}) | ||
.scroll(40, 2, 0, 100, {origin: firstSpacer}) | ||
.pause(1) | ||
.scroll(40, 2, 0, 50, {origin: firstSpacer}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my understanding, firstSpacer
is now scrolled out after the previous .scroll
call. Does this call emulate user input in any browsers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this emulates what happens for several small wheel scrolls that start on firstSpacer
that happen in quick succession. I'll add a test that doesn't add an origin for additional coverage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test that does what this test did without an element as an origin. It intermittently fails on WebKit, but the behavior is always the same for a manual test.
assert_equals(second_spacer_wheel_event, false, "Wheel event should not be fired to the second spacer"); | ||
assert_equals(inner_wheel_event, false, "Wheel event should not be fired to inner div"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least under current UI Events spec, one of these should be true
if the last .scroll
call emulates a wheel operation on secondSpacer
or innerDiv
because both of them are in same scrollable element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also my understanding of the current spec. This is what I was trying to describe in w3c/uievents#338, but I'm not sure if I described it well. For both manual and emulated tests, the current spec behavior does not seem to happen on WebKit or Blink.
Note that a event sent to secondSpacer
when the scroll moves beyond the bounds of firstSpacer
would cause user scrolls to be interrupted in the case that secondSpacer
has a event listener that uses preventDefault. We get a steady stream of bug reports for this in the Gecko APZ component. So maybe it makes the most sense to fire the wheel event at the parent that contains both elements instead of firing it at the initial target and relying on the event bubbling up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay to reply, but I've still not reached the conclusion yet.
Could you rewrite these tests to collect Event.target
of wheel
events with window.addEventListener
into an array and compare each array item with what you expect? Then, what's expected here becomes easier to understand. I.e.,
let wheelEventTargets = [];
window.addEventListener("wheel", event => {
wheelEventTargets.push(event.target);
}, {passive: true});
...
function runTest() {
wheelEventTargets = [];
...
assert_equal(
document.getElementById("..."),
wheelEventTargets[0],
"..."
);
assert_equal(
document.getElementById("..."),
wheelEventTargets[1],
"..."
);
}
(I guess and assume that the number of wheel
events is not different between browsers in what this test does.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay to reply, but I've still not reached the conclusion yet.
No problem! This is a bit of a complex topic that (I think) doesn't currently follow the spec.
Could you rewrite these tests to collect Event.target of wheel events with window.addEventListener into an array and compare each array item with what you expect?
Thanks for the feedback! Yeah, that makes sense... I think I can rework the test to work like this. Some of the way the tests are architected is an artifact of me trying to figure out how non-firefox browsers handle wheel event group targetting.
2625a56
to
7876bd1
Compare
7876bd1
to
dbf4b63
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review! Hopefully this version makes it easier to reason about... if it doesn't, let me know and I can think about altering things to make it more readable.
I can also create a example for manual testing if it would help.
testInfo.scrollingElement.scrollTo({top: 0, left: 0, behavior: "instant"}); | ||
|
||
wheelEventTargetsEqual(testInfo.targetElement, | ||
"All wheel events in the group have the same element"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you rewrite these tests to collect Event.target of wheel events with window.addEventListener into an array and compare each array item with what you expect?
Went about doing this in a slightly different manner. All the wheel event targets for a given test should be in the same wheel event group, so they all should be the same. As a result, we don't need to check wheelEventTargets[0] == expectedTarget
, we can just iterate through all the wheel event targets we collected in the testcase and ensure they're the expected target.
targetElement: secondInnerSpacer, | ||
title: 'Wheel event groups beyond the origin bound have the same target', | ||
}, | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used a array of test info instead of separate test definitions to make it easier to reason about the test cases.
9bca6f9
to
ce7b93f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wanted to add a test for a moved element, but that turns out to be a bit more complicated and the tests get super flaky, so I'm not really sure what the correct behavior is.
"All wheel events in the group have the same target"); | ||
|
||
document.removeEventListener("wheel", onEventRemoveInitialTarget, {passive: true}); | ||
}, "Remove the initial wheel event target."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a simple test that removes the initial target on the first wheel event. Note that I assumed chromes behavior for this test because it was easier to test. I'm unsure if this is the right behavior.
ce7b93f
to
2dd2f45
Compare
Reorganized the tests and rewrote the removal/move initial target tests to greatly improve their reliability. All tests pass very reliably for chrome and firefox (with the bug 1168182 patch) for me on the main box I'm using to work on this. I'll try to run the tests on WebKit and maybe other OSes over the next few days. |
2dd2f45
to
9884b2b
Compare
9884b2b
to
9e28eb2
Compare
Added |
aad9b4d
to
18e23c3
Compare
CC: @smaug---- |
|
||
// The first wheel event should be targetted at the moved element. | ||
assert_equals(wheelEventTargets.shift(), initialTarget, | ||
"Initial wheel event is has the moved element as the target"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"is has"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
3271944
to
2effcbd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review! Added new test that exercises the display: none
case.
|
||
// The first wheel event should be targetted at the moved element. | ||
assert_equals(wheelEventTargets.shift(), initialTarget, | ||
"Initial wheel event is has the moved element as the target"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
wheelEventTargets.forEach((wheelEventTarget) => { | ||
assert_not_equals(wheelEventTarget, initialTarget, | ||
"All following wheel events are not targetting the removed element"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that browser engines do different things in the event target mutation test cases. E.g. Gecko and WebKit will essentially fallback to the non wheel event groups event target after the original event target is mutated in some way, while Blink will only retarget once. I greatly weakened this assertion, so that all engines should pass. We might want to circle back at some point once there is some sort of consensus.
2effcbd
to
69a7b66
Compare
e.target.style.height = '10px'; | ||
} | ||
} | ||
window.addEventListener("wheel", resizeInitialElement, {passive: true}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder, passive
value could change the behavior due to optimization in some browsers. Did you check the false
case?
Could be nicer to check both passive: true
and passive: false
cases in variants.
scrollY: 2, | ||
scrollingElement: document.scrollingElement, | ||
targetElement: firstRootSpacer, | ||
title: 'Wheel events are grouped and are not targetted at following elements.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: using "should" or "shouldn't" make the expectation clearer for everybody.
// Wait some extra time to ensure nothing from the prior test impacts this one. | ||
// At a minimum this should be greater than 500ms to ensure that the wheel events | ||
// in this test are in a new wheel event group | ||
await new Promise(resolve => step_timeout(resolve, 1000)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really required in some browsers? It's odd to work a wheel transaction across browsing contexts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was also confused by this. Spent some time investigating this and the issue was partially solved by using variants. It turns out these tests also need to wait for the compositor to be ready waitForCompositorReady()
.
wheelEventTargets.forEach((wheelEventTarget) => { | ||
assert_equals(wheelEventTarget, testInfo.targetElement, | ||
"All wheel events in the group have the same target"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unclear which index's result is wrong. Please update the assertion comment to let developers know the failure point.
|
||
await waitForCompositorCommit(); | ||
|
||
wheelEventTargets = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't you define the variable at this line?
function runTest() { | ||
promise_test(async (t) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder, if you do:
promise_test(async t => {
await new Promise(resolve => addEventListener("load", resolve, {once:true});
...
Then, you can reduce one indent level of the test body.
wheelEventTargets.forEach((wheelEventTarget) => { | ||
assert_equals(wheelEventTarget, firstRootSpacer, | ||
"All following wheel events in the group have the same target"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto, please update the assertion message to let developers know which index failed.
wheelEventTargets.forEach((wheelEventTarget) => { | ||
assert_not_equals(wheelEventTarget, initialTarget, | ||
"All following wheel events are not targetting the moved element"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto please change the assertion message for each.
assert_not_equals(wheelEventTarget, initialTarget, | ||
"All following wheel events are not targetting the removed element"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
assert_equals(wheelEventTarget, initialTarget, | ||
"All wheel events should target the initial element"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto update the assertion message for each.
await waitForAnimationEnd(() => { return document.scrollingElement.scrollTop; }); | ||
await waitForCompositorCommit(); | ||
|
||
wheelEventTargets.forEach((wheelEventTarget) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder, scroll top should be checked whether it's still 0
or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably worthwhile
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to put all the filed under tentative/ just because there is no spec for this. But other than that looks good
598c501
to
eb993ee
Compare
Renamed all tests to |
dom/events/scrolling/wheel-event-transactions-basic.tentative.html
Outdated
Show resolved
Hide resolved
dom/events/scrolling/wheel-event-transactions-multiple-action-chains.tentative.html
Outdated
Show resolved
Hide resolved
<head> | ||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please always add <meta charset="utf-8">
to skip maybe expensive auto-detection of the browsers.
And shouldn't this test have <meta name="timeout" content="long">
for avoiding unexpected timeout during the test?
<head> | ||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
<head> | ||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
<head> | ||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
<head> | ||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
dom/events/scrolling/wheel-event-transactions-target-display-change.tentative.html
Outdated
Show resolved
Hide resolved
dom/events/scrolling/wheel-event-transactions-target-removal.tentative.html
Outdated
Show resolved
Hide resolved
dom/events/scrolling/wheel-event-transactions-target-removal.tentative.html
Outdated
Show resolved
Hide resolved
Hi @dlrobertson. Do you plan to update this PR? It might be nice to have those tests for the upcoming work for widget level events in Marionette. Thanks. |
2691a25
to
b4d5721
Compare
@whimboo Updated and resolved all comments. Thanks for the ping! |
Re tentative, now there is a spec since w3c/uievents#338 was merged. |
👍 Thanks for the note about this. Forgot that I'd need to update this. Also it looks like chrome no longer passes the tests reliably. I'll have to dig into the tests to figure out what changed. |
@zcorpan Actually to what extent should I rename things? For example, AFAIK it isn't explicitly specified what should happen when the initial target of the wheel transaction is removed, but I have a test for that in this PR. |
Keep |
Hi @dlrobertson. Do you have an update for this PR? |
b4d5721
to
93c1d44
Compare
@masayuki-nakano could you please take another look. It looks like that after the last push it was missed to request review again. Thanks. |
await waitForCompositorCommit(); | ||
|
||
initialTarget.addEventListener("wheel", () => { | ||
assert_true(false, "wheel event should never be fired after the target is removed") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this test. Looks like that you add this event listener after all events are fired. Don't you need to do this in the first wheel
event listener, removeInitialElement
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Updated to set this in the first wheel event listener.
93c1d44
to
7c500ba
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, looks fine although I've not checked actual changes strictly because it seems that it's impossible to get the diff from previous version :-(
Well, I'd be happy if you'd add <meta charset="utf-8">
(to skip running encode detection) to all tests for quicker run in CI, but up to you.
Awesome! I'll update it asap |
Add tests for groups of wheel events.
7c500ba
to
8b9432a
Compare
Updated! |
@dlrobertson I assume that this PR doesn't need another review, so what is the merge blocked on? |
Merged! Just wasn't sure if I was supposed to merge it, or if I was supposed to wait for a reviewer to merge it. Thanks for the ping! |
Add tests for groups of wheel events.