Rails, Capybara. Unable to check checkbox element

58 Views Asked by At

The following is Slim.

.checkboxes__item
  = f.check_box :insert_thumbnail, { checked: @article.new_record? || @article.insert_thumbnail, class: 'a-toggle-checkbox' }
  = f.label :insert_thumbnail, 'insert thumbnail?'

HTML

<input name="article[insert_thumbnail]" type="hidden" value="0">
<input class="a-toggle-checkbox" 
       type="checkbox" 
       value="1" 
       checked="checked" 
       name="article[insert_thumbnail]" 
       id="article_insert_thumbnail">
<label for="article_insert_thumbnail">insert thumbnail?</label>
</div>

I would like to check this checkbox in the E2E test, but it does not work.

check 'insert thumbnail?', visible: false
Error:
ArticlesTest#test_uncheck_checkbox_whether_to_display_thumbnail_in_body:
Selenium::WebDriver::Error::ElementNotInteractableError: element not interactable
  (Session info: headless chrome=117.0.5938.62)
    test/system/articles_test.rb:292:in `block in <class:ArticlesTest>'

I understand this error to mean that the element exists but cannot be manipulated.

Is this due to CSS? Or should I just pass an option other than visible to the check method?

.a-toggle-checkbox
  +size(0)
  display: block
  +position(fixed, left 0)
  opacity: 0
  overflow: hidden
  visibility: hidden
  • Set the visible option to true
uncheck 'insert thumbnail?', visible: true
Error:
ArticlesTest#test_uncheck_checkbox_whether_to_display_thumbnail_in_body:
Capybara::ElementNotFound: Unable to find visible checkbox "insert thumbnail?" that is not disabled
    test/system/articles_test.rb:292:in `block in <class:ArticlesTest>'
  • Scroll to
scroll_to 'insert thumbnail?'
uncheck 'insert thumbnail?', visible: false
  • find + click
find('label[for=article_insert_thumbnail]').click

=> I can click.But I want to use check/uncheck method.

1

There are 1 best solutions below

1
engineersmnky On BEST ANSWER

Due to the fact that your check boxes are not visible and you are are targeting the label element with your selector, I believe you just need to enable the automatic_label_click option.

Whether Element#choose, Element#check, Element#uncheck will attempt to click the associated <label> element if the checkbox/radio button are non-visible.

Capybara.configure do |config|
   config.automatic_label_click = true
end

Or pass that option explicitly to the check method e.g.

check 'insert thumbnail?', allow_label_click: true

Here is the actual method, which has a secondary attempt if this option is true, and the error is "catchable" which it is in your case (See below).

This will then look for the label and call click (which seems to work for you now)

def _check_with_label(selector, checked, locator,
                            allow_label_click: session_options.automatic_label_click, **options)
  options[:allow_self] = true if locator.nil?
  synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
    el = find(selector, locator, **options)
    el.set(checked)
  rescue StandardError => e
    raise unless allow_label_click && catch_error?(e)

    begin
      el ||= find(selector, locator, **options.merge(visible: :all))
      unless el.checked? == checked
        el.session
          .find(:label, for: el, visible: true, match: :first)
          .click(**(Hash.try_convert(allow_label_click) || {}))
      end
    rescue StandardError # swallow extra errors - raise original
      raise e
    end
  end
end

For Reference the "Catchable Errors" (catch_error?(e) #=> true) in this case would be:

Selenium::WebDriver::Error::StaleElementReferenceError
Selenium::WebDriver::Error::ElementNotInteractableError
Selenium::WebDriver::Error::InvalidSelectorError
Selenium::WebDriver::Error::ElementClickInterceptedError
Selenium::WebDriver::Error::NoSuchElementError 
Selenium::WebDriver::Error::InvalidArgumentError
Capybara::ElementNotFound