ruby-on-railscapybara

Rails, Capybara. Unable to check checkbox element


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
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 'insert thumbnail?'
uncheck 'insert thumbnail?', visible: false
find('label[for=article_insert_thumbnail]').click

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


Solution

  • 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