Selenium: Weird problem with moving an element (dragging it to another element)

Viewed 67

I am trying to have a script do the following:

  1. Move a SOURCE element to a TARGET element. Imagine TARGET as a grid. I want to place SOURCE on x,y position (1 1).
  2. Have the script move SOURCE along the top row of TARGET such that it loops the position through (2 1), (3 1), (4 1), (5 1) etc.

Here's what I have:

action = ActionChains(chrome_browser)
source = chrome_browser.find_element_by_class_name('SOURCE')
target = chrome_browser.find_element_by_xpath('Path')
action.click_and_hold(source).move_to_element_with_offset(target, 1, 1).release().perform()  # This accomplishes #1 on the list above (moves SOURCE to TARGET on position 1, 1)
i = 0
while i <= 100:  # LOOP 100x
    action.click_and_hold(source).move_by_offset(1, 0).release().perform()
    print('The current iteration is', i)
    time.sleep(10)
    i += 1

So the initial placement outside of the while loop works flawlessly. However, the iterations in the while loop do something very weird. Every iteration retraces the steps of all previous iterations. For example, iteration 7 instead of moving along the x axis by 1, it moves SOURCE to the original placement outside of the while loop and then moves it 1 unit right 7 times. Iteration 8 would do the same thing but move it 8x etc. This is so strange to me. What is going on?

1 Answers

you have to reset actions and this can be done in following ways:

  1. reinitialize action
  2. reset all devices in the action class
  3. use selenium 4

1:

action = ActionChains(chrome_browser)
source = chrome_browser.find_element_by_class_name('SOURCE')
target = chrome_browser.find_element_by_xpath('Path')
action.click_and_hold(source).move_to_element_with_offset(target, 1, 1).release().perform()  # This accomplishes #1 on the list above (moves SOURCE to TARGET on position 1, 1)
i = 0
while i <= 100:  # LOOP 100x
    action = ActionChains(chrome_browser)
    action.click_and_hold(source).move_by_offset(1, 0).release().perform()
    print('The current iteration is', i)
    time.sleep(10)
    i += 1

2:

Second appraoch:

there is reset_actions() method in action chain for this purpose , but there is abug:

https://github.com/SeleniumHQ/selenium/issues/6837

so use below approach:

action = ActionChains(chrome_browser)
source = chrome_browser.find_element_by_class_name('SOURCE')
target = chrome_browser.find_element_by_xpath('Path')
action.click_and_hold(source).move_to_element_with_offset(target, 1, 1).release().perform()  # This accomplishes #1 on the list above (moves SOURCE to TARGET on position 1, 1)
i = 0
while i <= 100:  # LOOP 100x
    action.w3c_actions.clear_actions()
    for device in action.w3c_actions.devices:
      device.clear_actions()
    action = ActionChains(chrome_browser)
    action.click_and_hold(source).move_by_offset(1, 0).release().perform()
    print('The current iteration is', i)
    time.sleep(10)
    i += 1

3:

If you are using selenium v4:

The bug is fixed :

to install selenium v4: pip install selenium==4.0.0.a7

action = ActionChains(chrome_browser)
source = chrome_browser.find_element_by_class_name('SOURCE')
target = chrome_browser.find_element_by_xpath('Path')
action.click_and_hold(source).move_to_element_with_offset(target, 1, 1).release().perform()  # This accomplishes #1 on the list above (moves SOURCE to TARGET on position 1, 1)
i = 0
while i <= 100:  # LOOP 100x
    action.reset_actions()
    action = ActionChains(chrome_browser)
    action.click_and_hold(source).move_by_offset(1, 0).release().perform()
    print('The current iteration is', i)
    time.sleep(10)
    i += 1
Related