1
0
Fork 0
mirror of https://github.com/teamcapybara/capybara.git synced 2022-11-09 12:08:07 -05:00

add has_text matcher based on Element#text

This commit is contained in:
Mark Dodwell 2011-10-16 16:46:19 -07:00
parent 0c3f377fc4
commit 9fb05c9c64
6 changed files with 250 additions and 17 deletions

View file

@ -367,6 +367,7 @@ certain elements, and working with and manipulating those elements.
page.has_xpath?('//table/tr')
page.has_css?('table tr.foo')
page.has_content?('foo')
page.has_text?('foo')
You can use these with RSpec's magic matchers:
@ -376,8 +377,14 @@ You can use these with RSpec's magic matchers:
page.should have_xpath('//table/tr')
page.should have_css('table tr.foo')
page.should have_content('foo')
page.should have_no_content('foo')
page.should have_text('foo')
page.should have_no_text('foo')
Note that there are 2 matchers for checking content/text. <tt>page.has_text?('foo')</tt>
will check only for text that is displayable, whereas <tt>page.has_content?('foo')</tt> will
check for the content within any nodes (including the head section and within script tags).
Most of the time you'll want the behaviour of <tt>page.has_text?('foo')</tt>, so go with that
unless you have a specific reason to use <tt>page.has_content?('foo')</tt> instead.
Note that <tt>page.should have_no_xpath</tt> is preferred over
<tt>page.should_not have_xpath</tt>. Read the section on asynchronous JavaScript
@ -483,7 +490,7 @@ When issuing instructions to the DSL such as:
click_link('foo')
click_link('bar')
page.should have_content('baz')
page.should have_text('baz')
If clicking on the *foo* link triggers an asynchronous process, such as
an Ajax request, which, when complete will add the *bar* link to the page,
@ -515,7 +522,7 @@ The two following statements are functionally equivalent:
Capybara's waiting behaviour is quite advanced, and can deal with situations
such as the following line of code:
find('#sidebar').find('h1').should have_content('Something')
find('#sidebar').find('h1').should have_text('Something')
Even if JavaScript causes <tt>#sidebar</tt> to disappear off the page, Capybara
will automatically reload it and any elements it contains. So if an AJAX

View file

@ -201,17 +201,21 @@ module Capybara
# Checks if the page or current node has the given text content,
# ignoring any HTML tags and normalizing whitespace.
#
# Unlike has_content this only matches text displayed on the page
# and specifically excludes text contained within script nodes.
# Unlike has_content this only matches displayable text and specifically
# excludes text contained within non-display nodes such as script or head tags.
#
# @param [String] content The text to check for
# @return [Boolean] Whether it exists
#
def has_text?(content)
literal = XPath::Expression::StringLiteral.new(content).to_xpath
expression = "./descendant-or-self::*[text()[contains(normalize-space(.), #{literal})] and not(ancestor-or-self::script)]"
normalized_content = normalize_whitespace(content)
has_xpath?(expression)
wait_until do
normalize_whitespace(text).include?(normalized_content) or
raise ExpectationNotMet
end
rescue Capybara::ExpectationNotMet
return false
end
##
@ -219,17 +223,21 @@ module Capybara
# Checks if the page or current node does not have the given text
# content, ignoring any HTML tags and normalizing whitespace.
#
# Unlike has_content this only matches text displayed on the page
# and specifically excludes text contained within script nodes.
# Unlike has_content this only matches displayable text and specifically
# excludes text contained within non-display nodes such as script or head tags.
#
# @param [String] content The text to check for
# @return [Boolean] Whether it exists
#
def has_no_text?(content)
literal = XPath::Expression::StringLiteral.new(content).to_xpath
expression = "./descendant-or-self::*[text()[contains(normalize-space(.), #{literal})] and not(ancestor-or-self::script)]"
normalized_content = normalize_whitespace(content)
has_no_xpath?(expression)
wait_until do
!normalize_whitespace(text).include?(normalized_content) or
raise ExpectationNotMet
end
rescue Capybara::ExpectationNotMet
return false
end
##
@ -448,6 +456,19 @@ module Capybara
options = options.dup
[options, if options.has_key?(key) then {key => options.delete(key)} else {} end]
end
##
#
# Normalizes whitespace space by stripping leading and trailing
# whitespace and replacing sequences of whitespace characters
# with a single space.
#
# @param [String] text Text to normalize
# @return [String] Normalized text
#
def normalize_whitespace(text)
text.gsub(/\s+/, ' ').strip
end
end
end
end

View file

@ -1,15 +1,128 @@
shared_examples_for 'has_text' do
describe '#has_text?' do
it 'works' do
it "should be true if the given text is on the page at least once" do
@session.visit('/with_html')
@session.should have_text('est')
@session.should have_text('Lorem')
@session.should have_text('Redirect')
end
it "should be true if scoped to an element which has the text" do
@session.visit('/with_html')
@session.within("//a[@title='awesome title']") do
@session.should have_text('labore')
end
end
it "should be false if scoped to an element which does not have the text" do
@session.visit('/with_html')
@session.within("//a[@title='awesome title']") do
@session.should_not have_text('monkey')
end
end
it "should ignore tags" do
@session.visit('/with_html')
@session.should_not have_text('exercitation <a href="/foo" id="foo">ullamco</a> laboris')
@session.should have_text('exercitation ullamco laboris')
end
it "should ignore extra whitespace and newlines" do
@session.visit('/with_html')
@session.should have_text('text with whitespace')
end
it "should be false if the given text is not on the page" do
@session.visit('/with_html')
@session.should_not have_text('xxxxyzzz')
@session.should_not have_text('monkey')
end
it 'should handle single quotes in the text' do
@session.visit('/with-quotes')
@session.should have_text("can't")
end
it 'should handle double quotes in the text' do
@session.visit('/with-quotes')
@session.should have_text(%q{"No," he said})
end
it 'should handle mixed single and double quotes in the text' do
@session.visit('/with-quotes')
@session.should have_text(%q{"you can't do that."})
end
it 'should be false if text is in the title tag in the head' do
@session.visit('/with_html')
@session.should_not have_text('with_js')
end
it 'should be false if text is inside a script tag in the body' do
@session.visit('/with_html')
@session.should_not have_text('a javascript comment')
@session.should_not have_text('aVar')
end
end
describe '#has_no_text?' do
it 'works' do
it "should be false if the given text is on the page at least once" do
@session.visit('/with_html')
@session.should have_no_text('Merol')
@session.should_not have_no_text('est')
@session.should_not have_no_text('Lorem')
@session.should_not have_no_text('Redirect')
end
it "should be false if scoped to an element which has the text" do
@session.visit('/with_html')
@session.within("//a[@title='awesome title']") do
@session.should_not have_no_text('labore')
end
end
it "should be true if scoped to an element which does not have the text" do
@session.visit('/with_html')
@session.within("//a[@title='awesome title']") do
@session.should have_no_text('monkey')
end
end
it "should ignore tags" do
@session.visit('/with_html')
@session.should have_no_text('exercitation <a href="/foo" id="foo">ullamco</a> laboris')
@session.should_not have_no_text('exercitation ullamco laboris')
end
it "should be true if the given text is not on the page" do
@session.visit('/with_html')
@session.should have_no_text('xxxxyzzz')
@session.should have_no_text('monkey')
end
it 'should handle single quotes in the text' do
@session.visit('/with-quotes')
@session.should_not have_no_text("can't")
end
it 'should handle double quotes in the text' do
@session.visit('/with-quotes')
@session.should_not have_no_text(%q{"No," he said})
end
it 'should handle mixed single and double quotes in the text' do
@session.visit('/with-quotes')
@session.should_not have_no_text(%q{"you can't do that."})
end
it 'should be true if text is in the title tag in the head' do
@session.visit('/with_html')
@session.should have_no_text('with_js')
end
it 'should be true if text is inside a script tag in the body' do
@session.visit('/with_html')
@session.should have_no_text('a javascript comment')
@session.should have_no_text('aVar')
end
end
end

View file

@ -274,6 +274,21 @@ shared_examples_for "session with javascript support" do
end
end
describe '#has_text?' do
it "should wait for text to appear" do
@session.visit('/with_js')
@session.click_link('Click me')
@session.should have_text("Has been clicked")
end
end
describe '#has_no_text?' do
it "should wait for text to disappear" do
@session.visit('/with_js')
@session.click_link('Click me')
@session.should have_no_text("I changed it")
end
end
end
end

View file

@ -43,6 +43,11 @@
<a id="reload-link" href="#">Reload!</a>
<div id="reload-me"><em>waiting to be reloaded</em></div>
</p>
<script type="text/javascript">
// a javascript comment
var aVar = 123;
</script>
</body>
</html>

View file

@ -312,6 +312,78 @@ describe Capybara::RSpecMatchers do
end
end
describe "have_text matcher" do
it "gives proper description" do
have_text('Text').description.should == "has text \"Text\""
end
context "on a string" do
context "with should" do
it "passes if has_text? returns true" do
"<h1>Text</h1>".should have_text('Text')
end
it "fails if has_text? returns false" do
expect do
"<h1>Text</h1>".should have_text('No such Text')
end.to raise_error(/expected there to be text "No such Text" in "Text"/)
end
end
context "with should_not" do
it "passes if has_no_text? returns true" do
"<h1>Text</h1>".should_not have_text('No such Text')
end
it "fails if has_no_text? returns false" do
expect do
"<h1>Text</h1>".should_not have_text('Text')
end.to raise_error(/expected text "Text" not to return anything/)
end
end
end
context "on a page or node" do
before do
visit('/with_html')
end
context "with should" do
it "passes if has_text? returns true" do
page.should have_text('This is a test')
end
it "fails if has_text? returns false" do
expect do
page.should have_text('No such Text')
end.to raise_error(/expected there to be text "No such Text" in "(.*)This is a test(.*)"/)
end
context "with default selector CSS" do
before { Capybara.default_selector = :css }
it "fails if has_text? returns false" do
expect do
page.should have_text('No such Text')
end.to raise_error(/expected there to be text "No such Text" in "(.*)This is a test(.*)"/)
end
after { Capybara.default_selector = :xpath }
end
end
context "with should_not" do
it "passes if has_no_text? returns true" do
page.should_not have_text('No such Text')
end
it "fails if has_no_text? returns false" do
expect do
page.should_not have_text('This is a test')
end.to raise_error(/expected text "This is a test" not to return anything/)
end
end
end
end
describe "have_link matcher" do
let(:html) { '<a href="#">Just a link</a>' }