Getting Started with Ruby and Capybara

Roselyne Makena
10 min readMar 29, 2023

The goal of this post is to cover the basics of Capybara and Ruby, and give a brief introduction to functional programming by exploring the use of Capybara with different frameworks.

By the end of this post, you should have a better idea about how to use Capybara and Ruby to write tests for your web applications, and be able to write tests for your application.

What are the advantages of using Capybara

1) Webdriver agnostic

Capybara works with any web driver that has a browser proxy. In other words, Capybara is agnostic about the web driver and it does not have some of its own requirements on the driver. It can be used with Selenium, PhantomJS and WebDriver from locations like Google Chrome, Firefox, Safari etc.

2) Works with multiple testing frameworks

Capybara can be used with several frameworks including, Cucumber, RSpec, Test::Unit, MiniTest, Minitest::Spec among others. This flexibility allows you to use the testing framework of your choice before you can begin writing tests with Capybara and switch out the frameworks with ease if need be.

At the same time, Capybara is flexible enough to use within a testing framework, that was not designed specifically for it.

For example, you can write tests using RSpec without having to worry about having to change the structure of your code as you would when using Test::Unit directly.

Capybara DSL

Before we begin, here is a brief introduction to the DSL that is available in Capybara that can be used in your tests.

a) Navigation

In cases where you would want to navigate to a new page in your test, the `visit` method can be used. Using the visit method. It’s important to note that the `visit` method only takes in a single parameter and is usualy a GET method.

In order to make assertions for a visited link — it’s adviseable to use the `have_current_path` — for example.

b) Finding elements

When testing webpages, you almost always will want to find specific elements that are relevant to your application. Capybara comes with a lot of tools to do this.

find_field — This finds the first field with the provided values. This can be used as:

find_field('My name').value
find_field(id: 'field_id').value
find_link('Home', :visible => :all).visible?
find_link(class: ['class-name', 'another-class-name'], :visible => :all).visible?
find_button('Submit').click
find_button(value: 'Continue').click
find(:xpath, ".//div/ul/li").click
find("#title").find("h1").click
all('a').each { |a| a[:href] }

c) Querying

To query the current page and find elements that match a particular page in order to perform assertions on them, Capybara offers the following.

page.has_selector?('div ul')
page.has_selector?(:xpath, './/div/h1')
page.has_xpath?('.//div/h3')
page.has_css?('div ul.li')
page.has_content?('my content')

d) Clicking elements

You use find_element to locate an element and place it inside of a block. In addition, there are other variations of this method that are available too. Here is how you can use these with Capybara

click_link — used to click a link by providing the button link as an argument. For example click_link(‘link-url’)

click_button — used to click a button by providing the button name as an argument.

click_on — used to click on a search field by providing the list of options as an argument. For example, if you want to select ‘Google’ from the list of suggestions provided by google, you would type: `click_on(‘Google’)`.

e) Interacting with forms

Capybara also provides a lot of tools that you can use to fill out forms, type text in textboxes and select items from Dropdown menus.

fill_in — used to fill in a textbox by providing the field name as an argument. For example, if you want to fill in the ‘username’ textbox, you would type:

fill_in('username', with: 'Rose')
fill_in('email', with: 'rose@gmail.com')
fill_in('Description', with: 'Really Long Text…')
choose('Radio Button Option Value')
check('Checkbox Value')
uncheck('Checkbox Value')
attach_file('Image', '/path/to/image-name.png')
select('Option', from: 'Option Na')

Scoping with Capybara

Capybara provides different ways to scope methods to specific elements. These scopes are used when you need to test how a certain select elements responds to a given actions. To do this, we use the `within` keyword.

within(“#some-id”) — This is used when you want to make assertions about elements that are within the xpath supplied by it, or those that have the id supplied by it. For example.

within("li#some-id") do
fill_in 'Username', with: 'Rose'
end

within(:xpath, ".//li[@id='username']") do
fill_in 'Name', with: 'Rose'
end

within_fieldset('username') do
fill_in 'Name', with: 'Rose'
end

within_table('Table') do
fill_in 'Name', with: 'Rose'
end

It’s important to note that these methods can be used in combination with each other too.

Using modals

By default, Capybara launches the application you are testing in your default browser. When testing browser applications, it’s important for you to be able to test them in different types of windows — such as pop-ups and modals.

You can easily confirm or dismiss any modal by using the following:

accept_alert do
click_link('Show')
end

dismiss_confirm do
click_link('Dismiss')
end

#You can combine the returned message and make assertions.

message = accept_prompt(with: 'Thank you') do
click_link('Show Alert')
end

expect(message).to eq('Thank you for clicking the Alert')

How to use Capybara DSL in a different context

To use the Capybara DSL in a different context, we can be specifying the context before using it’s methods like below.

include Capybara::DSL

Code Demo

We will have a look at how to use Capybara using different frameworks in order to have a better understanding on how to use this powerful tool.

This will allow us to have a better understanding of how test-driven development can be used effectively in our application testing process. Here is an example of how we would write a test for our application:

We will use the ecommerce website to run a few simple tests just for demonstration purposes.

Pre-requisites:

Before proceeding, you need to ensure you have the following.

1) Ruby

Have Ruby up and running on your local machine . You may need to install it using your operating system’s package manager or by visiting http://rubyinstaller.org/ and downloading the version that you want to install.

2) Browser

Ensure you have Google Chrome or Firefox browser installed. For this specific blog, I will be using Firefox as it has an integrated debugger which aids in debugging.

3) IDE of your choice

Make sure you have an IDE installed. For this guide I will be using VS studio as it has an integrated debugger as well. However, feel free to use your favourite IDE.

First ensure you have capybara and selenium gems installed by running.

`gem install selenium`
`gem install capybara`

If you list available gems for the above — you should see something similar to the following.

As you can see, I am using capybara 3.37.1 and cucumber 8.0.0 at the time of this blog. Your version may vary.

1) How to use Capybara with Cucumber

Cucumber is a Ruby library that is designed for writing BDD tests (Behavior Driven Development). When using Capybara with Cucumber, Capybara uses the Gherkin syntax to create and describe a series of test steps that can define an automation script. It also allows us to break down a single step into multiple test steps, which makes it easy to test scenarios that have a lot of steps.

Capybara is compatible with Cucumber out of the box and there are only two steps to get started using it with Cucumber:

To start, create a folder called capybara-cucumber and run `cucumber –init` when inside the folder. You should see something like the below.

You will notice a couple of features have been created. That we will have a look later.

Create a new folder called feature_files and create a file called `capybara_cucumber.feature`. This feature file will host our scenarios under test.

In this file, we will have the following.

# feature_files/capybara_cucumber.feature

Feature: Ecommerce login Feature
Scenario: Verify ecommerce webpage loads and user can sign in
Given Ecommerce webpage Login Page loads
And Ecommerce Login Link is present loaded
Then Correct Username and Password Should Login Successfully <username> <password>
And My Account page should display after login
Examples:
| username | password |
| swapnilbiswas012@gmail.com | LambdaTest123 |
| himanshi.jainn@rediffmail.com | LambdaTest123 |
| saumya.saran01@gmail.com | LambdaTest123 |

We will then create a new folder called page_object, and in it — have a file called `login_page.rb`. Inside the file — we will have the following.

class LoginPage
def username_link
$browser.find_link("Forgotten Password")
end

def username_textbox
$browser.find_field(id: "input-email")
end

def password_textbox
$browser.find_field(id: "input-password")
end

def login_button
$browser.find(:xpath, '//input[@value="Login"]')
end

def account_header
$browser.find(:xpath, '/html/body/div[1]/div[5]/div[1]/div/div/div[1]/h2')
end
end

Page objects help us define elements that we can re-use later. You can learn more about page objects in a separate blog.

Under the step_definitions folder, create a file called `ecommerce_steps.rb` — This file will define our actual test steps for our test to run. Inside the file, we will have the following.

require 'capybara/cucumber'
Capybara.default_driver = :selenium
Given(/^Ecommerce webpage Login Page loads$/) do
@url = "https://ecommerce-playground.lambdatest.io/index.php?route=account/login"
$browser.visit(@url)
$user_session = LoginPage.new
end
Then(/^Ecommerce Login Link is present loaded$/) do
expect($user_session.username_textbox)
end
Then(/^Correct Username and Password Should Login Successfully (.*) (.*)$/) do |username, password|
puts " - - - "
puts username
$browser.fill_in 'input-email', visible: false, with: username
sleep(1)
$browser.fill_in 'input-password', visible: false, with: password
sleep(2)
$user_session.login_button.click
end
And(/^My Account page should display after login$/) do
expect($user_session.account_header.text).to include("My Account")
end

Finally under `support/env.rb`. Replace the contents with the following.

require 'rubygems'
require 'selenium-webdriver'
Before do |scenario|
# used for local runs.
$browser = Capybara::Session.new(:selenium)
end
After do |scenario|
$browser.quit
end

To run the test, simply run `cucumber` within the folder and the tests will automatically pick up and start running.

Code Walkthrough: How to use Capybara with Cucumber

We can see the given-when-then format with the expected flow defined and is similar to the below flow which is common in cucumber tests.

The `$browser` variable here, is the one that was defined in the `env.rb` file — that defined the expected capabilities that the Selenium WebDriver will use to trigger the test. In the env file, You will note that we explicitly defined the browser version and the platform name we wish our tests to run. This can be changed to match the preferences desired.

We can also see the `.get(@url)` method that is used to navigate to our root webpage.

We are then able to maximize the browser and start our user session using the page object model we just created.

2) How to use Capybara with RSpec

RSpec is a Ruby testing framework and it is designed for writing BDD tests in a very clear and readable syntax. When using Capybara with RSpec, we will use the same steps that are used in Cucumber to define your scenarios, but implement RSpec related syntax.

Create a new folder called `capybara-rspec` and ensure you have run `rspec init` at the root of the directory in order to generate necessary files that will be used by Rspec when running the tests by running the command.

>> rspec –init

After generation, you will expect to find similar results logged on the terminal.

Create a file called `capybara-rspec_spec.rb ` under the spec folder, and type in the following.

require 'selenium-webdriver'
require 'capybara/rspec'
RSpec.describe 'Ecommerce Tests' do
def setupTest ()
# used for local runs.
@driver = Capybara::Session.new(:selenium)
@url = "https://ecommerce-playground.lambdatest.io/index.php?route=account/login"
@driver.visit @url
end
context "Login with username and password" do
usernames = ['swapnilbiswas012@gmail.com ', 'himanshi.jainn@rediffmail.com', 'saumya.saran01@gmail.com']
password = 'LambdaTest123'
usernames.each do |username|
it "should be able to login with the username and password" do
setupTest
@driver.fill_in 'input-email', visible: false, with: username
sleep(1)
@driver.fill_in 'input-password', visible: false, with: password
sleep(1)
@driver.click_button('Login')
sleep(5)
account_header = @driver.find(:xpath, '/html/body/div[1]/div[5]/div[1]/div/div/div[1]/h2')
expect(account_header.text).to eql("My Account")
@driver.quit
end
end
end
end

Also, it’s worth noting that the `spec_helper.rb` file that was generated — should look more or less like below.

RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
end

These are the default configuration settings that were created after running rspec –init and you do not need to change them at this point.

3) How to use Capybara with MiniTest

MiniTest is a framework for testing Ruby programs. In addition to Capybara, the framework includes a number of other test-suite related utilities such as matchers and spork extensions.

To get started, create a folder called capybara-minitest. On the CLI, install the gem by typing the following.

gem install minitest

After the installation is complete, you should see the version installed by listing the minitest gem. Do note that your gem version might be different from this one.

Create a file called `capybara-minitest_spec.rb` and type in the following.

require 'minitest/autorun'
require 'selenium-webdriver'
require 'capybara/minitest'
class EcommerceMiniTest < MiniTest::Test
include Capybara::DSL
include Capybara::Minitest::Assertions
def setupTest
# used for local runs.
@driver = Capybara::Session.new(:selenium)
@url = "https://ecommerce-playground.lambdatest.io/index.php?route=account/login"
end
def test_login_with_username_and_password
usernames = ['swapnilbiswas012@gmail.com ', 'himanshi.jainn@rediffmail.com', 'saumya.saran01@gmail.com']
password = 'LambdaTest123'
usernames.each do |username|
setupTest
@driver.visit @url
@driver.fill_in 'input-email', visible: false, with: username
sleep(1)
@driver.fill_in 'input-password', visible: false, with: password
sleep(1)
@driver.click_button('Login')
sleep(5)
account_header = @driver.find(:xpath, '/html/body/div[1]/div[5]/div[1]/div/div/div[1]/h2')
assert_equal(account_header.text, "My Account")
teardown
end
end
def teardown
@driver.quit
end
end

Code Walkthrough: Capybara with MiniTest

Minitest works quite similar to rspec. First we initiate the usernames and passwords we will use in our tests.

Then we create a block that loops through all the usernames by first setting up the page in the method setupTest.

On further inspection, you will notice that setupTest instantiates the test and fires up the browser with

4) How to use Capybara with Test::Unit

Test Unit is a ruby testing framework written in a way that most synchronous tests are readable, regardless of test complexity. Tests are written using a simple DSL, making it easy to write readable and maintainable tests.

In order to use Capybara with Test::Unit, all you will need to do is to include the testunit gem by running the following.

gem install testunit

If you check the gem version, you should see something similar to the following, although the exact version might vary.

Create a file called capybara-testunit_spec.rb` and type in the following.

require 'selenium-webdriver'
require 'test-unit'
class EcommerceTests < Test::Unit::TestCase
def setup
@driver = Selenium::WebDriver.for :firefox
@url = "https://ecommerce-playground.lambdatest.io/index.php?route=account/login"
@driver.get(@url)
@driver.manage.timeouts.implicit_wait = 30
@driver.manage.window.maximize
@wait = Selenium::WebDriver::Wait.new(:timeout => 7)
end
def test_login_with_username_and_password_should_go_to_my_account_page
@wait.until{@my_driver.title.include? "My Account"}
username = @driver.find_element(:id, "input-email")
password = @driver.find_element(:id, "input-password")
username.send_keys("swapnilbiswas012@gmail.com")
sleep(1)
password.send_keys("LambdaTest123")
sleep(1)
submit_button = @driver.find_element(xpath: '//*[@id="content"]/div/div[2]/div/div/form/input')
submit_button.submit
sleep(5)
account_header = @driver.find_element(xpath: '/html/body/div[1]/div[5]/div[1]/div/div/div[1]/h2')
assert_equal(account_header.text,"My Account")
end
def teardown
@driver.quit
end
end

To get the above code, you can check this repository.

Conclusion

Ruby is a wonderful programming language that is easy to learn and can be used for a wide range of applications. Both Ruby and the Capybara shared some useful information about such programming languages, so we hope this article has been informative for you.

Capybara makes testing easier and a lot less time-consuming. Ruby and Capybara are a great match for each other and I most definitely look forward to seeing where they will go in the future.

--

--

Roselyne Makena

Design thinking analytic. Born creative with design edge. Software QA Engineer. I write articles at: senseitechtips.com