Skip to content

Automating your first test with Selenium and Ruby

Matthew Heusser Aug 30, 2021 Automation

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

  1. 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
  2. Install webdrivers.  These are the executable files mentioned earlier. In Ruby, they are just a single gem install away!

    gem install webdrivers
  3. 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.

require 'minitest/autorun'
require 'selenium-webdriver'
require 'webdrivers'

class WonderProxyTest < MiniTest::Test
 
  def setup
    #----------------------------------------------
    @browser = Selenium::WebDriver.for :chrome
    #                             ^----> change to :firefox, :safari etc as needed
    #---------------------------------------------
    @browser.manage.timeouts.implicit_wait = 30
  end

  def test_wonderproxy
    @browser.navigate.to "https://wonderproxy.com"
    assert(@browser.title.eql? "Localization testing with confidence - WonderProxy");
  end

  def teardown
    @browser.close();
  end
end
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.

➜  ruby_selenium_example git:(master) ✗ ruby k.rb         
Run options: --seed 64340

# Running:

.

Finished in 6.517044s, 0.1534 runs/s, 0.1534 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
➜  ruby_selenium_example git:(master) ✗
Output for test_wonderproxy.rb

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.

Matthew Heusser

The managing director of Excelon Development, Matt Heusser writes and consults on software delivery with a focus on quality.