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

Wrap driver nodes in new Node class which inherits from session

This commit is contained in:
Jonas Nicklas 2010-07-10 01:19:09 +02:00
parent 02d86ac992
commit 77168519a1
13 changed files with 159 additions and 138 deletions

View file

@ -34,7 +34,7 @@ module Capybara
autoload :Server, 'capybara/server' autoload :Server, 'capybara/server'
autoload :Session, 'capybara/session' autoload :Session, 'capybara/session'
autoload :XPath, 'capybara/xpath' autoload :XPath, 'capybara/xpath'
autoload :Searchable, 'capybara/searchable' autoload :Node, 'capybara/node'
autoload :VERSION, 'capybara/version' autoload :VERSION, 'capybara/version'
module Driver module Driver

View file

@ -1,8 +1,6 @@
module Capybara module Capybara
module Driver module Driver
class Node class Node
include Searchable
attr_reader :driver, :node attr_reader :driver, :node
def initialize(driver, node) def initialize(driver, node)

26
lib/capybara/node.rb Normal file
View file

@ -0,0 +1,26 @@
module Capybara
class Node < Session
def initialize(session, driver_node)
@session = session
@driver_node = driver_node
end
def method_missing(*args)
@driver_node.send(*args)
end
def respond_to?(method)
super || @driver_node.respond_to?(method)
end
def driver
@session.driver
end
def all_unfiltered(locator)
XPath.wrap(locator).paths.map do |path|
@driver_node.send(:all_unfiltered, path)
end.flatten
end
end
end

View file

@ -1,60 +0,0 @@
module Capybara
module Searchable
def find(*args)
all(*args).first
end
def find_field(locator)
find(:xpath, XPath.field(locator))
end
alias_method :field_labeled, :find_field
def find_link(locator)
find(:xpath, XPath.link(locator))
end
def find_button(locator)
find(:xpath, XPath.button(locator))
end
def find_by_id(id)
find(:css, "##{id}")
end
def all(*args)
options = if args.last.is_a?(Hash) then args.pop else {} end
if args[1].nil?
kind, locator = Capybara.default_selector, args.first
else
kind, locator = args
end
locator = XPath.from_css(locator) if kind == :css
results = all_unfiltered(locator)
if options[:text]
if options[:text].kind_of?(Regexp)
regexp = options[:text]
else
regexp = Regexp.escape(options[:text])
end
results = results.select { |n| n.text.match(regexp) }
end
if options[:visible] or Capybara.ignore_hidden_elements
results = results.select { |n| n.visible? }
end
results
end
private
def all_unfiltered(locator)
raise "Must be overridden"
end
end
end

View file

@ -4,7 +4,6 @@ require 'capybara/timeout'
module Capybara module Capybara
class Session class Session
extend Forwardable extend Forwardable
include Searchable
DSL_METHODS = [ DSL_METHODS = [
:all, :attach_file, :body, :check, :choose, :click, :click_button, :click_link, :current_url, :drag, :evaluate_script, :all, :attach_file, :body, :check, :choose, :click, :click_button, :click_link, :current_url, :drag, :evaluate_script,
@ -128,14 +127,6 @@ module Capybara
end end
end end
def scope_to(*locator)
scoped_session = self.clone
scoped_session.instance_eval do
@scopes = scopes + locator
end
scoped_session
end
def has_xpath?(path, options={}) def has_xpath?(path, options={})
wait_conditionally_until do wait_conditionally_until do
results = all(:xpath, path, options) results = all(:xpath, path, options)
@ -253,8 +244,63 @@ module Capybara
driver.evaluate_script(script) driver.evaluate_script(script)
end end
def find(*args)
all(*args).first
end
def find_field(locator)
find(:xpath, XPath.field(locator))
end
alias_method :field_labeled, :find_field
def find_link(locator)
find(:xpath, XPath.link(locator))
end
def find_button(locator)
find(:xpath, XPath.button(locator))
end
def find_by_id(id)
find(:css, "##{id}")
end
def all(*args)
options = if args.last.is_a?(Hash) then args.pop else {} end
if args[1].nil?
kind, locator = Capybara.default_selector, args.first
else
kind, locator = args
end
locator = XPath.from_css(locator) if kind == :css
results = all_unfiltered(locator)
if options[:text]
if options[:text].kind_of?(Regexp)
regexp = options[:text]
else
regexp = Regexp.escape(options[:text])
end
results = results.select { |n| n.text.match(regexp) }
end
if options[:visible] or Capybara.ignore_hidden_elements
results = results.select { |n| n.visible? }
end
results.map { |n| Capybara::Node.new(self, n) }
end
private private
# temporary hack until inheritance chain is fixed
def session
self
end
def wait_conditionally_until def wait_conditionally_until
if driver.wait? then wait_until { yield } else yield end if driver.wait? then wait_until { yield } else yield end
end end
@ -266,7 +312,7 @@ module Capybara
end end
def current_scope def current_scope
scopes.join('') scopes.join('/')
end end
def scopes def scopes

View file

@ -39,51 +39,51 @@ shared_examples_for "session" do
end end
end end
describe '#scope_to' do #describe '#scope_to' do
let(:scope) { @session.scope_to("//p[@id='first']") } # let(:scope) { @session.scope_to("//p[@id='first']") }
let(:more_scope) { scope.scope_to("//a[@id='foo']") } # let(:more_scope) { scope.scope_to(".//a[@id='foo']") }
before do # before do
@session.visit('/with_html') # @session.visit('/with_html')
end # end
it 'has a simple link' do # it 'has a simple link' do
scope.should have_xpath("//a[@class='simple']") # scope.should have_xpath(".//a[@class='simple']")
end # end
it 'does not have a redirect link' do # it 'does not have a redirect link' do
scope.should have_no_xpath("//a[@id='red']") # scope.should have_no_xpath(".//a[@id='red']")
end # end
it 'does have a redirect link' do # it 'does have a redirect link' do
@session.should have_xpath("//a[@id='red']") # @session.should have_xpath(".//a[@id='red']")
end # end
it 'does not share scopes' do # it 'does not share scopes' do
@session.should have_xpath("//a[@id='red']") # @session.should have_xpath(".//a[@id='red']")
scope.should have_no_xpath("//a[@id='red']") # scope.should have_no_xpath(".//a[@id='red']")
@session.should have_xpath("//a[@id='red']") # @session.should have_xpath(".//a[@id='red']")
end # end
context 'more_scope' do # context 'more_scope' do
it 'has the text for foo' do # it 'has the text for foo' do
more_scope.should have_content('ullamco') # more_scope.should have_content('ullamco')
end # end
it 'does not have a simple link' do # it 'does not have a simple link' do
more_scope.should have_no_xpath("//a[@class='simple']") # more_scope.should have_no_xpath(".//a[@class='simple']")
end # end
it 'has not overridden scope' do # it 'has not overridden scope' do
scope.should have_xpath("//a[@class='simple']") # scope.should have_xpath(".//a[@class='simple']")
end # end
it 'has not overridden session' do # it 'has not overridden session' do
@session.should have_xpath("//p[@id='second']") # @session.should have_xpath(".//p[@id='second']")
end # end
end # end
end #end
it_should_behave_like "all" it_should_behave_like "all"
it_should_behave_like "attach_file" it_should_behave_like "attach_file"

View file

@ -65,7 +65,7 @@ shared_examples_for "all" do
it "should find any element using the given locator" do it "should find any element using the given locator" do
@session.within(:xpath, "//div[@id='for_bar']") do @session.within(:xpath, "//div[@id='for_bar']") do
@session.all('//li').should have(2).elements @session.all('.//li').should have(2).elements
end end
end end
end end

View file

@ -9,6 +9,16 @@ shared_examples_for "find" do
@session.find("//input[@id='test_field']")[:value].should == 'monkey' @session.find("//input[@id='test_field']")[:value].should == 'monkey'
end end
it "should act return a session like object" do
@session.visit('/form')
@form = @session.find(:css, '#get-form')
@form.should have_field('Middle Name')
@form.should have_no_field('Languages')
@form.fill_in('Middle Name', :with => 'Monkey')
@form.click_button('med')
extract_results(@session)['middle_name'].should == 'Monkey'
end
context "with css selectors" do context "with css selectors" do
it "should find the first element using the given locator" do it "should find the first element using the given locator" do
@session.find(:css, 'h1').text.should == 'This is a test' @session.find(:css, 'h1').text.should == 'This is a test'
@ -49,7 +59,7 @@ shared_examples_for "find" do
it "should find the first element using the given locator" do it "should find the first element using the given locator" do
@session.within(:xpath, "//div[@id='for_bar']") do @session.within(:xpath, "//div[@id='for_bar']") do
@session.find('//li').text.should =~ /With Simple HTML/ @session.find('.//li').text.should =~ /With Simple HTML/
end end
end end
end end

View file

@ -23,8 +23,8 @@ shared_examples_for "has_xpath" do
it "should respect scopes" do it "should respect scopes" do
@session.within "//p[@id='first']" do @session.within "//p[@id='first']" do
@session.should have_xpath("//a[@id='foo']") @session.should have_xpath(".//a[@id='foo']")
@session.should_not have_xpath("//a[@id='red']") @session.should_not have_xpath(".//a[@id='red']")
end end
end end
@ -84,8 +84,8 @@ shared_examples_for "has_xpath" do
it "should respect scopes" do it "should respect scopes" do
@session.within "//p[@id='first']" do @session.within "//p[@id='first']" do
@session.should_not have_no_xpath("//a[@id='foo']") @session.should_not have_no_xpath(".//a[@id='foo']")
@session.should have_no_xpath("//a[@id='red']") @session.should have_no_xpath(".//a[@id='red']")
end end
end end

View file

@ -57,7 +57,7 @@ shared_examples_for "locate" do
it "should find the first element using the given locator" do it "should find the first element using the given locator" do
@session.within(:xpath, "//div[@id='for_bar']") do @session.within(:xpath, "//div[@id='for_bar']") do
@session.locate('//li').text.should =~ /With Simple HTML/ @session.locate('.//li').text.should =~ /With Simple HTML/
end end
end end
end end

View file

@ -53,7 +53,7 @@ shared_examples_for "within" do
context "with nested scopes" do context "with nested scopes" do
it "should respect the inner scope" do it "should respect the inner scope" do
@session.within("//div[@id='for_bar']") do @session.within("//div[@id='for_bar']") do
@session.within("//li[contains(.,'Bar')]") do @session.within(".//li[contains(.,'Bar')]") do
@session.click_link('Go') @session.click_link('Go')
end end
end end
@ -62,7 +62,7 @@ shared_examples_for "within" do
it "should respect the outer scope" do it "should respect the outer scope" do
@session.within("//div[@id='another_foo']") do @session.within("//div[@id='another_foo']") do
@session.within("//li[contains(.,'With Simple HTML')]") do @session.within(".//li[contains(.,'With Simple HTML')]") do
@session.click_link('Go') @session.click_link('Go')
end end
end end
@ -82,12 +82,12 @@ shared_examples_for "within" do
@session.within("//div[@id='for_bar']") do @session.within("//div[@id='for_bar']") do
running { running {
running { running {
@session.within("//div[@id='doesnotexist']") do @session.within(".//div[@id='doesnotexist']") do
end end
}.should raise_error(Capybara::ElementNotFound) }.should raise_error(Capybara::ElementNotFound)
}.should_not change { @session.has_xpath?("//div[@id='another_foo']") }.from(false) }.should_not change { @session.has_xpath?(".//div[@id='another_foo']") }.from(false)
end end
}.should_not change { @session.has_xpath?("//div[@id='another_foo']") }.from(true) }.should_not change { @session.has_xpath?(".//div[@id='another_foo']") }.from(true)
end end
end end

View file

@ -175,7 +175,7 @@
</p> </p>
</form> </form>
<form action="/form/get?foo=bar" method="get"> <form id="get-form" action="/form/get?foo=bar" method="get">
<p> <p>
<label for="form_middle_name">Middle Name</label> <label for="form_middle_name">Middle Name</label>
<input type="text" name="form[middle_name]" value="Darren" id="form_middle_name"/> <input type="text" name="form[middle_name]" value="Darren" id="form_middle_name"/>

View file

@ -40,7 +40,7 @@ module Capybara
end end
def scope(scope) def scope(scope)
XPath.new(*paths.map { |p| scope + p }) XPath.new(*paths.map { |p| scope + '/' + p })
end end
def to_s def to_s
@ -56,7 +56,7 @@ module Capybara
end end
def from_css(css) def from_css(css)
XPath.new(*[@paths, Nokogiri::CSS.xpath_for(css)].flatten) XPath.new(*[@paths, Nokogiri::CSS.xpath_for(css).map { |selector| '.' + selector }].flatten)
end end
alias_method :for_css, :from_css alias_method :for_css, :from_css
@ -77,7 +77,7 @@ module Capybara
end end
def content(locator) def content(locator)
append("/descendant-or-self::*[contains(normalize-space(.),#{s(locator)})]") append("./descendant-or-self::*[contains(normalize-space(.),#{s(locator)})]")
end end
def table(locator, options={}) def table(locator, options={})
@ -89,38 +89,38 @@ module Capybara
end.join(sibling) end.join(sibling)
conditions << "[.//#{row_conditions}]" conditions << "[.//#{row_conditions}]"
end end
append("//table[@id=#{s(locator)} or contains(caption,#{s(locator)})]#{conditions}") append(".//table[@id=#{s(locator)} or contains(caption,#{s(locator)})]#{conditions}")
end end
def fieldset(locator) def fieldset(locator)
append("//fieldset[@id=#{s(locator)} or contains(legend,#{s(locator)})]") append(".//fieldset[@id=#{s(locator)} or contains(legend,#{s(locator)})]")
end end
def link(locator) def link(locator)
xpath = append("//a[@href][@id=#{s(locator)} or contains(.,#{s(locator)}) or contains(@title,#{s(locator)}) or img[contains(@alt,#{s(locator)})]]") xpath = append(".//a[@href][@id=#{s(locator)} or contains(.,#{s(locator)}) or contains(@title,#{s(locator)}) or img[contains(@alt,#{s(locator)})]]")
xpath.prepend("//a[@href][text()=#{s(locator)} or @title=#{s(locator)} or img[@alt=#{s(locator)}]]") xpath.prepend(".//a[@href][text()=#{s(locator)} or @title=#{s(locator)} or img[@alt=#{s(locator)}]]")
end end
def button(locator) def button(locator)
xpath = append("//input[@type='submit' or @type='image' or @type='button'][@id=#{s(locator)} or contains(@value,#{s(locator)})]") xpath = append(".//input[@type='submit' or @type='image' or @type='button'][@id=#{s(locator)} or contains(@value,#{s(locator)})]")
xpath = xpath.append("//button[@id=#{s(locator)} or contains(@value,#{s(locator)}) or contains(.,#{s(locator)})]") xpath = xpath.append(".//button[@id=#{s(locator)} or contains(@value,#{s(locator)}) or contains(.,#{s(locator)})]")
xpath = xpath.prepend("//input[@type='submit' or @type='image' or @type='button'][@value=#{s(locator)}]") xpath = xpath.prepend(".//input[@type='submit' or @type='image' or @type='button'][@value=#{s(locator)}]")
xpath = xpath.prepend("//input[@type='image'][@alt=#{s(locator)} or contains(@alt,#{s(locator)})]") xpath = xpath.prepend(".//input[@type='image'][@alt=#{s(locator)} or contains(@alt,#{s(locator)})]")
xpath = xpath.prepend("//button[@value=#{s(locator)} or text()=#{s(locator)}]") xpath = xpath.prepend(".//button[@value=#{s(locator)} or text()=#{s(locator)}]")
end end
def text_field(locator, options={}) def text_field(locator, options={})
options = options.merge(:value => options[:with]) if options.has_key?(:with) options = options.merge(:value => options[:with]) if options.has_key?(:with)
add_field(locator, "//input[not(@type) or (@type!='radio' and @type!='checkbox' and @type!='hidden')]", options) add_field(locator, ".//input[not(@type) or (@type!='radio' and @type!='checkbox' and @type!='hidden')]", options)
end end
def text_area(locator, options={}) def text_area(locator, options={})
options = options.merge(:text => options[:with]) if options.has_key?(:with) options = options.merge(:text => options[:with]) if options.has_key?(:with)
add_field(locator, "//textarea", options) add_field(locator, ".//textarea", options)
end end
def select(locator, options={}) def select(locator, options={})
add_field(locator, "//select", options) add_field(locator, ".//select", options)
end end
def checkbox(locator, options={}) def checkbox(locator, options={})
@ -139,7 +139,7 @@ module Capybara
def input_field(type, locator, options={}) def input_field(type, locator, options={})
options = options.merge(:value => options[:with]) if options.has_key?(:with) options = options.merge(:value => options[:with]) if options.has_key?(:with)
add_field(locator, "//input[@type='#{type}']", options) add_field(locator, ".//input[@type='#{type}']", options)
end end
# place this between to nodes to indicate that they should be siblings # place this between to nodes to indicate that they should be siblings
@ -152,7 +152,8 @@ module Capybara
xpath = append("#{field}[@id=#{s(locator)}]#{postfix}") xpath = append("#{field}[@id=#{s(locator)}]#{postfix}")
xpath = xpath.append("#{field}[@name=#{s(locator)}]#{postfix}") xpath = xpath.append("#{field}[@name=#{s(locator)}]#{postfix}")
xpath = xpath.append("#{field}[@id=//label[contains(.,#{s(locator)})]/@for]#{postfix}") xpath = xpath.append("#{field}[@id=//label[contains(.,#{s(locator)})]/@for]#{postfix}")
xpath = xpath.append("//label[contains(.,#{s(locator)})]#{field}#{postfix}") # FIXME: Label should not be scoped to node, temporary workaround!!!
xpath = xpath.append(".//label[contains(.,#{s(locator)})]/#{field}#{postfix}")
xpath.prepend("#{field}[@id=//label[text()=#{s(locator)}]/@for]#{postfix}") xpath.prepend("#{field}[@id=//label[text()=#{s(locator)}]/@for]#{postfix}")
end end