Search code examples
cssselenium-webdriverselenium-chromedrivercapybarageckodriver

Different CSS results between geckodriver and ChromeDriver


I'm encountering a problem when validating CSS properties in my Capybara tests, each webdriver is returning the selector value in a different format.

In my project, a page contains an element that has a CSS property background-color as a hexadecimal value. A sample of the CSS looks like the following:

#selected-colour-red {
    background-color: #ff0000;

When the tests run, the webdrivers (for whatever reason I still don't understand) instead look for the RGB equivalent of this hexadecimal value. So, my Capybara tests analyse the input value and convert it to the corresponding RGB value, so that the RSpec matcher can compare it to what the webdriver sees:

And(/^I should see the colour "(.*?)"$/) do |colour|
  case colour
    when 'red'
      rgb_colour = 'rgb(255, 0, 0)'
    when 'green'
      rgb_colour = 'rgb(0, 255, 0)'
    when 'blue'
      rgb_colour = 'rgb(0, 0, 255)'
  selected_colour = page.find(:css, 'div#colours-grid div#selected-colour-' + colour)
  pp selected_colour.style('background-color')   # debug - see what property the webdriver returns
  expect(selected_colour.style('background-color')).to have_content(rgb_colour)
end

The pp line outputs what the webdriver sees when the test runs.

When I run the tests using the geckodriver, the results pass because the value the webdriver sees matches that within the test:

    And I should see the text "The selected colour is <colour>" # features/colours.feature:14

    Examples: 
      | colour |
{"background-color"=>"rgb(255, 0, 0)"}
      | red    |
{"background-color"=>"rgb(0, 255, 0)"}
      | green  |
{"background-color"=>"rgb(0, 0, 255)"}
      | blue   |
3 scenarios (3 passed)
15 steps (15 passed)
0m3.205s

However, chromerdriver tests fail because the CSS property returned is in a different rgba format:

 And I should see the text "The selected colour is <colour>" # features/colours.feature:14

    Examples: 
      | colour |
{"background-color"=>"rgba(255, 0, 0, 1)"}
      | red    |
      expected to find text "rgb(255, 0, 0)" in "{\"background-color\"=>\"rgba(255, 0, 0, 1)\"}" (RSpec::Expectations::ExpectationNotMetError)
      ./features/step_definitions/colours.rb:47:in `/^I should see the colour "(.*?)"$/'
      features/colours.feature:17:13:in `I should see the colour "red"'
{"background-color"=>"rgba(0, 255, 0, 1)"}
      | green  |
      expected to find text "rgb(0, 255, 0)" in "{\"background-color\"=>\"rgba(0, 255, 0, 1)\"}" (RSpec::Expectations::ExpectationNotMetError)
      ./features/step_definitions/colours.rb:47:in `/^I should see the colour "(.*?)"$/'
      features/colours.feature:18:13:in `I should see the colour "green"'
{"background-color"=>"rgba(0, 0, 255, 1)"}
      | blue   |
      expected to find text "rgb(0, 0, 255)" in "{\"background-color\"=>\"rgba(0, 0, 255, 1)\"}" (RSpec::Expectations::ExpectationNotMetError)
      ./features/step_definitions/colours.rb:47:in `/^I should see the colour "(.*?)"$/'
      features/colours.feature:19:13:in `I should see the colour "blue"'
3 scenarios (3 failed)
15 steps (3 failed, 3 skipped, 9 passed)
0m2.051s

I don't want to write driver-specific code as that is difficult to maintain.

  • Should I write the expectation to use a regular expression as a matcher?
  • Is there a way to alter the format that chromium or firefox use for representing RGB values?
  • Is it possible to write the test so that it explicitly matches the hexadecimal value in the CSS?
  • Why do the drivers represent this value differently?

Solution

  • You'd have to ask the writers of chromedriver and geckodriver why their return values are different, but it's likely because the spec is lax - https://www.w3.org/TR/webdriver/#get-element-css-value - and they've just chosen to return two different, but valid, values.

    No it is not possible to match the hexadecimal value in the CSS directly because that is not accessible to Capybara. The best solution is to use a regex, and you should be using the match_style matcher rather than calling style directly

    expect(selected_colour).to match_style('background-color' => /rgba?\(255, 0, 0(, 1)?\)/)
    

    Another option would be to use the style filter for the have_css matcher and just do it all at once

    expect(page).to have_css('div#colours-grid div#selected-colour-' + colour, style: { 'background-color' => /rgba?\(255, 0, 0(, 1)?\)/ } )