capybara: matches_xxx? fails when used with elements located using sibling selectors
Capybara version 3.3.1. Right now, matches_css? expects the CSS in the first argument to match fully the given element - that is, if I have a div.a.b.c the whole CSS should be passed in order for matches_css? to return true. Passing div.a for example or div or any other combination returns false. Having this ability would be nice.
Actually, I see no other way of doing exactly that apart from page.all(css, wait: 0).include?(element) which, however, is extremely slow when css is e.g. div because a million elements are returned from the browser.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 18 (11 by maintainers)
@boris-petrov Thanks for reporting this, and for producing the reproducible example. Having an example of the failure makes debugging and fixing things so much easier. Will probably release a fix as 3.4.2 later today, assuming tests pass, etc.
AHA – this happens because
matches_xxx?uses the current elementsquery_scope(the element that was the current scope when it was found) as the scope for finding all elements that match the passed CSS and then checking if the current element is one of them. This works fine when the current elementsquery_scopeis an ancestor (which it would be most of the time), but doesn’t work when a sibling is selected since itsquery_scopeis not an ancestor of the current element being checked. Easiest way to fix this would be to use the elements parent as the scope for searching in amatchesquery, need to think about whether that has any downsides.As for the ‘div’ difference, if that’s a bug it would be a bug in selenium or chromedriver/chrome - I would expect
<div class="b"></div>to report the error shown since the element takes up no space on the page and is therefore not visible and wouldn’t, by default, be located by find. With any whitespace contents of the<div>I believe it should actually behave the same way and raise the error since whitespace is stripped and Chrome still reports the element as having 0px height but the element is reported as visible. I’m guessing this may be a bug in selenium but haven’t looked in depth far enough to say that for sure - but I can say it’s not a Capybara issue.@luke-hill - printing
following_siblingprints the correct element:#<Capybara::Node::Element tag="div" path="/HTML/BODY/DIV[2]">In the documentation it is not written that
findfinds only child elements. In any case, the following also does not work:This also prints the same element and also
false.Thirdly, the exception that I pasted above still happens in some cases and is another bug.
Your locator is looking inside the
div.a.Inside the
div.athere are nodivitems defined.You want the following locator
div.a + divordiv.a + .b