Ruby Webdriver SDK

The Evinced Ruby WebDriver SDK integrates with new or existing WebDriver tests to automatically detect accessibility issues. With the addition of as few as 5 lines of code to your WebDriver framework, you can begin to analyze all the pages and DOM changes to offer a dynamic view of how your site can become more accessible. At the conclusion of the test, a rich and comprehensive JSON or HTML report is generated to track issues in any reporting tool.

Interested in seeing this in action? Contact us to get started!

Prerequisites

  • Ruby version 2.6.3 or higher
  • selenium-webdriver gem 4.0.1 or higher
  • ChromeDriver

Get Started

Installation

1gem install selenium-webdriver
2gem install evinced-rubysdk --source https://<USER>:<PASSWORD>@evinced.jfrog.io/artifactory/api/gems/private-ruby

To avoid using plain text password you can generate an encrypted password in your JFrog profile.

If there is an issue ERROR: While executing gem

... (Gem::RemoteFetcher::FetchError)
bad response Not Found 404 please update the gem package manager
gem update --system
. We observed such an issue on gem version 3.2.3.

Initialize the SDK

The only command you need to add to add Evinced SDK to your code is

1require 'evinced/rubysdk'

Evinced uses the selenium-webdriver gem which will be added automatically.

All Evinced commands will be attached to the driver object upon initialization using the Selenium::WebDriver.for command.

Your first test

Basic single page analysis

1#filename: evinced_demo.rb
2require 'evinced/rubysdk'
3
4driver = Selenium::WebDriver.for :chrome
5driver.get 'https://ruby-doc.org/'
6#Scan for accessibility issues
7issues = driver.ev_analyze
8#Save the Evinced Acceessibility report
9driver.ev_save_file

Run this code with the command ruby evinced_demo.rb

Basic multiple page analysis

1require 'evinced/rubysdk'
2
3driver = Selenium::WebDriver.for :chrome
4issues = driver.ev_analyze_with do
5 driver.get 'https://ruby-doc.org/'
6 driver.get 'https://ruby-doc.org/core-3.1.0/File.html'
7end
8# You are able to change default destination and format
9driver.ev_save_file destination: '/tmp/evinced-results.yaml', format: :yaml

Run this code with the command ruby evinced_demo.rb

RSpec single page analysis(Single Run Mode)

1#filename: evinced_rspec_demo_spec.rb
2
3require 'evinced/rubysdk'
4
5describe 'Evinced RSpec example' do
6 it 'gathers issues with ev_analyze' do
7 driver = Selenium::WebDriver.for :chrome
8 driver.get 'https://ruby-doc.org/'
9 issues = driver.ev_analyze
10 expect(issues.size).to be > 0
11 expect(issues).not_to be_ev_valid
12 end
13end

Run this code with the command rspec evinced_rspec_demo_spec.rb

RSpec continuous analysis (Continuous Mode)

The ev_start command can be used to to start the Evinced engines running in the background. This will automatically detect dynamic elements and new pages and scan them for accessibility issues. The ev_stop command is used to stop Evinced at the conclusion of the test.

1#filename: evinced_rspec_demo_spec.rb
2
3require 'evinced/rubysdk'
4
5describe 'Evinced rspec example' do
6 it 'gathers issues with ev_start and ev_stop' do
7 driver = Selenium::WebDriver.for :chrome
8 driver.ev_start
9
10 url1, url2 = %w[https://ruby-doc.org/ https://ruby-doc.org/core-3.1.0/File.html]
11 driver.get url1
12 driver.get url2
13
14 driver.ev_stop
15
16 expect(Evinced::Rubysdk::OVERALL_RESULT[url1].size).to be > 0
17 expect(Evinced::Rubysdk::OVERALL_RESULT[url2].size).to be > 0
18 end
19end

Run this code with the command rspec evinced_rspec_demo_spec.rb

RSpec multiple page analysis (Multiple Page Mode)

1#filename: evinced_rspec_demo_spec.rb
2
3require 'evinced/rubysdk'
4
5describe 'Evinced rspec example' do
6 it 'gathers issues with ev_start and ev_stop' do
7 driver = Selenium::WebDriver.for :chrome
8 url1, url2 = %w[https://ruby-doc.org/ https://ruby-doc.org/core-3.1.0/File.html]
9
10 driver.ev_analyze_with do
11 driver.get url1
12 driver.get url2
13 end
14
15 expect(Evinced::Rubysdk::OVERALL_RESULT[url1].size).to be > 0
16 expect(Evinced::Rubysdk::OVERALL_RESULT[url2].size).to be > 0
17 end
18end

Run this code with the command rspec evinced_rspec_demo_spec.rb

It’s exactly the same test as seen with continuous mode but the ev_analyze_with command surrounds the code block with ev_start and ev_stop commands being called in the background.

API

ev_analyze(options={}) -> array

Scans the current page and returns an array containing accessibility issues or an empty array. This is the recommended method for static page analysis. For more information regarding reports as well as the Report object itself, please see our detailed Web Reports page. Note: This method is not supported if ev_start is already running.

Example:

1issues = @driver.ev_analyze(root_selector: '#some .selector')
2expect(issues.size).to eql 2

Default options

1root_selector: nil # css selector - set to scan only a subset of the DOM or nil

ev_start(opts={}) -> nil

Continually watches for DOM mutations and page navigation and records all accessibility issues until the ev_stop method is called. This method is recommended for dynamic page flows. Returns nil.

Example:

1 @driver.get 'http://example.com'
2 @driver.ev_start
3 expect(@driver.ev_stop.size).to eql 6

Default options:

1root_selector: nil # css selector - set to scan only a subset of the DOM or nil

ev_stop -> array

Stops accessibility scans initiated by the ev_start command. Returns an array containing accessibility issues or empty array. For more information regarding reports as well as the Report object itself, please see our detailed Web Reports page.

Example:

1 @driver.get 'http://example.com'
2 @driver.ev_start
3 @driver.find_element(css: '#some.selector').click
4 @driver.find_element(xpath: '//div[@class="clickable"]').click
5 issues = @driver.ev_stop
6 expect(issues.size).to be > 0
7 expect(issues).not_to be_ev_valid

ev_analyze_with(opts={}, &blk) -> array

Surrounds a code block with ev_start and ev_stop commands. Returns the array returned by ev_stop command.

Example:

1 @driver.get 'http://example.com'
2 issues = @driver.analyze_with do
3 @driver.find_element(css: '#some.selector').click
4 @driver.find_element(xpath: '//div[@class="clickable"]').click
5 end
6 expect(issues.size).to be > 0
7 expect(issues).not_to be_ev_valid

Default options:

See ev_start options

ev_save_file(destination: 'evinced-results.json', format: :json, report: nil)

Stores the results in the file.

Example:

1 issues = @driver.ev_analyze
2 @driver.ev_save_file destination: '/tmp/evinced.json'

Arguments

1destination: 'evinced-results.json' # path to the file where to store results
2format: :json # output format, :json by default. :yaml and html are also supported
3report: nil # the report to store. Optional. Will store the daefault report object.

Evinced.save_file(destination: 'evinced-results.json', format: :json)

Stores the results in the file. Similar to ev_save_file but can be used in context where the Selenium Webdriver object is not initialized. Works only for complete report gathered during the run.

Example:

1RSpec.configure do |config|
2 config.after :suite do
3 Evinced.save_file destination: 'results.json'
4 end
5end

Custom configuration

set_options(options)

Give an ability to override (not merge!) global Evinced configuration.

Example:

1Evinced.set_options(JSON.load 'custom-evinced-config.json')

Updating global options

Setting ruby_sdk specific options

1Evinced.global_config.ruby_sdk[:LOGGER_ON] = true

Updating axe configuration

1Evinced.global_config.plugins.axe[:resultTypes] = ['violations']
2
3# It'll replace default rules
4Evinced.global_config.plugins.axe[:rules] = {
5 'document-title': { enabled: false },
6 'html-has-lang': { enabled: true },
7}
8
9# It'll add/replace axe rules
10Evinced.global_config.plugins.axe.rules['document-title'] = { enabled: true }
11Evinced.global_config.plugins.axe.rules['accesskeys'] = { enabled: false }

Updating global rootSelector option

1Evinced.global_config[:rootSelector] = "#my-top-level-selector"

Restoring default options

1Evinced::Rubysdk::EvincedConfig.restore_default

Note that this command restores configuration to SDK default one. Be careful if you are using set_options command to override default SDK configuration.

Tutorials

1. Initial tests

1#filename: evinced_tutorial_spec.rb
2
3require 'selenium-webdriver'
4
5EVICED_DEMO_SITE = 'https://demo.evinced.com/'
6ANOTHER_PAGE_ON_DEMO_SITE = 'https://demo.evinced.com/results/?what=Caravan&where=Canada&date=Mon%20Mar%2029%202021%2011:38:30%20GMT+0300%20(Israel%20Daylight%20Time)'
7
8BASE_SELECTOR = '#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container'
9SELECT_HOME_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(1) > div > div.dropdown.line"
10SELECT_WHERE_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(2) > div > div.dropdown.line"
11TINY_HOME_OPTION = "#{BASE_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)"
12EAST_COAST_OPTION = "#{BASE_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)"
13
14describe 'evinced demo site' do
15 before :all do
16 @driver = Selenium::WebDriver.for :chrome
17 Selenium::WebDriver::Wait.new(timeout: 10)
18 end
19
20 after :all do
21 @driver.quit
22 end
23
24 it 'has clickable home selector' do
25 @driver.get EVICED_DEMO_SITE
26 @driver.find_element(css: SELECT_HOME_DROPDOWN).click
27 @driver.find_element(css: TINY_HOME_OPTION).click
28 end
29
30 it 'has clickable where selector' do
31 @driver.get EVICED_DEMO_SITE
32 @driver.find_element(css: SELECT_WHERE_DROPDOWN).click
33 @driver.find_element(css: EAST_COAST_OPTION).click
34 end
35
36 it 'has another page' do
37 @driver.get ANOTHER_PAGE_ON_DEMO_SITE
38 expect(@driver.current_url).to eql(ANOTHER_PAGE_ON_DEMO_SITE)
39 end
40end

Run this code snipped with rspec evinced_tutorial_spec.rb

2. Add evinced SDK to your tests

1#filename: evinced_tutorial_spec.rb
2
3require 'selenium-webdriver'
4require 'evinced/rubysdk' # <---- Only one line of code is added
5
6EVICED_DEMO_SITE = 'https://demo.evinced.com/'
7ANOTHER_PAGE_ON_DEMO_SITE = 'https://demo.evinced.com/results/?what=Caravan&where=Canada&date=Mon%20Mar%2029%202021%2011:38:30%20GMT+0300%20(Israel%20Daylight%20Time)'
8
9BASE_SELECTOR = '#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container'
10SELECT_HOME_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(1) > div > div.dropdown.line"
11SELECT_WHERE_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(2) > div > div.dropdown.line"
12TINY_HOME_OPTION = "#{BASE_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)"
13EAST_COAST_OPTION = "#{BASE_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)"
14
15describe 'evinced demo site' do
16 before :all do
17 @driver = Selenium::WebDriver.for :chrome
18 Selenium::WebDriver::Wait.new(timeout: 10)
19 end
20
21 after :all do
22 @driver.quit
23 end
24
25 it 'has clickable home selector' do
26 @driver.get EVICED_DEMO_SITE
27 @driver.find_element(css: SELECT_HOME_DROPDOWN).click
28 @driver.find_element(css: TINY_HOME_OPTION).click
29 end
30
31 it 'has clickable where selector' do
32 @driver.get EVICED_DEMO_SITE
33 @driver.find_element(css: SELECT_WHERE_DROPDOWN).click
34 @driver.find_element(css: EAST_COAST_OPTION).click
35 end
36
37 it 'has another page' do
38 @driver.get ANOTHER_PAGE_ON_DEMO_SITE
39 expect(@driver.current_url).to eql(ANOTHER_PAGE_ON_DEMO_SITE)
40 end
41end

Please see line 4 above. It’s the only line you need to add to your code to include the Evinced ruby SDK. Optionally, line 3 could be omitted because the Evinced SDK requires Selenium WebDriver implicitly.

3. Activate accessibility issue gathering and store results in file

1#filename: evinced_tutorial_spec.rb
2
3require 'selenium-webdriver'
4require 'evinced/rubysdk'
5
6EVICED_DEMO_SITE = 'https://demo.evinced.com/'
7ANOTHER_PAGE_ON_DEMO_SITE = 'https://demo.evinced.com/results/?what=Caravan&where=Canada&date=Mon%20Mar%2029%202021%2011:38:30%20GMT+0300%20(Israel%20Daylight%20Time)'
8
9BASE_SELECTOR = '#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container'
10SELECT_HOME_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(1) > div > div.dropdown.line"
11SELECT_WHERE_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(2) > div > div.dropdown.line"
12TINY_HOME_OPTION = "#{BASE_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)"
13EAST_COAST_OPTION = "#{BASE_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)"
14
15describe 'evinced demo site' do
16 before :all do
17 @driver = Selenium::WebDriver.for :chrome
18 Selenium::WebDriver::Wait.new(timeout: 10)
19 end
20
21 after :all do
22 @driver.quit
23 end
24
25 before :each do
26 @driver.ev_start
27 end
28
29 after :each do
30 @driver.ev_stop
31 end
32
33 after :all do
34 @driver.ev_save_file destination: 'evinced-tutorial-results.json'
35 end
36
37 it 'has clickable home selector' do
38 @driver.get EVICED_DEMO_SITE
39 @driver.find_element(css: SELECT_HOME_DROPDOWN).click
40 @driver.find_element(css: TINY_HOME_OPTION).click
41 end
42
43 it 'has clickable where selector' do
44 @driver.get EVICED_DEMO_SITE
45 @driver.find_element(css: SELECT_WHERE_DROPDOWN).click
46 @driver.find_element(css: EAST_COAST_OPTION).click
47 end
48
49 it 'has another page' do
50 @driver.get ANOTHER_PAGE_ON_DEMO_SITE
51 expect(@driver.current_url).to eql(ANOTHER_PAGE_ON_DEMO_SITE)
52 end
53end

Please review the new lines from 25 till 35. This code will activate accessibility issues gathering before each test and stop it after test. You can add it into rspec_helper.rb to apply to all spec files in your test suite.

The new after :all block stores results in the file.

4. Store results in after :suite once

The previous code snippet shows how to store results after running each test in the spec file. It is possible to save a separate report for each test, but usually it is more convenient to create a single consolidated report once all the tests are complete. RSpec has an after :suite hook, however it is likely that the driver object is not initialized there. In this case the Evinced.save static method can be used.

1#filename: evinced_tutorial_spec.rb
2
3require 'selenium-webdriver'
4require 'evinced/rubysdk'
5
6EVICED_DEMO_SITE = 'https://demo.evinced.com/'
7ANOTHER_PAGE_ON_DEMO_SITE = 'https://demo.evinced.com/results/?what=Caravan&where=Canada&date=Mon%20Mar%2029%202021%2011:38:30%20GMT+0300%20(Israel%20Daylight%20Time)'
8
9BASE_SELECTOR = '#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container'
10SELECT_HOME_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(1) > div > div.dropdown.line"
11SELECT_WHERE_DROPDOWN = "#{BASE_SELECTOR} > div:nth-child(2) > div > div.dropdown.line"
12TINY_HOME_OPTION = "#{BASE_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)"
13EAST_COAST_OPTION = "#{BASE_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)"
14
15describe 'evinced demo site' do
16 before :all do
17 @driver = Selenium::WebDriver.for :chrome
18 Selenium::WebDriver::Wait.new(timeout: 10)
19 end
20
21 after :all do
22 @driver.quit
23 end
24
25 before :each do
26 @driver.ev_start
27 end
28
29 after :each do
30 @driver.ev_stop
31 end
32
33 it 'has clickable home selector' do
34 @driver.get EVICED_DEMO_SITE
35 @driver.find_element(css: SELECT_HOME_DROPDOWN).click
36 @driver.find_element(css: TINY_HOME_OPTION).click
37 end
38
39 it 'has clickable where selector' do
40 @driver.get EVICED_DEMO_SITE
41 @driver.find_element(css: SELECT_WHERE_DROPDOWN).click
42 @driver.find_element(css: EAST_COAST_OPTION).click
43 end
44
45 it 'has another page' do
46 @driver.get ANOTHER_PAGE_ON_DEMO_SITE
47 expect(@driver.current_url).to eql(ANOTHER_PAGE_ON_DEMO_SITE)
48 end
49end
50
51RSpec.configure do |config|
52 config.after :suite do
53 Evinced.save_file destination: 'evinced-tutorial-results.html', format: 'html'
54 end
55end

Support

Please feel free to reach out to support@evinced.com with any questions.

FAQ

  1. Do you have support for languages other than Ruby?
    Yes! We have SDK versions for Java, Cypress and WebdriverIO. We have implementations for Python and C# coming soon.
  2. Can I configure which validations to run?
    Yes, see the API section for details on how to configure validations to your needs.
  3. Can I run tests with Evinced using cloud-based services like Sauce Labs, Perfecto, or BrowserStack?
    Yes, we have tested the Evinced SDK on many of these types of cloud-based services and expect no issues.