mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
Extract HTML xpaths into XPath gem
This commit is contained in:
parent
5f9483326c
commit
d59d7bb3f7
10 changed files with 40 additions and 167 deletions
|
@ -1,6 +1,6 @@
|
|||
GIT
|
||||
remote: git://github.com/jnicklas/xpath.git
|
||||
revision: 07cbb7a
|
||||
revision: 18be9a2
|
||||
specs:
|
||||
xpath (0.0.1)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'timeout'
|
||||
require 'nokogiri'
|
||||
require 'xpath'
|
||||
|
||||
module Capybara
|
||||
class CapybaraError < StandardError; end
|
||||
|
@ -49,7 +50,6 @@ module Capybara
|
|||
|
||||
autoload :Server, 'capybara/server'
|
||||
autoload :Session, 'capybara/session'
|
||||
autoload :XPath, 'capybara/xpath'
|
||||
autoload :Node, 'capybara/node'
|
||||
autoload :Document, 'capybara/node'
|
||||
autoload :Element, 'capybara/node'
|
||||
|
|
|
@ -36,7 +36,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
|
||||
def set(value)
|
||||
if tag_name == 'input' and type == 'radio'
|
||||
other_radios_xpath = ::XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
|
||||
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
|
||||
driver.html.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
|
||||
native['checked'] = 'checked'
|
||||
elsif tag_name == 'input' and type == 'checkbox'
|
||||
|
|
|
@ -11,7 +11,7 @@ module Capybara
|
|||
#
|
||||
def click_link_or_button(locator)
|
||||
msg = "no link or button '#{locator}' found"
|
||||
find(:xpath, Capybara::XPath.link_or_button(locator), :message => msg).click
|
||||
find(:xpath, XPath::HTML.link_or_button(locator), :message => msg).click
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -23,7 +23,7 @@ module Capybara
|
|||
#
|
||||
def click_link(locator)
|
||||
msg = "no link with title, id or text '#{locator}' found"
|
||||
find(:xpath, Capybara::XPath.link(locator), :message => msg).click
|
||||
find(:xpath, XPath::HTML.link(locator), :message => msg).click
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -34,7 +34,7 @@ module Capybara
|
|||
#
|
||||
def click_button(locator)
|
||||
msg = "no button with value or id or text '#{locator}' found"
|
||||
find(:xpath, Capybara::XPath.button(locator), :message => msg).click
|
||||
find(:xpath, XPath::HTML.button(locator), :message => msg).click
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -50,7 +50,7 @@ module Capybara
|
|||
def fill_in(locator, options={})
|
||||
msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found"
|
||||
raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
|
||||
find(:xpath, Capybara::XPath.fillable_field(locator), :message => msg).set(options[:with])
|
||||
find(:xpath, XPath::HTML.fillable_field(locator), :message => msg).set(options[:with])
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -64,7 +64,7 @@ module Capybara
|
|||
#
|
||||
def choose(locator)
|
||||
msg = "cannot choose field, no radio button with id, name, or label '#{locator}' found"
|
||||
find(:xpath, Capybara::XPath.radio_button(locator), :message => msg).set(true)
|
||||
find(:xpath, XPath::HTML.radio_button(locator), :message => msg).set(true)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -78,7 +78,7 @@ module Capybara
|
|||
#
|
||||
def check(locator)
|
||||
msg = "cannot check field, no checkbox with id, name, or label '#{locator}' found"
|
||||
find(:xpath, Capybara::XPath.checkbox(locator), :message => msg).set(true)
|
||||
find(:xpath, XPath::HTML.checkbox(locator), :message => msg).set(true)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -92,7 +92,7 @@ module Capybara
|
|||
#
|
||||
def uncheck(locator)
|
||||
msg = "cannot uncheck field, no checkbox with id, name, or label '#{locator}' found"
|
||||
find(:xpath, Capybara::XPath.checkbox(locator), :message => msg).set(false)
|
||||
find(:xpath, XPath::HTML.checkbox(locator), :message => msg).set(false)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -108,8 +108,8 @@ module Capybara
|
|||
def select(value, options={})
|
||||
no_select_msg = "cannot select option, no select box with id, name, or label '#{options[:from]}' found"
|
||||
no_option_msg = "cannot select option, no option with text '#{value}' in select box '#{options[:from]}'"
|
||||
select = find(:xpath, Capybara::XPath.select(options[:from]), :message => no_select_msg)
|
||||
select.find(:xpath, Capybara::XPath.option(value), :message => no_option_msg).select_option
|
||||
select = find(:xpath, XPath::HTML.select(options[:from]), :message => no_select_msg)
|
||||
select.find(:xpath, XPath::HTML.option(value), :message => no_option_msg).select_option
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -125,8 +125,8 @@ module Capybara
|
|||
def unselect(value, options={})
|
||||
no_select_msg = "cannot unselect option, no select box with id, name, or label '#{options[:from]}' found"
|
||||
no_option_msg = "cannot unselect option, no option with text '#{value}' in select box '#{options[:from]}'"
|
||||
select = find(:xpath, Capybara::XPath.select(options[:from]), :message => no_select_msg)
|
||||
select.find(:xpath, Capybara::XPath.option(value), :message => no_option_msg).unselect_option
|
||||
select = find(:xpath, XPath::HTML.select(options[:from]), :message => no_select_msg)
|
||||
select.find(:xpath, XPath::HTML.option(value), :message => no_option_msg).unselect_option
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -141,7 +141,7 @@ module Capybara
|
|||
#
|
||||
def attach_file(locator, path)
|
||||
msg = "cannot attach file, no file field with id, name, or label '#{locator}' found"
|
||||
find(:xpath, Capybara::XPath.file_field(locator), :message => msg).set(path)
|
||||
find(:xpath, XPath::HTML.file_field(locator), :message => msg).set(path)
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -47,7 +47,7 @@ module Capybara
|
|||
# @return [Capybara::Element] The found element
|
||||
#
|
||||
def find_field(locator)
|
||||
find(:xpath, Capybara::XPath.field(locator))
|
||||
find(:xpath, XPath::HTML.field(locator))
|
||||
end
|
||||
alias_method :field_labeled, :find_field
|
||||
|
||||
|
@ -59,7 +59,7 @@ module Capybara
|
|||
# @return [Capybara::Element] The found element
|
||||
#
|
||||
def find_link(locator)
|
||||
find(:xpath, Capybara::XPath.link(locator))
|
||||
find(:xpath, XPath::HTML.link(locator))
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -70,7 +70,7 @@ module Capybara
|
|||
# @return [Capybara::Element] The found element
|
||||
#
|
||||
def find_button(locator)
|
||||
find(:xpath, Capybara::XPath.button(locator))
|
||||
find(:xpath, XPath::HTML.button(locator))
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -121,7 +121,7 @@ module Capybara
|
|||
def all(*args)
|
||||
options = if args.last.is_a?(Hash) then args.pop else {} end
|
||||
|
||||
results = Capybara::XPath.wrap(normalize_locator(*args)).map do |path|
|
||||
results = XPath::HTML.wrap(normalize_locator(*args)).map do |path|
|
||||
base.find(path)
|
||||
end.flatten
|
||||
|
||||
|
@ -142,7 +142,7 @@ module Capybara
|
|||
|
||||
def normalize_locator(kind, locator=nil)
|
||||
kind, locator = Capybara.default_selector, kind if locator.nil?
|
||||
locator = Capybara::XPath.from_css(locator) if kind == :css
|
||||
locator = XPath::HTML.from_css(locator) if kind == :css
|
||||
locator
|
||||
end
|
||||
|
||||
|
|
|
@ -30,67 +30,67 @@ module Capybara
|
|||
end
|
||||
|
||||
def has_css?(path, options={})
|
||||
has_xpath?(Capybara::XPath.from_css(path), options)
|
||||
has_xpath?(XPath::HTML.from_css(path), options)
|
||||
end
|
||||
|
||||
def has_no_css?(path, options={})
|
||||
has_no_xpath?(Capybara::XPath.from_css(path), options)
|
||||
has_no_xpath?(XPath::HTML.from_css(path), options)
|
||||
end
|
||||
|
||||
def has_content?(content)
|
||||
has_xpath?(Capybara::XPath.content(content))
|
||||
has_xpath?(XPath::HTML.content(content))
|
||||
end
|
||||
|
||||
def has_no_content?(content)
|
||||
has_no_xpath?(Capybara::XPath.content(content))
|
||||
has_no_xpath?(XPath::HTML.content(content))
|
||||
end
|
||||
|
||||
def has_link?(locator)
|
||||
has_xpath?(Capybara::XPath.link(locator))
|
||||
has_xpath?(XPath::HTML.link(locator))
|
||||
end
|
||||
|
||||
def has_no_link?(locator)
|
||||
has_no_xpath?(Capybara::XPath.link(locator))
|
||||
has_no_xpath?(XPath::HTML.link(locator))
|
||||
end
|
||||
|
||||
def has_button?(locator)
|
||||
has_xpath?(Capybara::XPath.button(locator))
|
||||
has_xpath?(XPath::HTML.button(locator))
|
||||
end
|
||||
|
||||
def has_no_button?(locator)
|
||||
has_no_xpath?(Capybara::XPath.button(locator))
|
||||
has_no_xpath?(XPath::HTML.button(locator))
|
||||
end
|
||||
|
||||
def has_field?(locator, options={})
|
||||
has_xpath?(Capybara::XPath.field(locator, options))
|
||||
has_xpath?(XPath::HTML.field(locator, options))
|
||||
end
|
||||
|
||||
def has_no_field?(locator, options={})
|
||||
has_no_xpath?(Capybara::XPath.field(locator, options))
|
||||
has_no_xpath?(XPath::HTML.field(locator, options))
|
||||
end
|
||||
|
||||
def has_checked_field?(locator)
|
||||
has_xpath?(Capybara::XPath.field(locator, :checked => true))
|
||||
has_xpath?(XPath::HTML.field(locator, :checked => true))
|
||||
end
|
||||
|
||||
def has_unchecked_field?(locator)
|
||||
has_xpath?(Capybara::XPath.field(locator, :unchecked => true))
|
||||
has_xpath?(XPath::HTML.field(locator, :unchecked => true))
|
||||
end
|
||||
|
||||
def has_select?(locator, options={})
|
||||
has_xpath?(Capybara::XPath.select(locator, options))
|
||||
has_xpath?(XPath::HTML.select(locator, options))
|
||||
end
|
||||
|
||||
def has_no_select?(locator, options={})
|
||||
has_no_xpath?(Capybara::XPath.select(locator, options))
|
||||
has_no_xpath?(XPath::HTML.select(locator, options))
|
||||
end
|
||||
|
||||
def has_table?(locator, options={})
|
||||
has_xpath?(Capybara::XPath.table(locator, options))
|
||||
has_xpath?(XPath::HTML.table(locator, options))
|
||||
end
|
||||
|
||||
def has_no_table?(locator, options={})
|
||||
has_no_xpath?(Capybara::XPath.table(locator, options))
|
||||
has_no_xpath?(XPath::HTML.table(locator, options))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -170,7 +170,7 @@ module Capybara
|
|||
# @param [String] locator Id or legend of the fieldset
|
||||
#
|
||||
def within_fieldset(locator)
|
||||
within :xpath, Capybara::XPath.fieldset(locator) do
|
||||
within :xpath, XPath::HTML.fieldset(locator) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
@ -182,7 +182,7 @@ module Capybara
|
|||
# @param [String] locator Id or caption of the table
|
||||
#
|
||||
def within_table(locator)
|
||||
within :xpath, Capybara::XPath.table(locator) do
|
||||
within :xpath, XPath::HTML.table(locator) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ shared_examples_for "all" do
|
|||
|
||||
it "should accept an XPath instance" do
|
||||
@session.visit('/form')
|
||||
@xpath = Capybara::XPath.fillable_field('Name')
|
||||
@xpath = XPath::HTML.fillable_field('Name')
|
||||
@result = @session.all(@xpath).map { |r| r.value }
|
||||
@result.should include('Smith', 'John', 'John Smith')
|
||||
end
|
||||
|
|
|
@ -72,7 +72,7 @@ shared_examples_for "find" do
|
|||
|
||||
it "should accept an XPath instance and respect the order of paths" do
|
||||
@session.visit('/form')
|
||||
@xpath = Capybara::XPath.fillable_field('Name')
|
||||
@xpath = XPath::HTML.fillable_field('Name')
|
||||
@session.find(@xpath).value.should == 'John Smith'
|
||||
end
|
||||
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
require 'xpath'
|
||||
|
||||
module Capybara
|
||||
|
||||
module XPath
|
||||
|
||||
include ::XPath
|
||||
extend self
|
||||
|
||||
def from_css(css)
|
||||
XPath::Union.new(*Nokogiri::CSS.xpath_for(css).map { |selector| ::XPath::Expression::Literal.new(:".#{selector}") }.flatten)
|
||||
end
|
||||
|
||||
def link(locator)
|
||||
link = descendant(:a)[attr(:href)]
|
||||
link[attr(:id).equals(locator) | text.is(locator) | attr(:title).is(locator) | descendant(:img)[attr(:alt).is(locator)]]
|
||||
end
|
||||
|
||||
def content(locator)
|
||||
child(:"descendant-or-self::*")[current.n.contains(locator)]
|
||||
end
|
||||
|
||||
def button(locator)
|
||||
button = descendant(:input)[attr(:type).one_of('submit', 'image', 'button')][attr(:id).equals(locator) | attr(:value).is(locator)]
|
||||
button += descendant(:button)[attr(:id).equals(locator) | attr(:value).is(locator) | text.is(locator)]
|
||||
button += descendant(:input)[attr(:type).equals('image')][attr(:alt).is(locator)]
|
||||
end
|
||||
|
||||
def link_or_button(locator)
|
||||
link(locator) + button(locator)
|
||||
end
|
||||
|
||||
def fieldset(locator)
|
||||
descendant(:fieldset)[attr(:id).equals(locator) | descendant(:legend)[text.is(locator)]]
|
||||
end
|
||||
|
||||
def field(locator, options={})
|
||||
if options[:with]
|
||||
fillable_field(locator, options)
|
||||
else
|
||||
xpath = descendant(:input, :textarea, :select)[~attr(:type).one_of('submit', 'image', 'hidden')]
|
||||
xpath = locate_field(xpath, locator)
|
||||
xpath = xpath[attr(:checked)] if options[:checked]
|
||||
xpath = xpath[~attr(:checked)] if options[:unchecked]
|
||||
xpath
|
||||
end
|
||||
end
|
||||
|
||||
def fillable_field(locator, options={})
|
||||
xpath = descendant(:input, :textarea)[~attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')]
|
||||
xpath = locate_field(xpath, locator)
|
||||
xpath = xpath[field_value(options[:with])] if options.has_key?(:with)
|
||||
xpath
|
||||
end
|
||||
|
||||
def select(locator, options={})
|
||||
xpath = locate_field(descendant(:select), locator)
|
||||
|
||||
options[:options].each do |option|
|
||||
xpath = xpath[descendant(:option).text.equals(option)]
|
||||
end if options[:options]
|
||||
|
||||
[options[:selected]].flatten.each do |option|
|
||||
xpath = xpath[descendant(:option)[attr(:selected)].text.equals(option)]
|
||||
end if options[:selected]
|
||||
|
||||
xpath
|
||||
end
|
||||
|
||||
def checkbox(locator, options={})
|
||||
xpath = locate_field(descendant(:input)[attr(:type).equals('checkbox')], locator)
|
||||
end
|
||||
|
||||
def radio_button(locator, options={})
|
||||
locate_field(descendant(:input)[attr(:type).equals('radio')], locator)
|
||||
end
|
||||
|
||||
def file_field(locator, options={})
|
||||
locate_field(descendant(:input)[attr(:type).equals('file')], locator)
|
||||
end
|
||||
|
||||
def option(name)
|
||||
descendant(:option)[text.n.is(name)]
|
||||
end
|
||||
|
||||
def table(locator, options={})
|
||||
xpath = descendant(:table)[attr(:id).equals(locator) | descendant(:caption).contains(locator)]
|
||||
xpath = xpath[table_rows(options[:rows])] if options[:rows]
|
||||
xpath
|
||||
end
|
||||
|
||||
def table_rows(rows)
|
||||
row_conditions = descendant(:tr)[table_row(rows.first)]
|
||||
rows.drop(1).each do |row|
|
||||
row_conditions = row_conditions.next_sibling(:tr)[table_row(row)]
|
||||
end
|
||||
row_conditions
|
||||
end
|
||||
|
||||
def table_row(cells)
|
||||
cell_conditions = child(:td, :th)[text.equals(cells.first)]
|
||||
cells.drop(1).each do |cell|
|
||||
cell_conditions = cell_conditions.next_sibling(:td, :th)[text.equals(cell)]
|
||||
end
|
||||
cell_conditions
|
||||
end
|
||||
|
||||
def wrap(path)
|
||||
if path.respond_to?(:to_xpaths)
|
||||
path.to_xpaths
|
||||
else
|
||||
[path.to_s].flatten
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def locate_field(xpath, locator)
|
||||
locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:id).equals(anywhere(:label)[text.is(locator)].attr(:for))]
|
||||
locate_field += descendant(:label)[text.is(locator)].descendant(xpath)
|
||||
end
|
||||
|
||||
def field_value(value)
|
||||
(text.is(value) & name.equals('textarea')) | (attr(:value).equals(value) & ~name.equals('textarea'))
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue