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:
parent
0c3f377fc4
commit
9fb05c9c64
6 changed files with 250 additions and 17 deletions
15
README.rdoc
15
README.rdoc
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>' }
|
||||
|
||||
|
|
Loading…
Reference in a new issue