Skip to content

Commit

Permalink
Util function for applying matchers to strings
Browse files Browse the repository at this point in the history
  • Loading branch information
David Chelimsky and Jonas Nicklas committed Nov 12, 2010
1 parent b4c228f commit f2fb04f
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 23 deletions.
28 changes: 8 additions & 20 deletions lib/capybara/driver/rack_test_driver.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'capybara/util/string'
require 'rack/test'
require 'rack/utils'
require 'mime/types'
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/capybara/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def initialize(session, base)

protected

def wait?
driver.wait?
end

def driver
session.driver
end
Expand Down
14 changes: 11 additions & 3 deletions lib/capybara/node/finders.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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
Expand Down
72 changes: 72 additions & 0 deletions lib/capybara/util/string.rb
Original file line number Diff line number Diff line change
@@ -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
78 changes: 78 additions & 0 deletions spec/util/string_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
require 'spec_helper'
require 'capybara/util/string'

describe Capybara do
describe '.string' do
let :string do
Capybara.string <<-STRING
<div id="page">
<div id="content">
<h1 data="fantastic">Awesome</h1>
<p>Yes it is</p>
</div>
<div id="footer" style="display: none">
<p>c2010</p>
<p>Jonas Nicklas</p>
<input type="text" name="foo" value="bar"/>
<select name="animal">
<option>Monkey</option>
<option selected="selected">Capybara</option>
</select>
</div>
</div>
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

0 comments on commit f2fb04f

Please sign in to comment.