Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Capybara, does :exact or Capybara.exact apply to have_selector?

I'm having difficulty using Capybara's have_selector when trying to match for an element where the text matches exactly. I know that this can be done using a regular expression, but my reading of Capybara's blog post led me to believe that I could use an :exact arg or set Capybara.exact = true. I am currently using Capybara 2.2.1. Here is what I have:

Assuming that I have a page (called "test page"). On this page is this:

<div id="my_div">abcdef</div>

I have a Cucumber feature test that looks like this:

Feature: Test for exact text matches in have_selector
Scenario:
  Given I am on the test page
  Then I should get a partial text match "bcde" in my div
  And I should get a partial text match "abcdef" in my div
  And I should get an exact text match using regexp "abcdef" in my div
  And I should not get an exact text match using regexp "bcde" in my div
  And I should get an exact text match using arg "abcdef" in my div
  And I should not get an exact text match using arg "bcde" in my div

My step definitions look like this:

Then /^I should get a partial text match "([^\"]*)" in my div$/ do |text|
  page.should have_selector('div#my_div', :text => text)
end

Then /^I should get an exact text match using regexp "([^\"]*)" in my div$/ do |text|
  page.should have_selector('div#my_div', :text => /^#{text}$/)
end

Then /^I should not get an exact text match using regexp "([^\"]*)" in my div$/ do |text|
  page.should_not have_selector('div#my_div', :text => /^#{text}$/)
end

Then /^I should get an exact text match using arg "([^\"]*)" in my div$/ do |text|
  page.should have_selector('div#my_div', :text => text, :exact => true)
end

Then /^I should not get an exact text match using arg "([^\"]*)" in my div$/ do |text|
  page.should_not have_selector('div#my_div', :text => text, :exact => true)
end

Contrary to my expectations, I got the following error:

And I should not get an exact text match using arg "bcde" in my div
expected not to find css "div#my_div" with text "bcde", found 1 match: "abcdef" (Capybara::ExpectationNotMet)

This leads me to believe that :exact => true is not doing anything in my have_selector call. I have similarly tried to set Capybara.exact = true in my test setup configurations, but this also does not seem to affect my tests that I way I would have expected.

Am I missing something? Or am I misunderstanding how this option is supposed to be used? I know that I can always use the regular expression syntax for matching an exact text string, but I would have thought that the :exact option is specifically for this kind of situation.

like image 883
Alvin S. Lee Avatar asked Dec 25 '22 10:12

Alvin S. Lee


1 Answers

There is an open feature request, Capybara Github Issue 1256, to have have_selector (and others) support exact text matching.

However, for now (in Capybara 2.x), the :exact option does not apply to the :text option. If I recall correctly, it is the following piece of code (from query.rb) that does the text option filtering. As you can see, there is no logic or consideration of the :exact option.

def matches_filters?(node)
  if options[:text]
    regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
    return false if not node.text(visible).match(regexp)
  end

As per the Capybara docs, the :exact option is actually to:

Control whether is expressions in the given XPath match exactly or partially

This is basically only used in the Capybara::Node::Actions, where the text (or id, name, etc.) is not specified as an option - ex:

# Will match links that exactly match 'Password'
click_link('Password', :exact => true)

# Will match links that contain the word 'Password' - ex 'Password Confirmation'
click_link('Password', :exact => false)
like image 55
Justin Ko Avatar answered May 01 '23 16:05

Justin Ko