From f2fb04f14a31b528885997104d5c4dff0add1211 Mon Sep 17 00:00:00 2001 From: David Chelimsky and Jonas Nicklas Date: Fri, 12 Nov 2010 14:46:46 -0600 Subject: [PATCH] Util function for applying matchers to strings --- lib/capybara/driver/rack_test_driver.rb | 28 +++------ lib/capybara/node.rb | 4 ++ lib/capybara/node/finders.rb | 14 ++++- lib/capybara/util/string.rb | 72 +++++++++++++++++++++++ spec/util/string_spec.rb | 78 +++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 23 deletions(-) create mode 100644 lib/capybara/util/string.rb create mode 100644 spec/util/string_spec.rb diff --git a/lib/capybara/driver/rack_test_driver.rb b/lib/capybara/driver/rack_test_driver.rb index e493d7bcf..bb09f8801 100644 --- a/lib/capybara/driver/rack_test_driver.rb +++ b/lib/capybara/driver/rack_test_driver.rb @@ -1,3 +1,4 @@ +require 'capybara/util/string' require 'rack/test' require 'rack/utils' require 'mime/types' @@ -11,28 +12,11 @@ def text end def [](name) - attr_name = name.to_s - case - when 'select' == tag_name && 'value' == attr_name - if native['multiple'] == 'multiple' - native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content } - else - option = native.xpath(".//option[@selected='selected']").first || native.xpath(".//option").first - option[:value] || option.content if option - end - when 'input' == tag_name && 'checkbox' == type && 'checked' == attr_name - native[attr_name] == 'checked' ? true : false - else - native[attr_name] - end + string_node[name] end def value - if tag_name == 'textarea' - native.content - else - self[:value] - end + string_node.value end def set(value) @@ -82,7 +66,7 @@ def tag_name end def visible? - native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none')]").size == 0 + string_node.visible? end def path @@ -95,6 +79,10 @@ def find(locator) private + def string_node + @string_node ||= Capybara::StringNode.new(native) + end + # a reference to the select node if this is an option node def select_node find('./ancestor::select').first diff --git a/lib/capybara/node.rb b/lib/capybara/node.rb index b1f2c6688..4fce649c8 100644 --- a/lib/capybara/node.rb +++ b/lib/capybara/node.rb @@ -38,6 +38,10 @@ def initialize(session, base) protected + def wait? + driver.wait? + end + def driver session.driver end diff --git a/lib/capybara/node/finders.rb b/lib/capybara/node/finders.rb index 32e30979c..99f32a542 100644 --- a/lib/capybara/node/finders.rb +++ b/lib/capybara/node/finders.rb @@ -114,7 +114,7 @@ def all(*args) options = if args.last.is_a?(Hash) then args.pop else {} end results = Capybara::Selector.normalize(*args).map do |path| - base.find(path) + find_in_base(path) end.flatten if text = options[:text] @@ -127,13 +127,21 @@ def all(*args) results = results.select { |node| node.visible? } end - results.map { |n| Capybara::Element.new(session, n) } + convert_elements(results) end protected + def find_in_base(xpath) + base.find(xpath) + end + + def convert_elements(elements) + elements.map { |element| Capybara::Element.new(session, element) } + end + def wait_conditionally_until - if driver.wait? then session.wait_until { yield } else yield end + if wait? then session.wait_until { yield } else yield end end end diff --git a/lib/capybara/util/string.rb b/lib/capybara/util/string.rb new file mode 100644 index 000000000..2a05ac63a --- /dev/null +++ b/lib/capybara/util/string.rb @@ -0,0 +1,72 @@ +module Capybara + def self.string(html) + StringNode.new(Nokogiri::HTML(html)) + end + + class StringNode + include Capybara::Node::Finders + include Capybara::Node::Matchers + + attr_reader :native + + def initialize(native) + @native = native + end + + def text + native.text + end + + def [](name) + attr_name = name.to_s + if attr_name == 'value' + value + elsif 'input' == tag_name and 'checkbox' == native[:type] and 'checked' == attr_name + native['checked'] == 'checked' + else + native[attr_name] + end + end + + def tag_name + native.node_name + end + + def path + native.path + end + + def value + if tag_name == 'textarea' + native.content + elsif tag_name == 'select' + if native['multiple'] == 'multiple' + native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content } + else + option = native.xpath(".//option[@selected='selected']").first || native.xpath(".//option").first + option[:value] || option.content if option + end + else + native[:value] + end + end + + def visible? + native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none')]").size == 0 + end + + protected + + def find_in_base(xpath) + native.xpath(xpath).map { |node| StringNode.new(node) } + end + + def convert_elements(elements) + elements + end + + def wait? + false + end + end +end diff --git a/spec/util/string_spec.rb b/spec/util/string_spec.rb new file mode 100644 index 000000000..f259d65ae --- /dev/null +++ b/spec/util/string_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' +require 'capybara/util/string' + +describe Capybara do + describe '.string' do + let :string do + Capybara.string <<-STRING +
+
+

Awesome

+

Yes it is

+
+ + +
+ STRING + end + + it "allows using matchers" do + string.should have_css('#page') + string.should_not have_css('#does-not-exist') + end + + it "allows using custom matchers" do + Capybara.add_selector :lifeform do + xpath { |name| "//option[contains(.,'#{name}')]" } + end + string.should have_selector(:page) + string.should_not have_selector(:'does-not-exist') + string.should have_selector(:lifeform, "Monkey") + string.should_not have_selector(:lifeform, "Gorilla") + end + + it "allows using matchers with text option" do + string.should have_css('h1', :text => 'Awesome') + string.should_not have_css('h1', :text => 'Not so awesome') + end + + it "allows finding only visible nodes" do + string.all('//p', :text => 'c2010', :visible => true).should be_empty + string.all('//p', :text => 'c2010', :visible => false).should have(1).element + end + + it "allows finding elements and extracting text from them" do + string.find('//h1').text.should == 'Awesome' + end + + it "allows finding elements and extracting attributes from them" do + string.find('//h1')[:data].should == 'fantastic' + end + + it "allows finding elements and extracting the tag name from them" do + string.find('//h1').tag_name.should == 'h1' + end + + it "allows finding elements and extracting the path" do + string.find('//h1').path.should == '/html/body/div/div[1]/h1' + end + + it "allows finding elements and extracting the path" do + string.find('//input').value.should == 'bar' + string.find('//select').value.should == 'Capybara' + end + + it "allows finding elements and checking if they are visible" do + string.find('//h1').should be_visible + string.find('//input').should_not be_visible + end + end +end