December 19, 2018

Basic Capybara-Gauge: Setting Up Capybara to Open a Chrome Browser

This is the third part of a series of blog posts. Care to go back to the beginning

So far, we have written test specifications to test Dave Haeffner's The-Internet, and we have set up the Gauge-Ruby environment.

Now, we need to set Capybara up to be integrated with the Gauge test framework. 



Gemfile Setup


Gauge uses Bundler to handle its dependencies, installing various Ruby gems found in RubyGems.org. If you open up the Gemfile that was installed with the test project, you will see:

   source 'https://rubygems.org'  

   gem 'test-unit', :group => [:development, :test]  
   gem 'gauge-ruby' , '~>0.5.1', :group => [:development, :test]  

We will be adding the Ruby gems:
  • Capybara: This Ruby gem handles all interaction with the browser. Visit new pages. Fill in text boxes. Click button. Within a certain area, expect pages to have content described. These are the human readable commands you can use to navigate and execute browser tests.
  • Rspec: This behavior driven framework can be implemented by Capybara to give you a whole library to compare an expected value to an actual value.
  • Selenium WebDriver: Capybara is a good testing framework for Ruby, but can't do everything. For all else, there is Selenium WebDriver. 
We can search on RubyGems.org for the latest versions for Capybara, Rspec, and Selenium WebDriver, copying and pasting on their respective pages what we need to grab to add them to our Gemfiles.

This now gives us: 

Gemfile
   source "https://rubygems.org"  
   
   gem 'capybara', '~> 3.12'  
   gem 'gauge-ruby' , '~>0.5.1', :group => [:development, :test]  
   gem 'rspec', '~> 3.8'  
   gem 'selenium-webdriver', '~> 3.141'  

Save the new file! Let's make sure to install of this on our local machine. With our Mac Terminal:
  • bundle update
... And our environment will be all set up!

Spec Helper Setup


Within the step_implementations folder, we will be adding a Ruby file called a spec_helper. All step implementations will use this file to setup Capybara to interact with the browser.

We will be creating a new file, spec_helper.rb, by stealing some code...

GoCD, Gauge's answer to continuous integration, has a suite of Ruby Functional tests. Taking an assortment of code that initializes their tests. In our spec_helper file we will:
  • Require for Bundler, the Bundler.setup.
  • Require Capybara/DSL and Capybara/RSpec, including these libraries in a module DRIVER.
  • Configure Gauge to include the DRIVER module we set up, along with the Screengrabber library, which will save screenshots on test failure. By default, they will be added to our tests.
  • Configure Capybara to have a default wait time of a variable we can call timeout, which we can set to 20 seconds.  

Here's what we have so far for spec_helper.rb:
 require 'bundler'  
 require 'capybara/dsl'  
 require 'capybara/rspec'  
 Bundler.setup(:default)  
 Bundler.require  
     
 module DRIVER  
  include RSpec::Matchers  
  include Capybara::DSL  
 end  
   
 TIMEOUT = 20  

There's No Place Like Chrome


For this sample project, let's focus just on getting the tests up and running on Chrome:
  • Chrome as the default driver, Chrome as the current driver, with Chrome as the Javascript driver. 
... Lazy? Yes.

... But, according to recent browser metrics of this site, 80% of the people accessing this blog is using Chrome, with only 8% using Firefox. If you are focusing solely on functional tests in a browser, and not on visual testing, getting things working in just Chrome might be a good start.


spec_helper.rb
 Capybara.default_driver = :chrome  
 Capybara.current_driver = :chrome  
 Capybara.javascript_driver = :chrome  

Capybara Registration and Configuration


Gauge allows you to set up execution hooks, to run certain things to happen either before the suite runs or after the test suite runs. They are called before_suite and after_suite.

Let's have before_suite register the Chrome driver, open a new window, then set up for options for the window to be 1240 x 1400 pixels.

Let's add the default max wait time that we had declared earlier, and make sure to ignore any hidden elements, so we can only see what the user sees.

spec_helper.rb
 before_suite do  
  Capybara.register_driver(:chrome) do |app|  
   options = Selenium::WebDriver::Chrome::Options.new  
   options.add_argument('--window-size=1240,1400')  
    
   Capybara::Selenium::Driver.new(app,  
                   browser: :chrome,  
                   options: options)  
  end  
 end  
   
   
 Capybara.configure do |config|  
  config.default_max_wait_time = timeout  
  config.ignore_hidden_elements = true  
 end  

Gauge Configuration

Remember the DRIVER module which included Capybara/DSL and RSpec? Let's make sure that Gauge can use that. Let's also have Gauge know to use Capybara's save_screenshot method for Screengrabber, to include it in the HTML reports when things go sour, saving it as a file, screenshot.png, in the /tmp directory. 

spec_helper.rb
 Gauge.configure do |config|  
  config.include DRIVER  
  config.screengrabber = -> {  
   Capybara.page.save_screenshot('/tmp/screenshot.png')  
   return File.binread('/tmp/screenshot.png')  
  }  
 end  


Write a Navigation Test Case

Under the specs folder, let's delete the example.spec that was installed as part of the sample project.

Let's create a new file, Navigation.spec, and test that we can navigate to https://the-internet.herokuapp.com/login. As a verification step, let's make sure that the header is "Login Page".

The test script could look like this:

specs/Navigation/Navigation.spec
 # Navigation: Go to The-Internet Login Page  
   
 ## NAVIGATION: Visit The-Internet Confirming Login Page  
 * LOGIN: Visit the Login Page  
 * LOGIN: Verify the heading is "Login Page"   

The first line is the Heading. That text will go into the HTML Report. It can be whatever you like.

The next line is the Scenario Heading. The text will also go into the HTML Report. It can be whatever you like.

The next two bullet points are the test steps to be executed. Gauge will take whatever text is listed here, and search for the corresponding code block in the step_implementation folder.

You can use whatever sequence of characters you want to describe the step, as long as it starts off with a bullet point. Personally, I like describing exactly what is happening, and what page the action is happening on.

Notice the "Login Page" in quotation marks? That is how Gauge makes tests dynamically driven. In my experience, labels are always, always changing, therefore I never want to bury them in the code itself, else I will keep having to change the code, again and again.

If the header changes from "Login Page" to, say, "Login", to update the framework all I would need to do is update the spec.

Hook Up Test Steps To Capybara

There are two steps we need to hook up in the step_implementation folder:
  • LOGIN: Visit the Login Page
  • LOGIN: Verify the heading is "Login Page"
The first step is easy. Setting up the block of code with the first step, we can use Capybara's "Visit" method, and Capybara will use the configuration set up in the spec_helper to open up the browser and visit the page... as long as we require the spec_helper file. Let's create a constant in Ruby to hold the application url to make the code look cleaner.

For the second step, let's store whatever we passed into the step method into a variable. Let's call it "page_header".

Capybara includes Rspec methods where we can can compare and contrast expected values with actual values found.

We could easily do: expect(page).to have_content("Login Page")

... But I want it to be more exact, checking out only the text in the H2 element of the Login page. I also want to the test to be more dynamic, to take whatever value we have indicated on the Navigation.spec in the SPECS section.

Since this all relates to the LOGIN page, let's name the file "login_spec.rb".

login_spec.rb
 require_relative 'spec_helper'  
   
 APP_URL = 'https://the-internet.herokuapp.com/login'  
 LOGIN_HEADER = 'h2'  
   
 step 'LOGIN: Visit the Login Page' do  
  visit(APP_URL)  
 end  
   
 step 'LOGIN: Verify the heading is <page_header>' do |page_header|  
  expect(LOGIN_HEADER).to have_content(page_header)  
 end  


Run The Tests

To run all of the tests in verbose mode, we can run on the Mac Terminal:
  • bundle exec gauge run specs -v
If we wanted to run just the Navigation tests, we could run:
  • bundle exec gauge run specs/Navigation.spec -v
What happens?
  • A browser opens up
  • The first step is executed, visiting The-Internet Login page
  • The second step is executed, checking that the header level 2 matches the spec, "Login Page"
  • The browser closes.
The following output is shown in the Mac Terminal:

 # Navigation: Go to The-Internet Login Page  
  ## NAVIGATION: Visit The-Internet Confirming Login Page  
    * LOGIN: Visit the Login Page      ...[PASS]  
    * LOGIN: Verify the heading is "Login Page"      ...[PASS]  

If you go to reports -> html-report, you can open index.html in a browser, which shows what passed and what failed, automatically taking a screenshot.

Want to see an example of a failing test? In the Navigation.spec, search for "Secure Area" instead of "Login Page", and the test will fail.

Next, let's alter the spec_helper file to allow Chrome to be run in headless mode!

Happy Testing!



-T.J. Maher

Sr. QA Engineer, Software Engineer in Test
Meetup Organizer, Ministry of Testing - Boston

Twitter | YouTubeLinkedIn | Articles

No comments: