Automating your first test with Selenium and Ruby
In addition to being a chemical element, Selenium is an open-source project that provides a set of tools for test automation. That includes everything from tools to run tests in the cloud, to a browser-based, codeless development environment, to webdriver, which provides a code library to direct a browser. Today's article will cover the Ruby wrapper for Selenium-Webdriver, providing step-by-step directions to understand, install, create and run tests in Ruby using Selenium 4.
Understanding Webdriver Architecture
Imagine a computer program with a simple browser object. Conceptually, you create the browser and tell it to open www.yourwebpage.com. From there, you can wait for the username element to load, then type into it a username, and so on. In this world, the browser is an object and you send it commands, which can include getting the text and making sure, after log in, the username appears on the page along with the text "hello, Matthew Heusser", or any other indicators the user is logged in.
Making this work takes a little more than downloading and installing a Ruby library. That library will call a webdriver object. That webdriver is actually an executable program - a .exe in Windows or a compiled binary on Mac or Linux. Every browser has a different binary, which will interpret the webdriver protocol and command the browser. The great advantage of this approach is that the protocol is an over-the-internet protocol. You can take the same tests and redirect them to a server on the other side of the internet, which makes running tests in the cloud, or at scale, a matter of creating a different webdriver object.
Let's get all the prerequisites installed.
Getting Selenium set up in Ruby
- Install the webdriver code library. Start with Ruby installed (tested under ruby-2.6.7), which provides gem, the install for Ruby code libraries. From the command line, install webdriver.
gem install selenium-webdriver
- Install webdrivers. These are the executable files mentioned earlier. In Ruby, they are just a single gem install away!
gem install webdrivers
- Install minitest. Webdriver is just that, a browser-driver, not a test tool. Minitest is a popular Ruby unit-test framework, the example that Sandi Metz uses in her book Practical Object-Oriented Design in Ruby ("Poodr"). If you haven't read a book on Object-Oriented design in Ruby, it will be incredibly helpful in structuring the test code so it does not become overwhelming. Of course, if you are an OO expert, adapting this code to any testing framework in Ruby will be trivial.
gem install minitest
Creating the first Ruby Selenium test
The example below opens up a new browser, sends it to a web page, and checks that the title matches expectations. The test doesn't do much. Don't worry; the blog post will include a second example below that covers some real functionality. For now, we just want to get the browser up.
The example runs on Google's Chrome browser. To change the browser to test on, change :chrome
to :firefox
, :safari
, or any supported browser. (Make sure the corresponding browser is installed too.) Note the use of setup
to create a single browser object for each test, then teardown
to tear that browser object down. That makes sure each test gets a clean browser. The code below is a slightly simplified version with just the basics. The best way to train your fingers is to type, but if you want to cut/paste this version of the code it is up on Github as well. Save the file and call it test_wonderproxy.rb
.
Running the first Selenium test in Ruby
The file above, test_wonderproxy.rb
, is a working Ruby program that runs inside a test framework. Run it from the command line, watch a browser pop up, and see the results. Depending on your operating system you may need to allow a downloaded program to accept incoming network connections.
Again, while the test above does prove you can control a browser, it does not do much. Let's at least check the website functionality a bit and learn how to connect to objects.
Testing website functionality in Ruby with Selenium
Minitest will automatically run any method that starts with "test" as a test, but we can define helper methods with different names. Let's create two, locate_object
(which takes a locator string and returns, hopefully, a webdriver selenium element) and object_loaded
, which returns true/false so we can assert the object was located. locate_object
will include a wait for the page to load. Here's the new code for these helpers:
def setup
@browser = Selenium::WebDriver.for :chrome
@browser.manage.timeouts.implicit_wait = 30
@wait = Selenium::WebDriver::Wait.new(:timeout => 15)
end
def object_loaded(object)
!object.nil? && object != 0 && (object.class.name.eql? "Selenium::WebDriver::Element")
end
def locate_object(locator)
@wait.until {
element = @browser.find_element(:xpath => locator)
element if element.displayed?
}
end
And here's the new test_wonderproxy_plans
method, which now includes messages on failure:
def test_wonderproxy_plans
# Click explore plans, see text!
@browser.navigate.to "https://wonderproxy.com"
link = locate_object( "//a[text()='Explore Plans']")
assert(object_loaded(link),"Found explore plans link on homepage")
link.click()
assert((@browser.page_source.include? "Stop localization testing today."),
"Text should be signup page text after click")
assert((@browser.page_source.include? "Get accurate results."),
"Checking additional signup text")
end
Tests run the same as before; the program now includes four assertions. The messages only appear on error, so we changed the test code from "Start localization testing", to "Stop localization testing" to trigger the failure.
➜ ruby_selenium_example git:(master) ✗ ruby test_wonderproxy.rb
Run options: --seed 41145
# Running:
.F
Finished in 7.256541s, 0.2756 runs/s, 0.4134 assertions/s.
1) Failure:
WonderProxyTest#test_wonderproxy_plans [test_wonderproxy.rb:45]:
Text should be signup page text after click
2 runs, 3 assertions, 1 failures, 0 errors, 0 skips
Where to go for more
The next step is probably learning to type into text boxes, click submit buttons, and check text within sub-elements. To do that, check out the Ruby Selenium cheat sheet and tutorials on locators in Selenium. Selectors are strings that allow you to convert some element on the web page to a Ruby element to click or type into. The examples above use XPath; the primary competitor to XPath is the cascading style sheet, or CSS.
The examples above hint at good software engineering with helper functions. A larger project would create helper libraries, possibly tied to actual business functionality (like search, or login), that can be included in multiple test files. The page object pattern is a common way to structure these tests.