December 20, 2018

Basic Capybara-Gauge: Set Up Headless Chrome

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

We've come up with test specs for Dave Haeffner's The-Internet. We've set up a Ruby environment to run the tests, and configured Chrome to open the Login page.

With this entry, we will be activating Chrome in Headless Mode, i.e. running Chrome but without a visual interface, allowing the tests to run faster.

About Headless Chrome


According to Eric Bidelman's article, Getting Started with Headless Chrome, the new option of running Chrome in Headless mode started with Google Chrome version 59, released in May 2017.

Before, you had to use something such as PhantomJS to emulate the Chrome browser if you wanted to run Chrome in a place where the processing power to bring up a visual window would be a waste, such as running it with an automated test script running in a continuous integration environment. Now, it is built right in.



"Headless Chrome is shipping in Chrome 59. It's a way to run the Chrome browser in a headless environment. Essentially, running Chrome without chrome! It brings all modern web platform features provided by Chromium and the Blink rendering engine to the command line.

"Why is that useful? A headless browser is a great tool for automated testing and server environments where you don't need a visible UI shell. For example, you may want to run some tests against a real web page, create a PDF of it, or just inspect how the browser renders an URL".

The power of Headless Chrome and browser automation (Google I/O '18)
https://youtu.be/lhZOFUY1weo

There are a few command line interface commands from this article that we can incorporate when registering the Chrome driver:
  • Command to run Chrome in Headless Mode: --headless
  • Needed when running on Windows: --disable-gpu
  • Aren't setting up a specific Chrome user? --no-sandbox
There is one more command we should activate, in case we want to eventually use Chrome inside a Docker container: --disable-dev-shm-usage

If you launch a Docker container, by default, the /dev/shm partition will be 64 MB in size, too small to load. Let's add this to the spec_helper file.

Let's create a constant in Ruby to indicate if we want Headless mode on or off.

How do we know we are in headless mode or not when running the test? Let's output it to the screen:
  • HEADLESS_MODE = true
  • puts "CHROME_DRIVER: Headless mode == #{HEADLESS_MODE}"
Ruby is dynamically typed. Put a Boolean in it, it becomes a Boolean! Put a String in it, it becomes a String!

Ruby allows you to take a String and embed the value of a variable in it by using the hashtag and surrounding the variable with curly braces.

Move Headless Value to Gauge Properties

Gauge allows you to switch up environment properties for your Gauge project.

Let's say you want to have the tests run on your default environment (env/default) in your ruby.properties file:
  • Need visual aids for debugging? Set HEADLESS = false
  • Don't need visual aids for debugging? Set HEADLESS = true
By adding the HEADLESS = false in our env/default/ruby.properties file we don't have to go mucking about in the code itself to change these environment variables.

In our spec_helper file, we declare a constant, HEADLESS_MODE, and setting it to the environment variable we created:

HEADLESS_MODE = ENV['HEADLESS']


spec_helper.rb
 require 'bundler'  
 require 'capybara/dsl'  
 require 'capybara/rspec'  
 Bundler.setup(:default)  
 Bundler.require  
   
 HEADLESS_MODE = ENV['HEADLESS']  
   
 module DRIVER  
  include RSpec::Matchers  
  include Capybara::DSL  
 end  
   
 TIMEOUT = 20  
   
 Capybara.default_driver = :chrome  
 Capybara.current_driver = :chrome  
 Capybara.javascript_driver = :chrome  
   
 before_suite do  
  Capybara.register_driver(:chrome) do |app|  
   options = Selenium::WebDriver::Chrome::Options.new  
   options.add_argument('--window-size=1240,1400')  
   
   puts "CHROME_DRIVER: Headless mode == #{HEADLESS_MODE}"  
   
   if HEADLESS_MODE == true  
    options.add_argument('--headless')  
    options.add_argument('--disable-gpu')  
    options.add_argument('--no-sandbox')  
    options.add_argument('--disable-dev-shm-usage')  
   end  
  
  Capybara::Selenium::Driver.new(app,  
           browser: :chrome,  
           options: options)  
  end  
   
  Capybara.configure do |config|  
   config.default_max_wait_time = timeout  
   config.ignore_hidden_elements = true  
  end  
 end  
   
 Gauge.configure do |config|  
  config.include DRIVER  
  config.screengrabber = -> {  
    Capybara.page.save_screenshot('/tmp/screenshot.png')  
    return File.binread('/tmp/screenshot.png')  
  }  
 end  

Copying and pasting the default.properties to a new local directory in the env folder, and adding on HEADLESS = false, we get:

env/default/default.properies
 gauge_reports_dir = reports  
 overwrite_reports = true  
 screenshot_on_failure = true  
 logs_directory = logs  
 enable_multithreading = false  
 gauge_clear_state_level = scenario  
 gauge_specs_dir = specs  
 csv_delimiter = ,  
 allow_multiline_step = false   

env/default/ruby.properties
 # sample_key = sample_value  
   
 HEADLESS = false  

Running the Headless Tests

Want to run the tests pulling the environment variables of the local environment, where tests are being run in Chrome regularly, where HEADLESS = false?
  • bundle exec gauge run specs/Navigation.spec -v
Want to switch it up and see if tests can be run headlessly?

Change that HEADLESS = true in the ruby.properties file.

Next, we will revisit the Authorization test scenarios we came up with when analyzing The-Internet.
Happy Testing!



-T.J. Maher

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

Twitter | YouTubeLinkedIn | Articles

No comments: