move xpath gem html definitions into capybara

This commit is contained in:
Thomas Walpole 2016-03-24 11:18:12 -07:00
parent 5695789460
commit 2eda1540b9
4 changed files with 143 additions and 18 deletions

View File

@ -5,6 +5,7 @@ Release date: unreleased
* Element#visible?/checked?/disabled?/selected? Now return boolean
as expected when using the rack_test driver [Thomas Walpole]
* The rack_test driver now considers \<input type="hidden"> elements as non-visible [Thomas Walpole]
* A nil locator passed to the built-in html type selectors now behaves consistently, and finds all elements of the correct type [Thomas Walpole]
### Added
* :multiple filter added to relevant selectors [Thomas Walpole]

View File

@ -37,6 +37,7 @@ Gem::Specification.new do |s|
s.add_development_dependency("cucumber", [">= 0.10.5"])
s.add_development_dependency("rake", ["< 11.0"])
s.add_development_dependency("pry")
s.add_development_dependency("byebug")
if RUBY_ENGINE == 'rbx' then
s.add_development_dependency("racc")

View File

@ -119,6 +119,17 @@ module Capybara
def describe &block
@description = block
end
private
def locate_field(xpath, locator)
locate_field = xpath[XPath.attr(:id).equals(locator) |
XPath.attr(:name).equals(locator) |
XPath.attr(:placeholder).equals(locator) |
XPath.attr(:id).equals(XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for))]
locate_field += XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath)
locate_field
end
end
end
@ -135,7 +146,11 @@ Capybara.add_selector(:id) do
end
Capybara.add_selector(:field) do
xpath { |locator| XPath::HTML.field(locator) }
xpath do |locator|
xpath = XPath.descendant(:input, :textarea, :select)[~XPath.attr(:type).one_of('submit', 'image', 'hidden')]
xpath = locate_field(xpath, locator.to_s) unless locator.nil?
xpath
end
filter(:checked, boolean: true) { |node, value| not(value ^ node.checked?) }
filter(:unchecked, boolean: true) { |node, value| (value ^ node.checked?) }
filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
@ -164,18 +179,26 @@ Capybara.add_selector(:field) do
end
Capybara.add_selector(:fieldset) do
xpath { |locator| XPath::HTML.fieldset(locator) }
end
Capybara.add_selector(:link_or_button) do
label "link or button"
xpath { |locator| XPath::HTML.link_or_button(locator) }
filter(:disabled, default: false, boolean: true) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) }
describe { |options| " that is disabled" if options[:disabled] }
xpath do |locator|
xpath = XPath.descendant(:fieldset)
xpath = xpath[XPath.attr(:id).equals(locator.to_s) | XPath.child(:legend)[XPath.string.n.is(locator.to_s)]] unless locator.nil?
xpath
end
end
Capybara.add_selector(:link) do
xpath { |locator| XPath::HTML.link(locator) }
xpath do |locator|
xpath = XPath.descendant(:a)[XPath.attr(:href)]
unless locator.nil?
locator = locator.to_s
xpath = xpath[XPath.attr(:id).equals(locator) |
XPath.string.n.is(locator) |
XPath.attr(:title).is(locator) |
XPath.descendant(:img)[XPath.attr(:alt).is(locator)]]
end
xpath
end
filter(:href) do |node, href|
if href.is_a? Regexp
node[:href].match href
@ -183,20 +206,53 @@ Capybara.add_selector(:link) do
node.first(:xpath, XPath.axis(:self)[XPath.attr(:href).equals(href.to_s)], minimum: 0)
end
end
describe { |options| " with href #{options[:href].inspect}" if options[:href] }
end
Capybara.add_selector(:button) do
xpath { |locator| XPath::HTML.button(locator) }
xpath do |locator|
input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
btn_xpath = XPath.descendant(:button)
image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).equals('image')]
unless locator.nil?
locator = locator.to_s
input_btn_xpath = input_btn_xpath[XPath.attr(:id).equals(locator) | XPath.attr(:value).is(locator) | XPath.attr(:title).is(locator)]
btn_xpath = btn_xpath[XPath.attr(:id).equals(locator) | XPath.attr(:value).is(locator) | XPath.string.n.is(locator) | XPath.attr(:title).is(locator)]
image_btn_xpath = image_btn_xpath[XPath.attr(:alt).is(locator)]
end
input_btn_xpath + btn_xpath + image_btn_xpath
end
filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
describe { |options| " that is disabled" if options[:disabled] == true }
end
Capybara.add_selector(:link_or_button) do
label "link or button"
xpath do |locator|
self.class.all.values_at(:link, :button).map {|selector| selector.xpath.call(locator)}.reduce(:+)
end
filter(:disabled, default: false, boolean: true) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) }
describe { |options| " that is disabled" if options[:disabled] }
end
Capybara.add_selector(:fillable_field) do
label "field"
xpath { |locator| XPath::HTML.fillable_field(locator) }
xpath do |locator|
xpath = XPath.descendant(:input, :textarea)[~XPath.attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')]
xpath = locate_field(xpath, locator.to_s) unless locator.nil?
xpath
end
filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
filter(:multiple, boolean: true) { |node, value| !(value ^ node[:multiple]) }
describe do |options|
desc = String.new
desc << " that is disabled" if options[:disabled] == true
@ -208,11 +264,17 @@ end
Capybara.add_selector(:radio_button) do
label "radio button"
xpath { |locator| XPath::HTML.radio_button(locator) }
xpath do |locator|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('radio')]
xpath = locate_field(xpath, locator.to_s) unless locator.nil?
xpath
end
filter(:checked, boolean: true) { |node, value| not(value ^ node.checked?) }
filter(:unchecked, boolean: true) { |node, value| (value ^ node.checked?) }
filter(:option) { |node, value| node.value == value.to_s }
filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
describe do |options|
desc, states = String.new, []
desc << " with value #{options[:option].inspect}" if options[:option]
@ -225,11 +287,17 @@ Capybara.add_selector(:radio_button) do
end
Capybara.add_selector(:checkbox) do
xpath { |locator| XPath::HTML.checkbox(locator) }
xpath do |locator|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('checkbox')]
xpath = locate_field(xpath, locator.to_s) unless locator.nil?
xpath
end
filter(:checked, boolean: true) { |node, value| not(value ^ node.checked?) }
filter(:unchecked, boolean: true) { |node, value| (value ^ node.checked?) }
filter(:option) { |node, value| node.value == value.to_s }
filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
describe do |options|
desc, states = String.new, []
desc << " with value #{options[:option].inspect}" if options[:option]
@ -243,7 +311,12 @@ end
Capybara.add_selector(:select) do
label "select box"
xpath { |locator| XPath::HTML.select(locator) }
xpath do |locator|
xpath = XPath.descendant(:select)
xpath = locate_field(xpath, locator.to_s) unless locator.nil?
xpath
end
filter(:options) do |node, options|
if node.visible?
actual = node.all(:xpath, './/option').map { |option| option.text }
@ -265,6 +338,7 @@ Capybara.add_selector(:select) do
end
filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
filter(:multiple, boolean: true) { |node, value| !(value ^ node[:multiple]) }
describe do |options|
desc = String.new
desc << " with options #{options[:options].inspect}" if options[:options]
@ -278,14 +352,24 @@ Capybara.add_selector(:select) do
end
Capybara.add_selector(:option) do
xpath { |locator| XPath::HTML.option(locator) }
xpath do |locator|
xpath = XPath.descendant(:option)
xpath = xpath[XPath.string.n.is(locator.to_s)] unless locator.nil?
xpath
end
end
Capybara.add_selector(:file_field) do
label "file field"
xpath { |locator| XPath::HTML.file_field(locator) }
xpath do |locator|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('file')]
xpath = locate_field(xpath, locator.to_s) unless locator.nil?
xpath
end
filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
filter(:multiple, boolean: true) { |node, value| !(value ^ node[:multiple]) }
describe do |options|
desc = String.new
desc << " that is disabled" if options[:disabled] == true
@ -296,5 +380,9 @@ Capybara.add_selector(:file_field) do
end
Capybara.add_selector(:table) do
xpath { |locator| XPath::HTML.table(locator) }
xpath do |locator|
xpath = XPath.descendant(:table)
xpath = xpath[XPath.attr(:id).equals(locator.to_s) | XPath.descendant(:caption).is(locator.to_s)] unless locator.nil?
xpath
end
end

View File

@ -18,6 +18,18 @@ RSpec.describe Capybara do
<p class="b">Some Content</p>
<p class="b"></p>
</div>
<input type="checkbox"/>
<input type="radio"/>
<input type="text"/>
<input type="file"/>
<a href="#">link</a>
<fieldset></fieldset>
<select>
<option value="a">A</option>
</select>
<table>
<tr><td></td></tr>
</table
</body>
</html>
STRING
@ -50,5 +62,28 @@ RSpec.describe Capybara do
expect(string).to have_selector(:custom_selector, 'b', not_empty: :all, count: 2)
end
end
describe "builtin selectors with nil locators" do
it "devolves to just finding element types" do
selectors = {
field: ".//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]",
fieldset: ".//fieldset",
link: ".//a[./@href]",
link_or_button: ".//a[./@href] | .//input[./@type = 'submit' or ./@type = 'reset' or ./@type = 'image' or ./@type = 'button'] | .//button" ,
fillable_field: ".//*[self::input | self::textarea][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'radio' or ./@type = 'checkbox' or ./@type = 'hidden' or ./@type = 'file')]",
radio_button: ".//input[./@type = 'radio']",
checkbox: ".//input[./@type = 'checkbox']",
select: ".//select",
option: ".//option",
file_field: ".//input[./@type = 'file']",
table: ".//table"
}
selectors.each do |selector, xpath|
results = string.all(selector,nil).to_a.map &:native
expect(results.size).to be > 0
expect(results).to eq string.all(:xpath, xpath).to_a.map(&:native)
end
end
end
end
end