mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
Move more of node functionality into subfolder
We have too many top level files, we have multiple classes in the same file. This allows us to solve both problems, while also providing a good place for the new Capybara::Node::Simple (formerly Capybara::StringNode)
This commit is contained in:
parent
39f998d846
commit
d223d542f7
15 changed files with 393 additions and 300 deletions
5
Rakefile
5
Rakefile
|
@ -3,7 +3,10 @@ require 'rspec/core/rake_task'
|
||||||
require 'yard'
|
require 'yard'
|
||||||
|
|
||||||
desc "Run all examples"
|
desc "Run all examples"
|
||||||
RSpec::Core::RakeTask.new('spec')
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
||||||
|
#t.rspec_path = 'bin/rspec'
|
||||||
|
t.rspec_opts = %w[--color]
|
||||||
|
end
|
||||||
|
|
||||||
YARD::Rake::YardocTask.new do |t|
|
YARD::Rake::YardocTask.new do |t|
|
||||||
t.files = ['lib/**/*.rb', 'README.rdoc']
|
t.files = ['lib/**/*.rb', 'README.rdoc']
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
require 'timeout'
|
require 'timeout'
|
||||||
require 'nokogiri'
|
require 'nokogiri'
|
||||||
require 'xpath'
|
require 'xpath'
|
||||||
|
|
||||||
module Capybara
|
module Capybara
|
||||||
class CapybaraError < StandardError; end
|
class CapybaraError < StandardError; end
|
||||||
class DriverNotFoundError < CapybaraError; end
|
class DriverNotFoundError < CapybaraError; end
|
||||||
|
@ -132,7 +131,7 @@ module Capybara
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Wraps the given string, which should contain an HTML document or fragment
|
# Wraps the given string, which should contain an HTML document or fragment
|
||||||
# in a {Capybara::StringNode} which exposes all {Capybara::Node::Matchers} and
|
# in a {Capybara::Node::Simple} which exposes all {Capybara::Node::Matchers} and
|
||||||
# {Capybara::Node::Finders}. This allows you to query any string containing
|
# {Capybara::Node::Finders}. This allows you to query any string containing
|
||||||
# HTML in the exact same way you would query the current document in a Capybara
|
# HTML in the exact same way you would query the current document in a Capybara
|
||||||
# session. For example:
|
# session. For example:
|
||||||
|
@ -150,10 +149,10 @@ module Capybara
|
||||||
# node.find('ul').find('li').text # => 'Home'
|
# node.find('ul').find('li').text # => 'Home'
|
||||||
#
|
#
|
||||||
# @param [String] html An html fragment or document
|
# @param [String] html An html fragment or document
|
||||||
# @return [Capybara::StringNode] A node which has Capybara's finders and matchers
|
# @return [Capybara::Node::Simple] A node which has Capybara's finders and matchers
|
||||||
#
|
#
|
||||||
def string(html)
|
def string(html)
|
||||||
StringNode.new(html)
|
Capybara::Node::Simple.new(html)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -183,13 +182,19 @@ module Capybara
|
||||||
|
|
||||||
autoload :Server, 'capybara/server'
|
autoload :Server, 'capybara/server'
|
||||||
autoload :Session, 'capybara/session'
|
autoload :Session, 'capybara/session'
|
||||||
autoload :Node, 'capybara/node'
|
|
||||||
autoload :StringNode, 'capybara/util/string'
|
|
||||||
autoload :Document, 'capybara/node'
|
|
||||||
autoload :Element, 'capybara/node'
|
|
||||||
autoload :Selector, 'capybara/selector'
|
autoload :Selector, 'capybara/selector'
|
||||||
autoload :VERSION, 'capybara/version'
|
autoload :VERSION, 'capybara/version'
|
||||||
|
|
||||||
|
module Node
|
||||||
|
autoload :Base, 'capybara/node/base'
|
||||||
|
autoload :Simple, 'capybara/node/simple'
|
||||||
|
autoload :Element, 'capybara/node/element'
|
||||||
|
autoload :Document, 'capybara/node/document'
|
||||||
|
autoload :Finders, 'capybara/node/finders'
|
||||||
|
autoload :Matchers, 'capybara/node/matchers'
|
||||||
|
autoload :Actions, 'capybara/node/actions'
|
||||||
|
end
|
||||||
|
|
||||||
module Driver
|
module Driver
|
||||||
autoload :Base, 'capybara/driver/base'
|
autoload :Base, 'capybara/driver/base'
|
||||||
autoload :Node, 'capybara/driver/node'
|
autoload :Node, 'capybara/driver/node'
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
||||||
private
|
private
|
||||||
|
|
||||||
def string_node
|
def string_node
|
||||||
@string_node ||= Capybara::StringNode.new(native)
|
@string_node ||= Capybara::Node::Simple.new(native)
|
||||||
end
|
end
|
||||||
|
|
||||||
# a reference to the select node if this is an option node
|
# a reference to the select node if this is an option node
|
||||||
|
|
|
@ -1,216 +0,0 @@
|
||||||
require 'capybara/node/finders'
|
|
||||||
require 'capybara/node/actions'
|
|
||||||
require 'capybara/node/matchers'
|
|
||||||
|
|
||||||
module Capybara
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# A {Capybara::Node} represents either an element on a page through the subclass
|
|
||||||
# {Capybara::Element} or a document through {Capybara::Document}.
|
|
||||||
#
|
|
||||||
# Both types of Node share the same methods, used for interacting with the
|
|
||||||
# elements on the page. These methods are divided into three categories,
|
|
||||||
# finders, actions and matchers. These are found in the modules
|
|
||||||
# {Capybara::Node::Finders}, {Capybara::Node::Actions} and {Capybara::Node::Matchers}
|
|
||||||
# respectively.
|
|
||||||
#
|
|
||||||
# A {Capybara::Session} exposes all methods from {Capybara::Document} directly:
|
|
||||||
#
|
|
||||||
# session = Capybara::Session.new(:rack_test, my_app)
|
|
||||||
# session.visit('/')
|
|
||||||
# session.fill_in('Foo', :with => 'Bar') # from Capybara::Node::Actions
|
|
||||||
# bar = session.find('#bar') # from Capybara::Node::Finders
|
|
||||||
# bar.select('Baz', :from => 'Quox') # from Capybara::Node::Actions
|
|
||||||
# session.has_css?('#foobar') # from Capybara::Node::Matchers
|
|
||||||
#
|
|
||||||
class Node
|
|
||||||
attr_reader :session, :base
|
|
||||||
|
|
||||||
include Capybara::Node::Finders
|
|
||||||
include Capybara::Node::Actions
|
|
||||||
include Capybara::Node::Matchers
|
|
||||||
|
|
||||||
def initialize(session, base)
|
|
||||||
@session = session
|
|
||||||
@base = base
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def wait?
|
|
||||||
driver.wait?
|
|
||||||
end
|
|
||||||
|
|
||||||
def driver
|
|
||||||
session.driver
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# A {Capybara::Element} represents a single element on the page. It is possible
|
|
||||||
# to interact with the contents of this element the same as with a document:
|
|
||||||
#
|
|
||||||
# session = Capybara::Session.new(:rack_test, my_app)
|
|
||||||
#
|
|
||||||
# bar = session.find('#bar') # from Capybara::Node::Finders
|
|
||||||
# bar.select('Baz', :from => 'Quox') # from Capybara::Node::Actions
|
|
||||||
#
|
|
||||||
# {Capybara::Element} also has access to HTML attributes and other properties of the
|
|
||||||
# element:
|
|
||||||
#
|
|
||||||
# bar.value
|
|
||||||
# bar.text
|
|
||||||
# bar[:title]
|
|
||||||
#
|
|
||||||
# @see Capybara::Node
|
|
||||||
#
|
|
||||||
class Element < Node
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# @return [Object] The native element from the driver, this allows access to driver specific methods
|
|
||||||
#
|
|
||||||
def native
|
|
||||||
base.native
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# @return [String] The text of the element
|
|
||||||
#
|
|
||||||
def text
|
|
||||||
base.text
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Retrieve the given attribute
|
|
||||||
#
|
|
||||||
# element[:title] # => HTML title attribute
|
|
||||||
#
|
|
||||||
# @param [Symbol] attribute The attribute to retrieve
|
|
||||||
# @return [String] The value of the attribute
|
|
||||||
#
|
|
||||||
def [](attribute)
|
|
||||||
base[attribute]
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# @return [String] The value of the form element
|
|
||||||
#
|
|
||||||
def value
|
|
||||||
base.value
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Set the value of the form element to the given value.
|
|
||||||
#
|
|
||||||
# @param [String] value The new value
|
|
||||||
#
|
|
||||||
def set(value)
|
|
||||||
base.set(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Select this node if is an option element inside a select tag
|
|
||||||
#
|
|
||||||
def select_option
|
|
||||||
base.select_option
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Unselect this node if is an option element inside a multiple select tag
|
|
||||||
#
|
|
||||||
def unselect_option
|
|
||||||
base.unselect_option
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Click the Element
|
|
||||||
#
|
|
||||||
def click
|
|
||||||
base.click
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# @return [String] The tag name of the element
|
|
||||||
#
|
|
||||||
def tag_name
|
|
||||||
base.tag_name
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Whether or not the element is visible. Not all drivers support CSS, so
|
|
||||||
# the result may be inaccurate.
|
|
||||||
#
|
|
||||||
# @return [Boolean] Whether the element is visible
|
|
||||||
#
|
|
||||||
def visible?
|
|
||||||
base.visible?
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# An XPath expression describing where on the page the element can be found
|
|
||||||
#
|
|
||||||
# @return [String] An XPath expression
|
|
||||||
#
|
|
||||||
def path
|
|
||||||
base.path
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Trigger any event on the current element, for example mouseover or focus
|
|
||||||
# events. Does not work in Selenium.
|
|
||||||
#
|
|
||||||
# @param [String] event The name of the event to trigger
|
|
||||||
#
|
|
||||||
def trigger(event)
|
|
||||||
base.trigger(event)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Drag the element to the given other element.
|
|
||||||
#
|
|
||||||
# source = page.find('#foo')
|
|
||||||
# target = page.find('#bar')
|
|
||||||
# source.drag_to(target)
|
|
||||||
#
|
|
||||||
# @param [Capybara::Element] node The element to drag to
|
|
||||||
#
|
|
||||||
def drag_to(node)
|
|
||||||
base.drag_to(node.base)
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
%(#<Capybara::Element tag="#{tag_name}" path="#{path}">)
|
|
||||||
rescue NotSupportedByDriverError
|
|
||||||
%(#<Capybara::Element tag="#{tag_name}">)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# A {Capybara::Document} represents an HTML document. Any operation
|
|
||||||
# performed on it will be performed on the entire document.
|
|
||||||
#
|
|
||||||
# @see Capybara::Node
|
|
||||||
#
|
|
||||||
class Document < Node
|
|
||||||
def inspect
|
|
||||||
%(#<Capybara::Document>)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +1,5 @@
|
||||||
module Capybara
|
module Capybara
|
||||||
class Node
|
module Node
|
||||||
module Actions
|
module Actions
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
47
lib/capybara/node/base.rb
Normal file
47
lib/capybara/node/base.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
module Capybara
|
||||||
|
module Node
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# A {Capybara::Node::Base} represents either an element on a page through the subclass
|
||||||
|
# {Capybara::Node::Element} or a document through {Capybara::Node::Document}.
|
||||||
|
#
|
||||||
|
# Both types of Node share the same methods, used for interacting with the
|
||||||
|
# elements on the page. These methods are divided into three categories,
|
||||||
|
# finders, actions and matchers. These are found in the modules
|
||||||
|
# {Capybara::Node::Finders}, {Capybara::Node::Actions} and {Capybara::Node::Matchers}
|
||||||
|
# respectively.
|
||||||
|
#
|
||||||
|
# A {Capybara::Session} exposes all methods from {Capybara::Node::Document} directly:
|
||||||
|
#
|
||||||
|
# session = Capybara::Session.new(:rack_test, my_app)
|
||||||
|
# session.visit('/')
|
||||||
|
# session.fill_in('Foo', :with => 'Bar') # from Capybara::Node::Actions
|
||||||
|
# bar = session.find('#bar') # from Capybara::Node::Finders
|
||||||
|
# bar.select('Baz', :from => 'Quox') # from Capybara::Node::Actions
|
||||||
|
# session.has_css?('#foobar') # from Capybara::Node::Matchers
|
||||||
|
#
|
||||||
|
class Base
|
||||||
|
attr_reader :session, :base
|
||||||
|
|
||||||
|
include Capybara::Node::Finders
|
||||||
|
include Capybara::Node::Actions
|
||||||
|
include Capybara::Node::Matchers
|
||||||
|
|
||||||
|
def initialize(session, base)
|
||||||
|
@session = session
|
||||||
|
@base = base
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def wait?
|
||||||
|
driver.wait?
|
||||||
|
end
|
||||||
|
|
||||||
|
def driver
|
||||||
|
session.driver
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
17
lib/capybara/node/document.rb
Normal file
17
lib/capybara/node/document.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
module Capybara
|
||||||
|
module Node
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# A {Capybara::Document} represents an HTML document. Any operation
|
||||||
|
# performed on it will be performed on the entire document.
|
||||||
|
#
|
||||||
|
# @see Capybara::Node
|
||||||
|
#
|
||||||
|
class Document < Base
|
||||||
|
def inspect
|
||||||
|
%(#<Capybara::Document>)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
158
lib/capybara/node/element.rb
Normal file
158
lib/capybara/node/element.rb
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
module Capybara
|
||||||
|
module Node
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# A {Capybara::Element} represents a single element on the page. It is possible
|
||||||
|
# to interact with the contents of this element the same as with a document:
|
||||||
|
#
|
||||||
|
# session = Capybara::Session.new(:rack_test, my_app)
|
||||||
|
#
|
||||||
|
# bar = session.find('#bar') # from Capybara::Node::Finders
|
||||||
|
# bar.select('Baz', :from => 'Quox') # from Capybara::Node::Actions
|
||||||
|
#
|
||||||
|
# {Capybara::Element} also has access to HTML attributes and other properties of the
|
||||||
|
# element:
|
||||||
|
#
|
||||||
|
# bar.value
|
||||||
|
# bar.text
|
||||||
|
# bar[:title]
|
||||||
|
#
|
||||||
|
# @see Capybara::Node
|
||||||
|
#
|
||||||
|
class Element < Base
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# @return [Object] The native element from the driver, this allows access to driver specific methods
|
||||||
|
#
|
||||||
|
def native
|
||||||
|
base.native
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# @return [String] The text of the element
|
||||||
|
#
|
||||||
|
def text
|
||||||
|
base.text
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Retrieve the given attribute
|
||||||
|
#
|
||||||
|
# element[:title] # => HTML title attribute
|
||||||
|
#
|
||||||
|
# @param [Symbol] attribute The attribute to retrieve
|
||||||
|
# @return [String] The value of the attribute
|
||||||
|
#
|
||||||
|
def [](attribute)
|
||||||
|
base[attribute]
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# @return [String] The value of the form element
|
||||||
|
#
|
||||||
|
def value
|
||||||
|
base.value
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Set the value of the form element to the given value.
|
||||||
|
#
|
||||||
|
# @param [String] value The new value
|
||||||
|
#
|
||||||
|
def set(value)
|
||||||
|
base.set(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Select this node if is an option element inside a select tag
|
||||||
|
#
|
||||||
|
def select_option
|
||||||
|
base.select_option
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Unselect this node if is an option element inside a multiple select tag
|
||||||
|
#
|
||||||
|
def unselect_option
|
||||||
|
base.unselect_option
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Click the Element
|
||||||
|
#
|
||||||
|
def click
|
||||||
|
base.click
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# @return [String] The tag name of the element
|
||||||
|
#
|
||||||
|
def tag_name
|
||||||
|
base.tag_name
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Whether or not the element is visible. Not all drivers support CSS, so
|
||||||
|
# the result may be inaccurate.
|
||||||
|
#
|
||||||
|
# @return [Boolean] Whether the element is visible
|
||||||
|
#
|
||||||
|
def visible?
|
||||||
|
base.visible?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# An XPath expression describing where on the page the element can be found
|
||||||
|
#
|
||||||
|
# @return [String] An XPath expression
|
||||||
|
#
|
||||||
|
def path
|
||||||
|
base.path
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Trigger any event on the current element, for example mouseover or focus
|
||||||
|
# events. Does not work in Selenium.
|
||||||
|
#
|
||||||
|
# @param [String] event The name of the event to trigger
|
||||||
|
#
|
||||||
|
def trigger(event)
|
||||||
|
base.trigger(event)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Drag the element to the given other element.
|
||||||
|
#
|
||||||
|
# source = page.find('#foo')
|
||||||
|
# target = page.find('#bar')
|
||||||
|
# source.drag_to(target)
|
||||||
|
#
|
||||||
|
# @param [Capybara::Element] node The element to drag to
|
||||||
|
#
|
||||||
|
def drag_to(node)
|
||||||
|
base.drag_to(node.base)
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
%(#<Capybara::Element tag="#{tag_name}" path="#{path}">)
|
||||||
|
rescue NotSupportedByDriverError
|
||||||
|
%(#<Capybara::Element tag="#{tag_name}">)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
module Capybara
|
module Capybara
|
||||||
class Node
|
module Node
|
||||||
module Finders
|
module Finders
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -137,7 +137,7 @@ module Capybara
|
||||||
end
|
end
|
||||||
|
|
||||||
def convert_elements(elements)
|
def convert_elements(elements)
|
||||||
elements.map { |element| Capybara::Element.new(session, element) }
|
elements.map { |element| Capybara::Node::Element.new(session, element) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def wait_conditionally_until
|
def wait_conditionally_until
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module Capybara
|
module Capybara
|
||||||
class Node
|
module Node
|
||||||
module Matchers
|
module Matchers
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
71
lib/capybara/node/simple.rb
Normal file
71
lib/capybara/node/simple.rb
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
module Capybara
|
||||||
|
module Node
|
||||||
|
class Simple
|
||||||
|
include Capybara::Node::Finders
|
||||||
|
include Capybara::Node::Matchers
|
||||||
|
|
||||||
|
attr_reader :native
|
||||||
|
|
||||||
|
def initialize(native)
|
||||||
|
native = Nokogiri::HTML(native) if native.is_a?(String)
|
||||||
|
@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| self.class.new(node) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def convert_elements(elements)
|
||||||
|
elements
|
||||||
|
end
|
||||||
|
|
||||||
|
def wait?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -257,7 +257,7 @@ module Capybara
|
||||||
end
|
end
|
||||||
|
|
||||||
def document
|
def document
|
||||||
Capybara::Document.new(self, driver)
|
Capybara::Node::Document.new(self, driver)
|
||||||
end
|
end
|
||||||
|
|
||||||
def method_missing(*args)
|
def method_missing(*args)
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
module Capybara
|
|
||||||
class StringNode
|
|
||||||
include Capybara::Node::Finders
|
|
||||||
include Capybara::Node::Matchers
|
|
||||||
|
|
||||||
attr_reader :native
|
|
||||||
|
|
||||||
def initialize(native)
|
|
||||||
native = Nokogiri::HTML(native) if native.is_a?(String)
|
|
||||||
@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
|
|
77
spec/string_spec.rb
Normal file
77
spec/string_spec.rb
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
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
|
Loading…
Reference in a new issue