Open tarjei opened 11 years ago
Well, the only difference between your code and the driver is that your code does not trigger the events: https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2Driver.php#L829
Interesting. Then the question becomes, why did my code work and the code that also triggers the events not?
@everzet do we really need to emulate the D&D events ? We are using the selenium API to trigger all actions there, so it should handle them, no ?
@stof Mink has and always had 2 responsibilities:
If all of the emulators emulate events, but Selenium doesn't, then it's a good idea for Mink to do it.
The default behaviour of this function doesn't work with already binded drag/drop elements. (using jquery ui droppable / draggable). Replacing the function with the one mentioned above works fine.
If this function can't be changed then are we able to get another function added with the following parts removed?:
$script = <<<JS
(function (element) {
var event = document.createEvent("HTMLEvents");
event.initEvent("dragstart", true, true);
event.dataTransfer = {};
element.dispatchEvent(event);
}({{ELEMENT}}));
JS;
$this->withSyn()->executeJsOnXpath($sourceXpath, $script);
and:
$script = <<<JS
(function (element) {
var event = document.createEvent("HTMLEvents");
event.initEvent("drop", true, true);
event.dataTransfer = {};
element.dispatchEvent(event);
}({{ELEMENT}}));
JS;
$this->withSyn()->executeJsOnXpath($destinationXpath, $script);
Let me know if this would be accepted and I'll submit a pull request.
Thanks.
@allmyitjason , can you please send PR anyway? Without it I need to jump back and forth in the code just to see what has been changed compared to current implementation.
@tarjei: Just to clarify: with current drag-n-drop implementation the drag works fine, but respective events aren't fired at all? Drag-n-drop tests pass right now, because they are using jQueryUI draggable/droppable components to detect if a drag-n-drop operation succeeded. jQuery does pretty well in overcoming browser incompatibilities and firing correct events at correct times. There might be an issue however in cross-browser even firing code, that is used.
Improved code version is here: https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2Driver.php#L684-L701 Original code version is here: https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2Driver.php#L895-L902
As you can see if document.createEvent
is missing in used browser, then no events are fired. Can you please try adding missing parts of cross-browser event triggering code to dragTo
method and see if it helps you. And if it does I would be glad to see an PR from you.
@allmyitjason:
In your PR you provide alternative implementation of dragTo
function. What is not working in current dragTo
implementation for you? Are it events not being fired? If so, then please read beginning of this message, for more info.
hi @aik099
Yea drop and drop events aren't being fired. I'll try with the updated js and will let you know if it resolves my issue.
@allmyitjason , please also update your PR if it does help you.
@aik099:
I have just been testing the changes with the new js code and I still see the same result. The events aren't fired and text between the two elements are simply being highlighted. Same result is experienced in IE 9,10 / Firefox 23.
Using the above pull request code, the drag and drop works as expected in IE and FF.
This was the JS I added to https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2Driver.php#L894
$script = <<<JS
(function (element, eventName) {
var event;
if (document.createEvent) {
event = document.createEvent("HTMLEvents");
event.initEvent(eventName, true, true);
} else {
event = document.createEventObject();
event.eventType = eventName;
}
event.eventName = eventName;
if (document.createEvent) {
element.dispatchEvent(event);
} else {
element.fireEvent("on" + event.eventType, event);
}
}({{ELEMENT}}, 'dragstart'));
JS;
$script = <<<JS
(function (element, eventName) {
var event;
if (document.createEvent) {
event = document.createEvent("HTMLEvents");
event.initEvent(eventName, true, true);
} else {
event = document.createEventObject();
event.eventType = eventName;
}
event.eventName = eventName;
if (document.createEvent) {
element.dispatchEvent(event);
} else {
element.fireEvent("on" + event.eventType, event);
}
}({{ELEMENT}}, 'drop'));
JS;
Are you using jQuery to bind event listeners to drag events? If nope, then I'm strongly recommending that.
Also can you run tests locally for MinkSelenium2Driver? These tests are using jQueryUI/jQuery (as I've mentioned before), to verify, that drop has happened. They pass for me on Firefox 23 without problems.
I'm using the jQuery UI draggable for the drag element. And jQuery Fullcalendar plugin for the drop event.
Drag
$('#external-events div.external-event').each(function() {
// it doesn't need to have a start or end
var eventObject = {
title: $.trim($(this).text()) // use the element's text as the event title
};
// store the Event Object in the DOM element so we can get to it later
$(this).data('eventObject', eventObject);
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
Drop
$('#cal').fullCalendar({
droppable: true,
drop: function(date, allDay) {
alert('drop');
}
});
I'll have a look at the tests, but I not sure how to run them? So far been using Mink simply through codeception.
To run tests do the following:
About your code: And what is test code, that you're performing? I guess it's clicking on the input to open a calendar, but I can't guess what exactly are you dragging there.
I have ran the tests and they did pass.
However I still feel this function should be added, as this is all an end user would be doing. Click on an element, drag and un-click. This is the exact function that I wan't to be able to test without having extra javascript running and possibly conflicting with any listening methods.
My current tests are simply clicking on an element and dropping on a day in the calendar. This is working fine in the browser if I do it myself, and is also working fine with the code in the above pull request.
I'm not too familiar with JavaScript listening methods, but somehow that extra JavaScript is conflicting.
The drag and drop code is all from the jQuery fullcalendar plugin (http://arshaw.com/fullcalendar/docs/dropping/drop/)
I have ran the tests and they did pass.
That is very strange, because tests are testing, that something is dropped onto designed area. That's what you're doing too.
However I still feel this function should be added, as this is all an end user would be doing.
Existing function obviously don't work in your case and we need to find out why, rather than adding another function that partially duplicates current dragTo
method.
I'm not too familiar with JavaScript listening methods, but somehow that extra JavaScript is conflicting.
Fully agree on that. Here are full info about drag-n-drop events: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_and_Drop . Now we need to:
dragTo
implementation and see which events are fineddragTo
implementation and see which events are finedIn worst case Selenium would fire events on it's own and manual event firing done in current dragTo
implementation might confuse other JS code (that fullcalendar in this case).
@tarjei or @allmyitjason , ready for a PR creation as discussed in last comment?
@tarjei, @allmyitjason, based on @stof comment (see https://github.com/Behat/MinkSelenium2Driver/issues/51#issuecomment-18337179) I can conclude, that removing manual JavaScript event triggering can solve the problem. Then the only thing that needs to be tested is whatever Selenium does trigger proper JavaScript events in correct order on it's own.
Preferably we need a test in JavaScriptDriverTest
class to verify that as well. Then we can safely remove Syn
usage from dragTo
method.
It would be helpful to know what OS people are testing on.
As a bit of background: Firefox+Webdriver on Windows defaults to using native events. Firefox+Webdriver on Linux defaults to using emulation. (On Linux, we found it didn't generate dragstart/drop events, hence 274ecf6c9028f642766ec734d8ecfce07343a5b6.)
@robocoder , is there any way to force native event usage?
Yes, it can be forced, but I believe we should leave it "as is" because native events is not fully supported across all window managers:
That said, I agree with determining the sequence of events to be triggered and adding tests.
Does these native events
mean, that even onclick
won't be triggered natively when ->click()
is called on the WebElement, if Selenium server is launched on Linux?
Or native events
are only HTML5 events?
I haven't looked at the code, so I don't know which events are emulated vs native. For the time being, I think we'll have to find a way to support both:
As we develop features in the Firefox Driver, we expose the ability to use them. For example, until we feel native events are stable on Firefox for Linux, they are disabled by default.
Without a way to detecting which events are fired natively we can't safely use Syn, because there is a risk, that event can be fired twice (native and via syn), which indeed may result in some weird results.
We typically run Firefox+Linux with xvfb and without a window manager. Running Selenium 2.40, even if I force nativeEvents=true in the desired/required capabilities request, the driver response says nativeEvents=false. So while we can specify that we want native events, the driver appears to have the discretion to ignore it -- which is disconcerting given that I also tried with "required" capabilities.
@robocoder, how do you get the nativeEvents
setting back from WebDriver?
So we can get that setting and based on actual native event support decide whatever to invoke Syn code or not.
I could not get my test to work when using the dragTo implementation in the Selenium2Driver, but this worked:
Most of the code is just a cut and paste from an example I found in a comment on the internet(I cannot remember where), but it is fairly straight forward.