Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option matches should be strict #681

Closed
ghost opened this issue Apr 1, 2012 · 15 comments
Closed

Option matches should be strict #681

ghost opened this issue Apr 1, 2012 · 15 comments
Labels
Milestone

Comments

@ghost
Copy link

ghost commented Apr 1, 2012

I had trouble figuring out how to best test this outside of Rails, but this is my issue in a Rails 3.2.3, Rspec, Capybara (rack-test), Turnip setup.

If I have the following HTML:

<label>Day <select name="day">
  <option value="1">1</option>
  <option value="2">2</option>
  ...
  <option value="9">9</option>
  <option value="10">10</option>
  ...
  <option value="30">30</option>
  <option value="31">31</option>
</select></label>

This step:

select n.to_s, from: 'Day'

works as expected when n >= 10 and fails when n < 10 with the error:

Capybara::ElementNotFound:
no option with text '4' in the select box

If I replace the step with:

find('select[name="date"]').all('option').each_with_index do |option, i|
  puts option.value == (i + 1).to_s
end

It spits out a bunch of trues (as I would expect).

If I have the following HTML:

<label>Day <select name="day">
  <option value="a">a</option>
  <option value="b">b</option>
  ...
  <option value="y">y</option>
  <option value="z">z</option>
</select></label>

Then the step works as expected with (n any of the characters).

If I have the following HTML:

<label>Day <select name="day">
  <option value="01">01</option>
  <option value="02">02</option>
  ...
  <option value="09">09</option>
  <option value="10">10</option>
  ...
  <option value="30">30</option>
  <option value="31">31</option>
</select></label>

Then the step works as expected (with n the result of a date.strftime('%d')).

If someone could point my in a better direction with regards to testing outside of Rails, I'll see if I can better locate the issue behind my problem.

@nashby
Copy link
Contributor

nashby commented Apr 1, 2012

It's because when you're trying to find <option value="1">1</option> capybara matches not only <option value="1">1</option> but <option value="10">10</option> too. And then because of https://github.com/jnicklas/capybara/blob/master/lib/capybara/query.rb#L60 this if statement you're getting Capybara::ElementNotFound error as results.length == 2

@ghost
Copy link
Author

ghost commented Apr 1, 2012

I see, thanks. I was looking at the comments for #find, but it only mentioned throwing an error if the element wasn't found at all.

So, the default behavior is to match anything that contains the value (and not just starts with it, i.e. find(:option, '4') also matches <option value="14">14</option> ).

This doesn't seem obvious or intuitive (and perhaps that's just my xpath ignorance). But certainly a better error message can be shown when multiple matches are found. The error no option with text '4' in the select box sent me down all the wrong paths trying to figure this out.

But thanks again.

@jnicklas
Copy link
Collaborator

jnicklas commented Apr 1, 2012

Are you using Capybara master? I would recommend sticking with the latest gem release unless you're well informed about the changes that have happened since. master is not compatible with the 1.x branch.

@ghost
Copy link
Author

ghost commented Apr 2, 2012

Yes, I am. My main issue was with regards to the error messaging, which #682 may address. Regardless, I think that it makes more sense for #select to continue to use #first instead of #find (which I believe the current 1.x branch does). Feel free to close when necessary.

@greis
Copy link

greis commented Apr 27, 2012

Now that capybara validates that just one element matches your criteria, shouldn't be good to have a default configuration where you can choose if you want an exact or a partial match for the elements?
And capybara would change the xpath expression for each case:

Capybara.default_match_type = :partial 
.//option[contains(normalize-space(string(.)), '1')]

Capybara.default_match_type = :exact
.//option[text() = '1']

And also should have a way to override the default match type during execution if you want:

find(:option, '1', match: :exact)

@DouweM
Copy link
Contributor

DouweM commented Jun 18, 2012

+1 on @greis's suggestion.

@jnicklas
Copy link
Collaborator

I don't like the idea of an option to specify whether the match should be exact or not. On the other hand, it seems that with the current behaviour, we should probably switch to matching exactly.

@espen
Copy link
Contributor

espen commented Jan 8, 2013

I'm having a similar issue after upgrading from Capybara 1. click_link "Hello" gives error. It used to find "Hello", but now it finds 2 elements since I also have a "Hello world" link. @jnicklas writes that Capybara should probably switch to matching exactly. I assume this has not been done? Or is there a setting that I can use? Selecting the first link is not appropriate as I want the exact match and the exact match might not be the first link.

@jnicklas
Copy link
Collaborator

jnicklas commented Jan 8, 2013

Unfortunately, there is no such option yet.

@abotalov
Copy link
Collaborator

abotalov commented Jan 8, 2013

@jnicklas Do you think it will be good to have all Actions methods (where it makes sense) to find an exact match (if it exists) instead of the first one?

@jnicklas
Copy link
Collaborator

jnicklas commented Jan 8, 2013

Yes, but I'd rather solve this problem properly rather than breaking compatibility unnecessarily without arriving at a really good solution. I have some ideas, which I'll present to the mailing list at some point soon.

@espen
Copy link
Contributor

espen commented Feb 13, 2013

@jnicklas did you post your ideas on the mailing list? I was unable to find it. I think that exact should be the default but also happy with just being able to specify :match => :exact as @greis suggests.

@kellyfelkins
Copy link

I'm also experiencing this issue:

I'm having a similar issue after upgrading from Capybara 1.
click_link "Hello" gives error. It used to find "Hello", but now
it finds 2 elements since I also have a "Hello world" link.

@abotalov
Copy link
Collaborator

@kellyfelkins
Copy link

Thank you. Very helpful.

-Kelly

On Thu, Feb 14, 2013 at 1:25 PM, Andrey Botalov notifications@github.comwrote:

@espen https://github.com/espen See
http://www.elabs.se/blog/55-a-capybara-future


Reply to this email directly or view it on GitHubhttps://github.com//issues/681#issuecomment-13579462.

Kelly Felkins
about.me/kellyfelkins

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants