Improve failure message when text is present but invisible.

When testing a page with JS that hides and shows
certain elements, it's useful to know whether a
test failure means that an element has failed to
render, or has rendered but become invisible (or
failed to become visible).

For instance, some jQuery plugins will take
existing elements and hide them, adding some other
elements onto the page that use the originals as
storage. If your tests are written to use the
now-hidden elements they will mysteriously start
failing.

This commit only changes the behavior for failed
tests (rspec and assert) and only for text
queries. It might be nice to extend this to the
other finders.
This commit is contained in:
Alex Chaffee 2015-11-02 08:04:20 -08:00 committed by Thomas Walpole
parent eaf1a61238
commit 51c83ed5a9
4 changed files with 52 additions and 7 deletions

View File

@ -501,7 +501,7 @@ module Capybara
#
# @!macro text_query_params
# @overload $0(type, text, options = {})
# @param [:all, :visible] type Whether to check for only visible or all text
# @param [:all, :visible] type Whether to check for only visible or all text. If this parameter is missing or nil then we use the value of `Capybara.ignore_hidden_elements`, which defaults to `true`, corresponding to `:visible`.
# @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
# @option options [Integer] :count (nil) Number of times the text is expected to occur
# @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur

View File

@ -15,11 +15,22 @@ module Capybara
end
def resolve_for(node)
@actual_text = Capybara::Helpers.normalize_whitespace(node.text(@type))
@node = node
@actual_text = text(node, @type)
@count = @actual_text.scan(@search_regexp).size
end
def failure_message
build_message(true)
end
def negative_failure_message
build_message(false).sub(/(to find)/, 'not \1')
end
private
def build_message(check_invisible)
description =
if @expected_text.is_a?(Regexp)
"text matching #{@expected_text.inspect}"
@ -32,17 +43,31 @@ module Capybara
message << " but found #{@count} #{Capybara::Helpers.declension('time', 'times', @count)}"
end
message << " in #{@actual_text.inspect}"
end
def negative_failure_message
failure_message.sub(/(to find)/, 'not \1')
end
if @node and visible? and check_invisible
invisible_text = text(@node, :all)
invisible_count = invisible_text.scan(@search_regexp).size
if invisible_count != @count
message << ". (However, it was found #{invisible_count} time#{'s' if invisible_count != 1} including invisible text.)"
end
end
private
message
end
def valid_keys
COUNT_KEYS + [:wait]
end
def visible?
@type == :visible or
(@type.nil? and (Capybara.ignore_hidden_elements or Capybara.visible_text_only))
end
def text(node, query_type)
Capybara::Helpers.normalize_whitespace(node.text(query_type))
end
end
end
end

View File

@ -37,6 +37,14 @@ Capybara::SpecHelper.spec '#assert_text' do
expect(@session.assert_text('Some of this text is hidden!')).to eq(true)
end
it "should raise error with an helpful message if the requested text is present but invisible." do
@session.visit('/with_html')
el = @session.find(:css, '#hidden-text')
expect do
el.assert_text(:visible, 'Some of this text is hidden!')
end.to raise_error(Capybara::ExpectationNotMet, /However, it was found 1 time including invisible text/)
end
it "should be true if the text in the page matches given regexp" do
@session.visit('/with_html')
expect(@session.assert_text(/Lorem/)).to eq(true)
@ -166,6 +174,14 @@ Capybara::SpecHelper.spec '#assert_no_text' do
end.to raise_error(Capybara::ExpectationNotMet, 'expected not to find text "Some of this text is hidden!" in "Some of this text is hidden!"')
end
it "should raise error if :all given and text is invisible." do
@session.visit('/with_html')
el = @session.find(:css, '#some-hidden-text', visible: false)
expect do
el.assert_no_text(:visible, 'hidden')
end.to raise_error(Capybara::ExpectationNotMet, 'expected not to find text "hidden" in "Some of this text is not hidden"')
end
it "should be true if the text in the page doesn't match given regexp" do
@session.visit('/with_html')
@session.assert_no_text(/xxxxyzzz/)

View File

@ -79,6 +79,10 @@ banana</textarea>
Some of this text is <em style="display:none">hidden!</em>
</div>
<div id="some-hidden-text">
Some of this text is not hidden <em style="display:none">and some is hidden</em>
</div>
<div style="display: none;">
<a id="first_invisble" class="hidden">first hidden link</a>
</div>