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

has_content matches hidden elements w/ Capybara.ignore_hidden_elements #81

Closed
nruth opened this issue May 24, 2010 · 20 comments
Closed
Labels

Comments

@nruth
Copy link
Contributor

nruth commented May 24, 2010

Since discovering how easy @javascript makes it to test js I've started doing some PE of an existing app with prototype/scriptaculous/lowpro, but have come upon some issues with hidden elements.

Following up from this group posting and my own troubles with this feature/scenarios/stepdefs on selenium, I have produced a feature branch w/ 2 failing specs tested in the rack-test and selenium session specs (I don't have the other bits and bobs installed, sorry).

I'm going to have a poke about the capybara code, but not sure whether I'll get very far with it.

I wonder if it's just a setting not being passed somewhere or other for has_content, since the find matchers seem to be working as expected when turning ignore_hidden_elements on/off.

@tinomen
Copy link

tinomen commented Aug 2, 2010

ignore_hidden_elements doesn't seem to change anything for my tests using @Selenium. While I do see the element disappear in the browser as the test runs the test fails on "And I should not see "Billing Address". Changing this to "And I should see "Billing Address" passes. I've yet to find a solution.

@vidmantas
Copy link

Same here, ignore_hidden_elements setting doesn't make any change in this situation. Looking for a solution

EDIT: I've investigated a bit - it filters visible/not visible elements actually GOOD, BUT that selector of content returns bunch of nodes that don't contain the text that we're matching. It returns that node too but filters out as invisible, other shouldnt-be-there nodes are left out so are not counted correctly

@suan
Copy link

suan commented Oct 14, 2010

Yeah ignoring hidden elements is a big reason why I wanted to use integration testing and Capybara. Hopefully it gets fixed soon.

@neerajsingh0101
Copy link

Today I came across https://github.com/alexdunae/premailer/blob/master/lib/premailer/html_to_plain_text.rb . premailer internally uses https://github.com/alexdunae/css_parser to bring all the css properties inline.

Right now the issue with "display:none" through css is that capybara only looks for "display:none" as inline style.

With premailer/css_parse all the css properties are brought to inline and then check for "display:none" will render right result.

Just a thought that popped up in my head when I saw premailer. What say.

@bjornblomqvist
Copy link
Contributor

If any one is interested, this is my quick fix.

Then /^(?:|I )should not see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, selector|
wait_until do

  its_hidden = page.evaluate_script("$('#{selector}:contains(#{text})').is(':hidden');")
  its_not_in_dom = page.evaluate_script("$('#{selector}:contains(#{text})').length == 0;")
  (its_hidden || its_not_in_dom).should be_true

end
end

@vidmantas
Copy link

But have to use selector which is not "human-friendly"... so cucumber steps one step further from its one of purposes :-)

@bjornblomqvist
Copy link
Contributor

My quick fix doesn't need a selector. If thats what you are commenting on.

@sriprasanna
Copy link

@bjornblomqvist your quick fix works perfectly. Thanks for that :)

@bilts
Copy link

bilts commented Nov 30, 2010

The workaround has a couple of issues. It doesn't correctly handle cases where two elements have the same text but only one is visible. Also, I ran into cases where jQuery was mis-reporting elements as being ':visible' in the same way as celerity. This is the workaround that I ended up with. I realize it's hideous.

Then /^(?:|I )should see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, locator| #"
  if Capybara.current_driver == :celerity
    wait_until do
      script = "var containsText = $('#{locator} :contains(#{text}), #{locator}:contains(#{text})');
        var leaves = containsText.not(containsText.parents()).filter(':visible');
        leaves.filter(function() {return !$(this).parents().is(':hidden');}).length > 0;"

      page.evaluate_script(script).should be_true
    end
  else
    with_scope(locator) do
      page.should have_content(text)
    end
  end
end

In English: filter locator and all of the elements under locator, looking for elements containing the search string. We only care about the lowest nodes, so remove any parent nodes from the search. Filter that list down to the list of visible nodes containing the search text. Finally, to work around the Celerity bug, filter out "visible" nodes which have an ancestor which is hidden.

edit Performance was too slow on huge pages when the caller doesn't provide a locator. Updated the code so its performance is better.

@jnicklas
Copy link
Collaborator

I don't think there is any really good way of handling this right now. This issue doesn't really help us, unless someone can provide any working fix. If you really want this, please reopen with a pull request.

@twcamper
Copy link

twcamper commented Mar 5, 2012

It looks like we need to be passing Capybara.ignore_hidden_elements along to XPath::HTML.
In XPath 0.1.4, see lib/xpath/html.rb:40. That's where attribute 'hidden' is hardcoded into an xpath 'not()'.

I can hack around this with something like:

# lib/capybara/node/finders.rb
def first(*args)
   . . .  
   selector.xpaths.each do |path|
     if Capybara.ignore_hidden_elements
       path.gsub!("or ./@type = 'hidden'", "")
     end
     . . .
   end
   . . .
end

but that's not pretty at all.

@jnicklas
Copy link
Collaborator

jnicklas commented Mar 5, 2012

Check Capybara's master, we've improved on this a lot, and it's now a lot less inconsistent.

@edrex-janrain
Copy link

Hidden elements are properly ignored by have_content in capybara/master, regardless of ignore_hidden_elements setting, at least using the capybara-webkit driver. This seems like the semantically-correct behavior, since have_content seems to address what the user sees, not what elements are in the DOM.

@jnicklas perhaps a new release is in order? This is a blocker for me using Capybara for JS testing, and while I can just use the :git option in Gemfile, the Capybara repo is 6.2MB and Bundler doesn't do --depth so I hesitate to foist it on my teammates.

@marcandre
Copy link

+1 for a release. I wasted hours trying to understand why have_{no}_content was seeing invisible text and trying to circumvent that. Only upside is I now know more about XPath...

@marcandre
Copy link

I was not successful in upgrading to current master. I had to also upgrade capybara-webkit, as the last official release appears to not be compatible with capybara master. I don't know which of the two is responsible, but I was getting intermittent errors.

I focused on a ultra basic integration spec with 5 scenarios. All five begin by calling the same login helper. I turned of the layout for that login screen, so no javascript whatsoever is taking place. Most of the times, but not all the time, the last two would fail to login. No error, fields are filled in but form is not posted. Sometimes all 5 pass, sometimes the last 2 fail.

After reverting to the last official version (1.1.2 and 0.12.1), I never get a failure.

So my dream at this point is an official release of capybara that provides exactly one thing: has_{no_}_content? which checks for the visibility of the content.

BTW, the doc in master still states there is a difference between has_content? and has_text?.

Thanks

@marcandre
Copy link

Could you please reopen this issue, or else should I follow another issue? Thanks.

@chazu
Copy link

chazu commented Jun 14, 2012

I too would be interested in a solution to this issue.

@marcandre
Copy link

@chazu For now, you can copy paste the has_{no_}text methods from https://github.com/jnicklas/capybara/blob/master/lib/capybara/node/matchers.rb , along with normalize_whitespace and things should work

@outerim
Copy link

outerim commented Jun 22, 2012

The code for has_{no_}text methods include the following comment:

Unlike has_content this only matches displayable text and specifically

excludes text contained within non-display nodes such as script or head tags.

And then has_{no_}content is aliased to has_{no_}text. Was that an oversight?

@jnicklas
Copy link
Collaborator

Yes, that's an oversight.

@lock lock bot locked and limited conversation to collaborators Aug 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests