5

I'm testing web app (using RobotFramework with Selenium2Library) in which some drag and drop actions is needed at couple of points. I tried Drag And Drop keyword, but it's not working properly.

Since I can't pass the production app, I recreated problem using this page below: https://html5demos.com/drag/

My code is:

*** Settings ***
Library  Selenium2Library

*** Variables ***
${URL} =  https://html5demos.com/drag/

*** Test Cases ***

Prepare Browser
    Open_Browser  ${url}  browser=chrome
    Maximize Browser Window

Make Test
    #Drag And Drop  //*[@id="one"]  //*[@id="bin"]
    #Drag And Drop  //*[@id="two"]  //*[@id="bin"]
    Capture Page Screenshot
    Sleep  1

Close All
    Close Browser

Have tried it using both Python 2.7 and 3.6.

Output I get is test shown as PASS, but I can't see any real results of drag and drop action (both in my production app and sample page linked above). Screenshot of drag and drop test results

When I look into what happens in the browser during test I notice, that the object became draggable (quote "drag me" is added in brackets) but test stood for a log time. When mouse cursor is moved, test goes on int PASS mentioned above, but without real effect.

Tried on newest Chrome, Firefox, IE. Also tried with keywords Mouse Down, Mouse Over, Mouse Up, but with the same results.

Here is screenshot of log from execution report: Execution report screenshot

I would appreciate any help or workaround to have it done correctly.

YggY
  • 65
  • 2
  • 8

3 Answers3

5

From other posts on [so] it appears that this functionality doesn't work very well. For this reason most answers contain the advice to use JavaScript to create a solution. I've adapted the example found in this SO answer to work with Robot Framework:

drag-n-drop.js

var dataTransfer=
                {
                    dropEffect:'',
                    effectAllowed:'all',
                    files:[],
                    items:{},
                    types:[],
                    setData:function(format,data)
                    {
                        this.items[format]=data;
                        this.types.push(format);
                    },
                    getData:function(format)
                    {
                        return this.items[format];
                    },
                    clearData:function(format){}
                };
var emit=function(event,target)
                {
                    var evt=document.createEvent('Event');
                    evt.initEvent(event,true,false);
                    evt.dataTransfer=dataTransfer;
                    target.dispatchEvent(evt);
                };
                
var DragNDrop=function(src,tgt) {
    src = document.getElementById(src);
    tgt = document.getElementById(tgt);
    emit('dragstart',src);
    emit('dragenter',tgt);
    emit('dragover',tgt);
    emit('drop',tgt);
    emit('dragend',src);
    return true;
}           

drag-n-drop.robot

*** Settings ***
Library  SeleniumLibrary
Library  OperatingSystem    

Suite Setup       Open_Browser    ${url}    Chrome
Suite Teardown    Close Browser

*** Variables ***
${URL} =  https://html5demos.com/drag/

*** Test Cases ***
Make Test
    ${js}        Get File              drag-n-drop.js
    ${result}    Execute Javascript    ${js}; return DragNDrop("two", "bin");
    
    Capture Page Screenshot
    Sleep  1
meles
  • 155
  • 2
  • 11
A. Kootstra
  • 6,331
  • 3
  • 17
  • 38
  • I still need some help with it, since I do not know JavaScript well yet. How to change the code above, if what I want to have as an arguments of DragNDrop function are xpaths instead of div ids. In the application I test I don't have attributes like 'id' and I use xpath locator strategy (usually I use div class and text()). In above example, when I want to locate source div by xpath=//*[@id="one"] and target by xpath=[@id="bin"] I get ERROR: WebDriverException: Message: unknown error: Cannot read property 'dispatchEvent' of null. How to change that JavaScript to be used in more universal? – YggY Apr 03 '18 at 12:47
  • I have xpath like this: SOURCE:
    Source Name
    DESTINATION:
    Drop here
    How would you try to get those ones?
    – YggY Apr 03 '18 at 12:59
  • 1
    This really is a new question. In addition, it is a question that has been asked before on [so] that a simple search on [JavaScript Cross xPath](https://stackoverflow.com/search?q=javascript+cross+xpath) gives a number of results that should allow you to craft a solution that works for you. – A. Kootstra Apr 04 '18 at 07:13
  • 2
    Workaround for how to find a locator using xpath is adding following function to the script above and call it inside DragNDrop function. `function getElementByXpath(path) {return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;}` And in DragNDrop: `src = getElementByXpath(src) tgt = getElementByXpath(tgt)` – YggY Apr 09 '18 at 14:28
1

I tried the above answer and they weren't applicable to my use case and neither was the inbuilt function of selenium. Instead i implemented my own drag and drop keyword that is reusable. This works even for scenarios where in the angular js/ react js elements for example don't have an attribute called draggable set.

Drag And Drop
    [Arguments]     ${src}     ${intermediate}      ${tgt}
    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Down   ${src}
    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Over   ${intermediate}
    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Over   ${tgt}
    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Up     ${tgt}

The use of Wait until keyword succeeds helps with guaranteeing to a good extent that the process wont fail. You can find its documentation here. What the drag and drop does is literally press the mouse down move location and release it. I have additionally used an intermediate location to handle cases where it may fail but its not necessary.

To call the function simply use something like this -

Drag And Drop   ${XPATH1}  ${XPATH2}  ${XPATH3}
1

Try it out

 Drag And Drop Element
    [Arguments]     ${src}  ${tgt}

    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Down   ${src}
    Sleep       1s
    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Out    ${src}
    Sleep       1s
    Capture Page Screenshot
    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Over   ${tgt}
    Sleep       1s
    Wait Until Keyword Succeeds      ${ATTEMPTS}     ${LARGER_TIMEOUT}      Mouse Up     ${tgt}
    Sleep       1s