DaniG2k
DaniG2k

Reputation: 4893

RSpec + headless Chrome for front-end integration test

I'm trying to test a part of my Rails 5.1 app that makes use of Vue.js. The issue I'm encountering is that, for example when generating a list, the Vue code looks like:

<div v-for="(amenity, idx) in amenities">
  <div class="custom-control custom-checkbox">
    <input type="checkbox" class="custom-control-input" v-bind:id="amenity.text" v-model="checkedAmenities[idx]" :value="amenity.id">
    <label class="custom-control-label" v-bind="{ 'for': amenity.text }" >{{ amenity.text }}</label>
  </div>
</div>

and the actual HTML that this produces once evaluated looks like this:

<div>
  <div class="custom-control custom-checkbox">
    <input id="Air conditioning" class="custom-control-input" value="0" type="checkbox"> <label for="Air conditioning" class="custom-control-label">Air conditioning</label>
  </div>
</div>

I end up getting this error in my specs:

Capybara::ElementNotFound:
  Unable to find visible checkbox "Some amenity" that is not disabled

This is because the amenities are defined in the Vue component but are not output in the HTML until they are parsed by the JS interpreter I believe.

I am trying to test with Chrome Headless. I've created the following chrome_driver.rb file:

Capybara.register_driver(:headless_chrome) do |app|
  capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
    chromeOptions: { args: %w[headless disable-gpu] }
  )

  Capybara::Selenium::Driver.new(
    app,
    browser: :chrome,
    desired_capabilities: capabilities
  )
end

and in my rails_helper.rb:

require 'selenium/webdriver'

RSpec.configure do |config|
  # ...
  Capybara.javascript_driver = :headless_chrome
end

my RSpec test looks something like this:

scenario 'successfully', js: true do
  # do some things here..

  check('Some amenity')
  click_button 'Next'
  click_link 'Create Listing'

  expect(page).to have_content 'Listing was created successfully!'
end

but as mentioned, the error I get is:

Capybara::ElementNotFound:
  Unable to find visible checkbox "Some amenity" that is not disabled

Any idea how I can get Chrome headless to parse the Vue.js code so that the amenities get populated on the frontend?

Thanks in advance!!

Upvotes: 1

Views: 1036

Answers (2)

Zoran Kikic
Zoran Kikic

Reputation: 247

If your label contains a link it will be clicked and not the check box itself:

check('Some amenity', allow_label_click: true)

You can solve it this way:

check('Some amenity', visible: :hidden)

Upvotes: 0

Thomas Walpole
Thomas Walpole

Reputation: 49890

Judging by the class names of the wrapping div, custom-control custom-checkbox, I'm pretty certain the issue here isn't that the fields aren't being populated correctly (you can use save_and_open_screenshot to verify that, or output page.html) but rather the actual html <input type="checkbox" ...> element is not actually visible on the page (as the error tells you). This was probably done in order to provide a fancy styling to the checkbox by showing images for the checked/unchecked states. To check the checkbox in that case you have a couple of options. The first option is to figure out what element the user actually needs to click to change the setting, and have Capybara do that. For instance

find(:label, 'Some amenity').click

The cleaner solution, when there is a correctly associated label element, is to tell the check method it's allowed to click the label if it needs to

check('Some amenity', allow_label_click: true)

If you want check, uncheck, and choose to always be allowed to click the associated label when a checkbox/radio button is hidden you can make that the default by setting

Capybara.automatic_label_click = true

Upvotes: 2

Related Questions