How to simulate a drag and drop action in protractor?
Asked Answered
M

8

11

I have a double slider and I'd like to test that it's operable and return's the right data. The slider has a min and a max handler, it also has some "breakpoints that I can hook to. "

What I want to simulate is

  • a touchStart of the ".handler-max" element
  • a move of the thumb over the element with class ".step-3"
  • a touchEnd of the ".handler-max" element

while I found how to trigger a touchStart and a touchEnd event. I'm clueless on how to simulate the move of the thumb

browser.executeScript('angular.element(arguments[0]).triggerHandler("touchstart");', filterHandler);
// <--- move event????
browser.executeScript('angular.element(arguments[0]).triggerHandler("touchend");', filterHandler);

P.S. The scope of this question is an integration test that tests if what happens to the application when a user interact's with a double slider directive is the desirable result.

Mllly answered 4/9, 2014 at 11:39 Comment(0)
P
21

elem = Element you want to move;

target = Element where you want to drop elem;

For WebdriverJS:-

browser.driver.actions().dragAndDrop(elem,target).mouseUp().perform();

For Protractor:-

browser.actions().dragAndDrop(elem,target).mouseUp().perform();
Predecease answered 20/11, 2015 at 22:1 Comment(1)
I'm guessing (Protractor) appended is a typo!Ell
B
10

This is quite straightforward nowadays:

browser.actions().dragAndDrop(elem, target).perform();

Where dragAndDrop behind the scenes is mouseDown + mouseMove + mouseUp:

/**
 * Convenience function for performing a "drag and drop" manuever. The target
 * element may be moved to the location of another element, or by an offset (in
 * pixels).
 * @param {!webdriver.WebElement} element The element to drag.
 * @param {(!webdriver.WebElement|{x: number, y: number})} location The
 *     location to drag to, either as another WebElement or an offset in pixels.
 * @return {!webdriver.ActionSequence} A self reference.
 */
webdriver.ActionSequence.prototype.dragAndDrop = function(element, location) {
  return this.mouseDown(element).mouseMove(location).mouseUp();
};
But answered 11/12, 2015 at 15:46 Comment(2)
awesome, I would vote up if it was verified by someone. Quite hard for me because I'm not working front end anymore and I'm not set up with selenium atmMllly
@AlexandrosSpyropoulos sure, I can verify it is working for me :)But
M
4

Ok playing around I found that I there are better ways. probably the sources I was looking before were outdated. The following script will do the trick very clean and easy...

it( 'step : 6 : select star rating min === 1 and max === 2' , function (done) {

    driver.actions()
        .mouseDown(element(by.css('.filter-editorial-rating .ngrs-handle-max')))
        .mouseMove(element(by.css('.filter-editorial-rating .step-2')))
        .mouseUp()
        .perform();


element( by.css( '.results-indicator' ) ).getText()
    .then( function ( text ) {
        resultsB = parseInt (text.split(" ")[0]);
        expect( resultsB ).toBeLessThan( resultsA );                            
        done();
    });
});

you can get driver like this ...

browser.get(url);
var driver = browser.driver;

Cheers

Mllly answered 4/9, 2014 at 14:8 Comment(0)
N
1
        var plot0 = ptor.element(protractor.By.id(''));

        ptor.driver.actions()

        .dragAndDrop(plot0, {x: 200, y: 100})

        .mouseMove(plot0, {x: 200, y: 100}) // 200px from left, 200 px from top of plot0

        .mouseDown()

        .mouseMove({x: 600, y: 0}) // 600px to the right of current location

        .perform();

This works for me guys. My scenario is drag a pop up dialog box which does not have a target element.

Narceine answered 21/3, 2017 at 16:11 Comment(1)
Thanks ! Worked like a charm !Scarlettscarp
B
0

I'm in a middle of converting automation project from the use of SELENIUM_PROMISE_MANAGER to the use of JS native async/await. Previously, I've been utilizing the way described by user3800138 ^, however it didn't work for me anymore as well as all other approaches described here. What did work for me is chaining every single action through then method like this

dragAndDrop: ( $element, $destination ) =>
    browser
        .actions()
        .mouseMove( $element )
        .perform()
        .then( () => browser
            .actions()
            .mouseDown( $element )
            .perform() )
        .then( () => browser
            .actions()
            .mouseMove( $destination )
            .perform() )
        .then( () => browser
            .actions()
            .mouseUp()
            .perform())

and then calling it like this await dragAndDrop($leftSlider, $lastDateTitle);

Or the same using await will look like this

dragAndDrop: async( $element, $destination ) => {
    await browser.actions().mouseMove( $element ).perform();
    await browser.actions().mouseDown( $element ).perform();
    await browser.actions().mouseMove( $destination ).perform();
    await browser.actions().mouseUp().perform();
}

I know it's a bit bulky, but I couldn't find a better option

Buckingham answered 27/9, 2018 at 0:8 Comment(0)
M
0

As someone already mentioned (but is a bit outdated) you can also move the slider to any direction by just providing x,y coordinates:

browser.actions().dragAndDrop(sliderElement, {x: 10}).perform()

browser.actions().dragAndDrop(sliderElement, {x: -10}).perform()

browser.actions().dragAndDrop(modalElement, {x: 100, y:100}).perform()
Marylnmarylou answered 18/11, 2019 at 11:28 Comment(0)
M
0
import {code as dragAndDrop} from 'html-dnd';

it("dragAndDropInCanvas",function(){
   var xy= (element(by.className('row ng-star-inserted')),{x: 300, y: 300});
   var source_1 = element(by.xpath('//*[@id="sidebarnav"]/li[3]/ul/li[1]'))
   var target = element(by.id('mainCanvas'));
   browser.sleep(1000);
   browser.executeScript(dragAndDrop, source_1, target);
   browser.sleep(2000);
   element(by.className('col-4 ng-star-inserted')).click()
   browser.sleep(5000)
  })
Minnich answered 5/11, 2020 at 5:30 Comment(0)
T
-2

With problems like this one, I isolate the business code (which actually does something useful with the drag & drop events) from the UI. That way, I can make sure the drag-start code will fill out the data structures correctly and I can make sure that the drop handling code will do the right thing without actually having to have something send real drag&drop events.

That way, the real event handling code is just 1-2 lines, so the chances that it breaks there are very, very slim. Also, there is no reason to test the drag&drop code of your browser or OS; this code should work.

Twaddle answered 4/9, 2014 at 11:51 Comment(8)
my problem seems to be exactly this github.com/angular/protractor/issues/160 . I mean that I'm trying to test integration between a slider directive and search module that actually updates any data. What I want to test is that . I a user interact's with the slider directive. Does it actually fires the sequence of events that the user experience expects?Mllly
@AlexandrosSpyropoulos: Your comment doesn't make sense to me.Twaddle
I mean that I'm trying to test integration between a slider directive and search module that actually handles the events. What I want to test is that . If a user interact's with the slider directive. Does it actually fires the sequence of events that the user experience expects? I hope this makes sense to you. In fact, I test a slider that changes min/max values and a few modules that are making requests to a service and display a list of data.Mllly
What do you expect to learn from executing hundreds of thousands of line of code? Doesn't your question really mean "I don't know how slider works and which events it fires"? I don't think that the events change very often. So it should be enough to find out once which events you can expect and in which order. Then write unit tests that make sure your code can handle them. If this part of the app breaks, check again which events get fired so see what has changed.Twaddle
Sorry, I probably didn't explain well. I'm not writing a unit test. That has been done and the unit test's satisfy their own tests. What I'm doing now is an E2E test. As you said, the fact is, the test doesn't know anything about the internals of the app. so I don't care about the internals of the application regarding this test. I care only of the UI the user experience (that actually a user is using a slider filter gets back a valid list of results). So can't see how I can simulate the user's action without simulating a move action. I'm afraid that your answer is not relevant to my question.Mllly
perhaps if you elaborate It will make sense to me.Mllly
I see. You're trying to write an integration test, not a pure unit test. In that case, I don't know an answer.Twaddle
I'll add more information in the question that explain the nature of the question. I though that protractor is a pure E2E framework and that was clear that I was asking about integration and not unit testing. Thank you for your answer.Mllly

© 2022 - 2024 — McMap. All rights reserved.