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

Add test for wheel event groups #37445

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dlrobertson
Copy link
Member

Add tests for groups of wheel events.

@dlrobertson
Copy link
Member Author

Test Blink WebKit Gecko
Wheel events are grouped and are not sent to a child element
Wheel events are not bound to a scroll frame
Wheel event groups beyond the origin bound have the same target

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})
Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Member Author

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.

Comment on lines 136 to 206
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");
Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

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.)

Copy link
Member Author

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.

Copy link
Member Author

@dlrobertson dlrobertson left a 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");
Copy link
Member Author

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',
},
];
Copy link
Member Author

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.

@dlrobertson dlrobertson force-pushed the wheel-event-groups branch 2 times, most recently from 9bca6f9 to ce7b93f Compare January 18, 2023 02:20
Copy link
Member Author

@dlrobertson dlrobertson left a 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.");
Copy link
Member Author

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.

@dlrobertson
Copy link
Member Author

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.

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.

@dlrobertson
Copy link
Member Author

dlrobertson commented Jan 27, 2023

Added dom/events/scrolling/wheel-event-groups-target-elements.html which ensures the text is not the event target for the wheel event group. Blink handles this correctly, but I'm currently unable to test on WebKit. This is the last failing test (that I know of 😆) with D163484 for Gecko.

@dlrobertson dlrobertson force-pushed the wheel-event-groups branch 2 times, most recently from aad9b4d to 18e23c3 Compare January 27, 2023 18:39
@dlrobertson
Copy link
Member Author

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");
Copy link
Contributor

Choose a reason for hiding this comment

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

"is has"

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks

@dlrobertson dlrobertson force-pushed the wheel-event-groups branch 2 times, most recently from 3271944 to 2effcbd Compare February 8, 2023 13:47
Copy link
Member Author

@dlrobertson dlrobertson left a 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");
Copy link
Member Author

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");
});
Copy link
Member Author

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.

e.target.style.height = '10px';
}
}
window.addEventListener("wheel", resizeInitialElement, {passive: true});
Copy link
Contributor

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.',
Copy link
Contributor

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));
Copy link
Contributor

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.

Copy link
Member Author

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().

Comment on lines 132 to 135
wheelEventTargets.forEach((wheelEventTarget) => {
assert_equals(wheelEventTarget, testInfo.targetElement,
"All wheel events in the group have the same target");
});
Copy link
Contributor

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 = [];
Copy link
Contributor

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?

Comment on lines 37 to 38
function runTest() {
promise_test(async (t) => {
Copy link
Contributor

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.

Comment on lines 71 to 74
wheelEventTargets.forEach((wheelEventTarget) => {
assert_equals(wheelEventTarget, firstRootSpacer,
"All following wheel events in the group have the same target");
});
Copy link
Contributor

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.

Comment on lines 81 to 84
wheelEventTargets.forEach((wheelEventTarget) => {
assert_not_equals(wheelEventTarget, initialTarget,
"All following wheel events are not targetting the moved element");
});
Copy link
Contributor

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.

Comment on lines 82 to 83
assert_not_equals(wheelEventTarget, initialTarget,
"All following wheel events are not targetting the removed element");
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 78 to 79
assert_equals(wheelEventTarget, initialTarget,
"All wheel events should target the initial element");
Copy link
Contributor

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.

Comment on lines 74 to 77
await waitForAnimationEnd(() => { return document.scrollingElement.scrollTop; });
await waitForCompositorCommit();

wheelEventTargets.forEach((wheelEventTarget) => {
Copy link
Contributor

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably worthwhile

@dlrobertson
Copy link
Member Author

This bug has been fixed two months ago. I've re-triggered the tests so hopefully they should all pass now.

Thanks for re-triggering the tests! Just re-ran these tests locally on chrome beta and m-c (with and without the bug 1821733 patchset). Tests pass reliably for me, but I'd be interested if others see the same results.

@dlrobertson is there anything else this PR would need?

I think the tests accurately describe browsers current behavior and are stable in my local testing. @masayuki-nakano is there anything else you think this PR needs?

@dlrobertson
Copy link
Member Author

Added dom/events/scrolling/wheel-event-groups-multiple-action-chains.html. It is largely focused on testing that the webdriver functions like we'd hope. Tested on both chrome and mozilla-central (fails on current m-c and pasess with bug 1821733 patches). If this test should exist somewhere else, I'm happy to move it... it has enough in common with the other wheel-event-group-* tests that I placed it with the rest of them.

@whimboo
Copy link
Contributor

whimboo commented May 23, 2023

@dlrobertson thanks for adding the test! It would be good if you could retrigger the CI checks (at least those for Firefox) once the fix from bug 1821733 made it into the next Nightly build.

@dlrobertson
Copy link
Member Author

@dlrobertson thanks for adding the test! It would be good if you could retrigger the CI checks (at least those for Firefox) once the fix from bug 1821733 made it into the next Nightly build.

@whimboo good point. Re-triggered the CI checks and the check wpt-firefox-nightly-results seems to pass now.

@whimboo
Copy link
Contributor

whimboo commented May 23, 2023

Great. So I think that @masayuki-nakano could have another look now.

@dlrobertson
Copy link
Member Author

@smaug---- or @masayuki-nakano PTAL, I'd like to get more testing coverage for this, since this behavior is now the default in firefox (riding the trains with bug 1823700)). If this doesn't look like it is ready to be merged soon-ish, I can pull this into the mozilla specific wpts for now.

@whimboo whimboo requested a review from smaug---- June 27, 2023 05:26
@smaug----
Copy link
Contributor

smaug---- commented Jun 27, 2023

I think I'd still prefer to call this thing something else than "event group". It is more like a wheel transaction or some such.

And sorry being late here. Getting the review through bugzilla would be faster in my case, even for public wpts
(not only because the reviewing tools we use are quite a bit nicer than github).

But I'll take a look here.

@dlrobertson
Copy link
Member Author

And sorry being late here. Getting the review through bugzilla would be faster in my case, even for public wpts
(not only because the reviewing tools we use are quite a bit nicer than github).

No problem, thanks for the feedback!

Copy link
Contributor

@smaug---- smaug---- left a comment

Choose a reason for hiding this comment

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

The tests are a bit hard to review since there is really no comment what is the overall thing they are trying to test. Could you add some comments?

scrollY: 2,
scrollingElement: document.scrollingElement,
targetElement: firstRootSpacer,
title: 'Wheel events should be grouped and should not targetted following elements.',
Copy link
Contributor

Choose a reason for hiding this comment

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

This talk about grouping is a bit unusual. In pointer events spec events may be captured to a one particular target. Could this all use similar terminology, something like wheel event capturing?

And then elsewhere there is also the concept of transaction used for this thing.

And there is also pointer lock. Is this whole thing some sort of implicit wheel event lock?


let variants = [
{
key: 'target-basic',
Copy link
Contributor

Choose a reason for hiding this comment

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

What does key refer to here?

Copy link
Contributor

Choose a reason for hiding this comment

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

ahaa, it is for some helper function.


<script>

let variants = [
Copy link
Contributor

Choose a reason for hiding this comment

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

I wish there was some generic comment on top of the script explaining what is being tested. This is not very easy test to read when one needs to find all the relevant helper methods in other script files etc.

@whimboo
Copy link
Contributor

whimboo commented Aug 21, 2023

@smaug---- as it looks like this PR is waiting for another round of review. Could you please have a look?

Copy link
Contributor

@smaug---- smaug---- left a 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

@dlrobertson
Copy link
Member Author

We might want to put all the filed under tentative/ just because there is no spec for this. But other than that looks good

Renamed all tests to <test-name>.tentative.html. Good suggestion

Comment on lines 3 to 6
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
Copy link
Contributor

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?

Comment on lines 3 to 6
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 3 to 6
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 3 to 6
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 3 to 6
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

@whimboo
Copy link
Contributor

whimboo commented Nov 28, 2023

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.

@dlrobertson dlrobertson force-pushed the wheel-event-groups branch 2 times, most recently from 8388187 to 2691a25 Compare December 4, 2023 17:22
Add tests for groups of wheel events.
@dlrobertson
Copy link
Member Author

@whimboo Updated and resolved all comments. Thanks for the ping!

@zcorpan
Copy link
Member

zcorpan commented Dec 5, 2023

Re tentative, now there is a spec since w3c/uievents#338 was merged.

@dlrobertson
Copy link
Member Author

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.

@dlrobertson
Copy link
Member Author

@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.

@zcorpan
Copy link
Member

zcorpan commented Dec 6, 2023

Keep tentative for any tests where there's no specified correct behavior, and file a spec issue. Bonus points for pointing to the spec issue in the test (with <link rel=help>).

@whimboo
Copy link
Contributor

whimboo commented Apr 9, 2024

Hi @dlrobertson. Do you have an update for this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants