Search code examples
testingcapybara

How do you refute the presence of an option with Capybara's has_select?


Consider that you have a select list with just the following option:

<option>Second Fake Option</option>

And you'd like to assert that the select list does not contain an option with the text "Fake Option":

<option>Fake Option</option>

When one refutes this like so:

refute has_select?('list_id',
  with_options: ['Fake Option'])

The test fails. It seems that Capybara is successfully partially matching the text Fake Option against the text Second Fake Option. Even further, the following also fails:

refute has_select?('select_id',
  with_options: [''])

Yet the following passes:

refute has_select?('select_id',
  with_options: ['BORK'])

The documentation for with_options: and options: describes the behavior regarding the list of options we're trying to match, but does not speak to this behavior of partially matching the text itself. Other questions here on SO refer to the same documented behavior... but don't address refuting or the matching of the options' text.

While I could assert the opposite behavior with options:, like this:

assert has_select?('select_id',
  options: ['Second Fake Option'])

This can be a pain when you have a long select list and want to refute the presence of one particular option in the list.

How does one properly refute the presence of a specific option in a select list?


Solution

  • Partial text matching is the default behavior but can be overridden with the :exact option. Also rather than refuting a predicate, you should be calling refute_select -- the error messages will be much better

    refute_select('select_id', with_options: ['Fake Option'], exact: true)
    

    Note: this would also pass if there was no 'select_id' select element on the page, which may not be what you want. If you want to verify the select does exist but that it doesn't have a specific option then something like

    select = find_field('select_id')
    refute_selector(select, :option, 'Fake Option', exact:  true)
    

    may be what you want, which could also be done with matches as

    select = find_select('select_id')
    refute_matches_selector(select, :select, with_options['Fake Option'], exact: true)