I would like to drag-and-drop one element to the position of another, triggered from within a watir-webdriver script.
By "drag-and-drop" I mean picking up a draggable element and releasing it on another. By "possible" I mean any method for drag/drop that can be executed from a watir-webdriver script. This includes code snippets, third party gems, etc.
As I understand it drag-and-drop is a feature request for core watir-webdriver (at time of asking), so I'm looking (in principle) for an alternative.
UPDATE drag-and-drop is now part of core watir-webdriver (as of 0.5.0, I believe)
UPDATE 2 For those seeking enlightenment, this is now possible (as of version 0.5.0):
a = browser.div(:id => "draggable")
b = browser.div(:id => "droppable")
a.drag_and_drop_on b
and
a = browser.div(:id => "draggable")
a.drag_and_drop_by 100, -200
I don't know if you found the answer for this by now, but this is how I do it for Firefox:
my_element.fire_event("onmousedown")
driver=browser.driver
driver.action.click_and_hold(my_element.wd).perform
sleep 2
driver.action.move_to(target.wd).perform
sleep 2
my_element.fire_event("onmouseup")
It fails without the delays, but it works fine with them on FF5.
require 'rubygems'
require 'watir-webdriver'
module Watir
class Element
def drag_and_drop_on(other)
assert_exists
driver.action.drag_and_drop(#element, other.wd).perform
end
end
end
profile = Selenium::WebDriver::Firefox::Profile.new
profile.native_events = true
b = Watir::Browser.new :firefox, :profile => profile
b.goto "http://jqueryui.com/demos/droppable/default.html"
b.element(:id => "draggable").drag_and_drop_on(b.element(:id => "droppable"))
h3manth.com
Did not use it myself, but there is some documentation about using Using drag and drop here: https://github.com/SeleniumHQ/selenium/wiki/Tips-And-Tricks
Related
I'm working on a project which uses nodejs and nighwatch for test automation. The problem here is that the tests are not reliable and give lots of false positives. I did everything to make them stable and still getting the errors. I went through some blogs like https://bocoup.com/blog/a-day-at-the-races and did some code refactoring. Did anyone have some suggestions to solve this issue. At this moment I have two options, either I rewrite the code in Java(removing nodejs and nightwatch from solution as I'm far more comfortable in Java then Javascript. Most of the time, struggle with the non blocking nature of Javascript) or taking snapshots/reviewing app logs/run one test at a time.
Test environment :-
Server -Linux
Display - Framebuffer
Total VM's -9 with selenium nodes running the tests in parallel.
Browser - Chrome
Type of errors which I get is element not found. Most of the time the tests fail as soon the page is loaded. I have already set 80 seconds for timeout so time can't be issue. The tests are running in parallel but on separate VM's so I don't know whether it can be issue or not.
Edit 1: -
Was working on this to know the root cause. I did following things to eliminate random fails: -
a. Added --suiteRetries to retry the failed cases.
b. Went through the error screenshot and DOM source. Everything seems fine.
c. Replaced the browser.pause with explicit waits
Also while debugging I observed one problem, maybe that is the issue which is causing random failures. Here's the code snippet
for (var i = 0; i < apiResponse.data.length; i++) {
var name = apiResponse.data[i];
browser.useXpath().waitForElementVisible(pageObject.getDynamicElement("#topicTextLabel", name.trim()), 5000, false);
browser.useCss().assert.containsText(
pageObject.getDynamicElement("#topicText", i + 1),
name.trim(),
util.format(issueCats.WRONG_DATA)
);
}
I added the xpath check to validate if i'm waiting enough for that text to appear. I observed that visible assertion is getting passed but in next assertion the #topicText is coming as previous value or null.This is an intermittent issue but on test server happens frequently.
There is no magic bullet to brittle UI end to end tests. In the ideal world there would be an option set avoid_random_failures=true that would quickly and easily solve the problem, but for now it's only a dream.
Simple rewriting all tests in Java will not solve the problem, but if you feel better in java, then I would definitely go in that direction.
As you already know from this article Avoiding random failures in Selenium UI tests there are 3 commonly used avoidance techniques for race conditions in UI tests:
using constant sleep
using WebDriver's "implicit wait" parameter
using explicit waits (WebDriverWait + ExpectedConditions + FluentWait)
These techniques are also briefly mentioned on WebDriver: Advanced Usage, you can also read about them here: Tips to Avoid Brittle UI Tests
Methods 1 and 2 are generally not recommended, they have drawbaks, they can work well on simple HTML pages, but they are not 100% realiable on AJAX pages, and they slow down the tests. The best one is #3 - explicit waits.
In order to use technique #3 (explicit waits) You need to familiarize yourself and be comfortable with the following WebDriver tools (I point to theirs java versions, but they have their counterparts in other languages):
WebDriverWait class
ExpectedConditions class
FluentWait - used very rarely, but very usefull in some difficult cases
ExpectedConditions has many predefinied wait states, the most used (in my experience) is ExpectedConditions#elementToBeClickable which waits until an element is visible and enabled such that you can click it.
How to use it - an example: say you open a page with a form which contains several fields to which you want to enter data. Usually it is enought to wait until the first field appears on the page and it will be editable (clickable):
By field1 = By.xpath("//div//input[.......]");
By field2 = By.id("some_id");
By field3 = By.name("some_name");
By buttonOk = By.xpath("//input[ text() = 'OK' ]");
....
....
WebDriwerWait wait = new WebDriverWait( driver, 60 ); // wait max 60 seconds
// wait max 60 seconds until element is visible and enabled such that you can click it
// if you can click it, that means it is editable
wait.until( ExpectedConditions.elementToBeClickable( field1 ) ).sendKeys("some data" );
driver.findElement( field2 ).sendKeys( "other data" );
driver.findElement( field3 ).sendKeys( "name" );
....
wait.until( ExpectedConditions.elementToBeClickable( buttonOK)).click();
The above code waits until field1 becomes editable after the page is loaded and rendered - but no longer, exactly as long as it is neccesarry. If the element will not be visible and editable after 60 seconds, then test will fail with TimeoutException.
Usually it's only necessary to wait for the first field on the page, if it becomes active, then the others also will be.
Running two tests at once, how do I get the second test from closing the browser of the first test?
Pretty much like my questions states: I'm running two tests (e.g.: test1.rb, test2.rb) at once using basic watir.
I'm not running rake, watir-grid, selenium-grid, parallel_test, or rspec. Whichever test finishes first invokes browser.close, causing the remaining test to fail. The returned message from the failed test is browser window was closed. /var/lib/gems/2.3.0/gems/watir-6.1.0/lib/watir/browser.rb:312:in 'assert_exists'.
What am I doing wrong? I've tried giving different variable names to the browser assignment such as browser1, browser2, etc. I've even tried installing rake under Jenkins to use two different workspaces. Below are examples of my tests (actual code removed to protect company identity).
test1.rb
#!/usr/bin/ruby
require 'watir'
require 'headless'
def runTests
# tests go here
end
begin
puts "Running headless."
headless = Headless.new
headless.start
puts "Running browser."
browser = Watir::Browser.new(:chrome)
browser.window.resize_to(1200, 1000)
browser.driver.manage.timeouts.implicit_wait = 5
runTests()
rescue => e
puts ("#{e}. "+ e.backtrace.join("\n"))
ensure
browser.close
headless.destroy
end
test2.rb
#!/usr/bin/ruby
require 'watir'
require 'headless'
require 'CoreClass'
def runSecondFileTests()
# second set of tests go here
# might use #coreClass if needed
end
begin
puts "Running headless."
headless = Headless.new
headless.start
puts "Running browser."
client = Selenium::WebDriver::Remote::Http::Default.new
client.read_timeout = 600
browser = Watir::Browser.new(:chrome, :http_client => client)
browser.window.resize_to(1200, 1000)
#coreClass = CoreClass.new(browser)
runSecondFileTests()
rescue => e
puts ("#{e} "+e.backtrace.join("\n"))
ensure
browser.close
headless.destroy
end
Posts I've already read:
Is it possible to run Watir test in parallel?
Watir webdriver; window.close is closing entire browser?
Suppress auto-closing window in Watir
https://markoh.co.uk/droplets
https://watirmelon.blog/tag/automated-testing/
http://watirautomation.blogspot.com/
https://github.com/grosser/parallel_tests#setup-for-non-rails
https://github.com/watir/watir-rspec
The problem is actually in the headless setup. The first headless.destroy will force close all open browsers in the default display. You need to specify display or reuse parameters.
Is there any way we can slow down the execution of Watir WebDriver under Cucumber?
I would like to visually track the actions performed by Watir. At the moment, it goes too fast for my eyes.
While Watir itself does not have an API for slowing down the execution, you could use the underlying Selenium-WebDriver's AbstractEventListener to add pauses before/after certain types of actions.
Given you want to see the result of actions, you probably want to pause after changing values and clicking elements. This would be done by creating the following AbstractEventListener and passing it in when creating the browser:
class ActionListener < Selenium::WebDriver::Support::AbstractEventListener
def after_change_value_of(element, driver)
sleep(5)
end
def after_click(element, driver)
sleep(5)
end
end
browser = Watir::Browser.new :firefox, :listener => ActionListener.new
For a full list of events that you can listen for, see the
Selenium::WebDriver::Support::AbstractEventListener documentation.
Not universally. You could Monkey Patch the element_call method to add a sleep after every interaction with a Selenium Element. Import this code after requiring watir-webdriver.
module Watir
class Element
alias_method :watir_element_call, :element_call
def element_call &block
watir_element_call &block
sleep 1
end
end
end
Also note, that Monkey Patching is generally a bad idea, and when I change the implementation (which I plan to), this code will break.
My suite of cucumbers gets run on both Firefox and Chrome. Some of them require a browser resize, which is horrible to deal with in Chrome. Since the behaviors that need the resize don't require cross browser testing, I'd like some way to ignore them when the detected browser is Chrome. Is there a way to do this? Perhaps with hooks or in the steps? I'm currently doing the resizing in Before and After hooks.
I don't know which web-driver you are using, but for watir-webdriver you can do the following:
You can determine which browser it is in the steps that you want to skip using the code in the below URL.
http://watirwebdriver.com/determining-which-browser/
Once you determine that it is chrome you can just skip that particular step.
In your test helper, you can add those methods :
def use_chrome_driver
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
Capybara.current_driver = :selenium_chrome
end
def setup
Capybara.current_driver = :selenium
end
All your tests will use the selenium default webdriver, then when you need to use Chrome, just call the method use_chrome_driver at the beginning of your test like that :
def test_login_with_chrome
use_chrome_driver
...
end
You may also add into your helper your firefox driver with the correct browser size you need, and make it the default selenium browser.
Hi is it possible to tell Capybara to use IE instead of always defaulting to Firefox?
I have to write some automated tests but the business only supports Internet Explorer so I need the tests to be run on this browser.
Thanks.
As marc_s suggested in the comments, you could try making IE the default browser on your test machine.
I also see some google hits about using Capybara with Selenium (remote control).
If you're interested, check the Selenium docs for how to specify the browser.
Edit It seems the tutorial I posted before was Rack-only. Not sure, but maybe this will work instead:
http://www.johng.co.uk/2010/10/13/run_capybara_and_cucumber_features_in_internet_explorer_on_remote_windows/
Capybara.app_host = "http://192.168.1.37:3000"
Capybara.default_driver = :selenium
Capybara.register_driver :selenium do |app|
Capybara::Driver::Selenium.new(app,
:browser => :remote,
:url => "http://192.168.1.127:4444/wd/hub",
:desired_capabilities => :internet_explorer)
end
It still requires Selenium.
Edit 2:
If you get this error:
Capybara::TimeoutError: failed to resynchronize, ajax request timed out
Then try adding this code to features/step_definitions/mydefiniation.rb:
Before do
page.driver.options[:resynchronize] = false
end
See this question about that specific problem: Using Capybara for AJAX integration tests
Use ->
ignore_mode = opts.delete(:introduce_flakiness_by_ignoring_security_domains) != false
Goto -> External Libraries- selenium-webdriver - lib - selenium - webdriver - ie - bridge.rb
Update module IE -> def initialize
It contains -
ignore_mode = opts.delete(:introduce_flakiness_by_ignoring_security_domains)
just add != false so that it becomes ->
ignore_mode = opts.delete(:introduce_flakiness_by_ignoring_security_domains) != false