-
Notifications
You must be signed in to change notification settings - Fork 163
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
Improve drag-and-drop JS event emulation on Selenium 3 #408
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #408 +/- ##
============================================
- Coverage 86.21% 86.07% -0.14%
+ Complexity 185 184 -1
============================================
Files 1 1
Lines 515 510 -5
============================================
- Hits 444 439 -5
Misses 71 71 ☔ View full report in Codecov by Sentry. |
I agree. We'll use the new event invocation code and see how it will perform.
Looking at the invoked events (proposed version in this PR) I've noticed that 99.9% matches (except for It also said, that for cases, when drag-and-dropping onto itself same set of events is called but on the same element. This is where an approach with the You're proposition definitely looks superior compared with the current (in the P.S. I've also updated your PR description (see |
While investigating the error, I noticed that we trigger
Thanks, that made sense. 👍
Either we have to "live with it" (in selenium 3, I could make a condition to keep previous behaviour), OR now that I think about it, maybe we should switch to javascript events for that too? That should also solve your question about coverage. What do you think? |
Just for testing, I've added the following code to the function getStandardEventNames(element) {
const eventNames = [];
for (const prop in element) {
if (!prop.startsWith("on")) {
continue;
}
const eventName = prop.slice(2);
try {
new Event(eventName);
eventNames.push(eventName);
} catch {
// if an error is thrown, it's not a valid event name
}
}
return eventNames;
}
function monitorStandardEvents(element) {
for (const eventName of getStandardEventNames(element)) {
element.addEventListener(eventName, event => console.log(event.target.id ?? 'unknown', eventName));
}
}
setInterval(() => console.log('-------------------------------------'), 5000);
// ^-- since we trigger a lot of unrelated events (e.g. while moving over element before or after drag and drop, I use this line to mark the beginning and the end of the manual test.
monitorStandardEvents(document.getElementById('draggable'));
monitorStandardEvents(document.getElementById('draggable2'));
monitorStandardEvents(document.getElementById('droppable'));
document.getElementById('draggable').setAttribure('draggable', 'true');
document.getElementById('draggable2').setAttribure('draggable', 'true'); I also had to comment out the After dragging the smaller & darker grey box to the right-most light grey box, I got the following event log:
That is effectively the sequence of events firefox generates. |
What error investigation are you talking about? You've mentioned drag-and-drop failure (in PR description), but which one? The only drag-related failure from recent times was with drag-onto-itself test and was caused by an outdated Firefox version.
There are no IFs in the driver code to perform different drag-n-drop behavior based on the Selenum Server version. The inconsistency in the build configuration (see below answer) might have resulted in that assumption. Please keep improved drag-and-drop behavior consistent (always on) regardless of the used Selenium Server version.
I've figured out why there was no coverage. The test, that covers it is ignored in Selenium 3+Firefox, but runs on Selenum 2+Firefox. Since I'm testing only on Firefox I got this line uncovered. Probably need to update build config to test Selenium2/3 on Chome at least on 1 PHP version. I've added #409 about this. |
Right, that's what I meant. Interestingly, I couldn't get the test to pass (without my changes) on any Firefox version. I checked these two tests:
Results:
I have no idea why the behaviour is so different compared to GitHub actions.
Yes, I know. What I meant was to have a condition for Selenium 3 to avoid the clicking problem, but now I suspect it would work anyway since I got the same results on Selenium 2.
In that case, we would need to also trigger the mouse/pointer events from javascript. |
For local testing, I launch Selenium Server's JAR file and let it control the browsers, which I have installed locally (Chrome/Firefox). I don't use Docker Selenium images at all. None of the drag-related tests fail in Firefox for me. Maybe they fail only in some Firefox versions due to geckodriver issues and exactly that version is used in the Selenium Docker image. Debugging the cause of failure you have locally (via Docker) might reveal some interesting bugs.
Sure. Please do so. Hopefully that won't break jQuery drag-and-drop JS used by test suite. |
@aik099 what worries me now is that triggering mouse/pointer events is not so easy: I have some trouble figuring out the various positions normally available with these events. I suspect that when I trigger such events fields like x/y, clientX/Y, layerX/Y, screenX/Y, pageX/Y are either undefined or zeroed out. 😞 |
@uuf6429 , are above-mentioned event properties correctly populated when Selenium Server 3 is triggering these JS events internally as part of the Actions API calls? |
@aik As far as I know, Selenium 3 triggers those events through browser API, so I'm pretty sure those fields would be set. In any case, my last commit avoids that problem and somehow fixes the tests (locally, Se3+Chrome was failing before this PR). It's not entirely clear why...maybe it was more of a problem that the old code didn't trigger the correct sequence of D&D events? 🤔 |
Could please use long array syntax ( If you'd like, you can do large scale replace and maybe add phpstan rule to check this. |
@aik099 small reminder; I don't have write access to this repo. |
@uuf6429 , if you need my assistance with anything (e.g. review the PR or merge it), then I'm here to help. Just let me know. In this particular case I should have guessed myself that PR review is requested (because I've asked one thing and you've made one commit), but better to be explicit about your expectations to avoid misunderstandings later on. |
Merging, thanks @uuf6429 . |
@aik099 I just realised that the problem mentioned in the description ( I've figured why and what happened:
In short: this PR improves the D&D event flow, but it doesn't fix the original problem. 😞 At least we now know it's a problem with Firefox. I'll work on a new and separate PR. |
@aik099 hmm, I've found that we are actually supposed to skip the You can ignore my last two comments. Edit: I've figured out why that test was being executed; I missed setting up the SELENIUM_VERSION env var so that test was executed since we skip it only on selenium 2. |
I'm not fully aware of the flow of running this driver with Selenium3, but this drag and drop failure seemed very consistent to me, so I tried solving it.
Investigation
I noticed the following:
luckily, I can just trigger click in this case, which pretty much is the same operation (since the element is not being moved - this is the selenium 3 fix.In terms of code
Drag Events before:
dragstart
on source elementdrop
on target elementDrag Events after (which I think should be more realistic):
dragstart
on source elementdragover
on target elementdrop
on target elementdragend
on source elementDriver Mouse Events before:
button down
sourceElement !== targetElement
mousemove
button up
Driver Mouse Events after:
move
button down
move
button up
I also switched to more modern javascript event construction. Not sure if we should worry about old browsers, like say MSIE. Compatibility chart: https://caniuse.com/mdn-api_dragevent_dragevent
Note that sticking to the old code has the opposite problem - it uses deprecated functionality that might break in new browsers - if we absolutely want to keep maximum compatibility, I suppose we could use a fallback ("if createEvent exists use it, else use constructor").
Live testing: https://jsfiddle.net/0L6kthxv/1/