ayanko-watir-webdriver 0.1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/.gitmodules +3 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.rdoc +55 -0
- data/Rakefile +139 -0
- data/VERSION +1 -0
- data/lib/watir-webdriver.rb +71 -0
- data/lib/watir-webdriver/attribute_helper.rb +128 -0
- data/lib/watir-webdriver/browser.rb +164 -0
- data/lib/watir-webdriver/browserbot.js +49 -0
- data/lib/watir-webdriver/cell_container.rb +19 -0
- data/lib/watir-webdriver/container.rb +40 -0
- data/lib/watir-webdriver/core_ext/string.rb +22 -0
- data/lib/watir-webdriver/element_collection.rb +96 -0
- data/lib/watir-webdriver/elements/button.rb +75 -0
- data/lib/watir-webdriver/elements/checkbox.rb +73 -0
- data/lib/watir-webdriver/elements/element.rb +265 -0
- data/lib/watir-webdriver/elements/file_field.rb +69 -0
- data/lib/watir-webdriver/elements/font.rb +11 -0
- data/lib/watir-webdriver/elements/form.rb +17 -0
- data/lib/watir-webdriver/elements/frame.rb +110 -0
- data/lib/watir-webdriver/elements/generated.rb +2541 -0
- data/lib/watir-webdriver/elements/hidden.rb +24 -0
- data/lib/watir-webdriver/elements/image.rb +51 -0
- data/lib/watir-webdriver/elements/input.rb +42 -0
- data/lib/watir-webdriver/elements/link.rb +7 -0
- data/lib/watir-webdriver/elements/option.rb +55 -0
- data/lib/watir-webdriver/elements/radio.rb +49 -0
- data/lib/watir-webdriver/elements/select.rb +216 -0
- data/lib/watir-webdriver/elements/table.rb +37 -0
- data/lib/watir-webdriver/elements/table_cell.rb +36 -0
- data/lib/watir-webdriver/elements/table_row.rb +45 -0
- data/lib/watir-webdriver/elements/table_section.rb +9 -0
- data/lib/watir-webdriver/elements/text_field.rb +97 -0
- data/lib/watir-webdriver/exception.rb +21 -0
- data/lib/watir-webdriver/extensions/alerts.rb +69 -0
- data/lib/watir-webdriver/extensions/cookies.rb +39 -0
- data/lib/watir-webdriver/extensions/firefox/webdriver.xpi +0 -0
- data/lib/watir-webdriver/extensions/nokogiri.rb +14 -0
- data/lib/watir-webdriver/extensions/performance.rb +54 -0
- data/lib/watir-webdriver/extensions/wait.rb +141 -0
- data/lib/watir-webdriver/html.rb +19 -0
- data/lib/watir-webdriver/html/generator.rb +112 -0
- data/lib/watir-webdriver/html/idl_sorter.rb +49 -0
- data/lib/watir-webdriver/html/spec_extractor.rb +111 -0
- data/lib/watir-webdriver/html/util.rb +22 -0
- data/lib/watir-webdriver/html/visitor.rb +174 -0
- data/lib/watir-webdriver/locators/button_locator.rb +74 -0
- data/lib/watir-webdriver/locators/child_cell_locator.rb +32 -0
- data/lib/watir-webdriver/locators/child_row_locator.rb +37 -0
- data/lib/watir-webdriver/locators/element_locator.rb +352 -0
- data/lib/watir-webdriver/locators/text_field_locator.rb +65 -0
- data/lib/watir-webdriver/row_container.rb +34 -0
- data/lib/watir-webdriver/window_switching.rb +105 -0
- data/lib/watir-webdriver/xpath_support.rb +28 -0
- data/lib/yard/handlers/watir.rb +57 -0
- data/spec/alert_spec.rb +49 -0
- data/spec/browser_spec.rb +42 -0
- data/spec/container_spec.rb +42 -0
- data/spec/element_locator_spec.rb +304 -0
- data/spec/element_spec.rb +13 -0
- data/spec/html/alerts.html +11 -0
- data/spec/html/keylogger.html +15 -0
- data/spec/html/wait.html +27 -0
- data/spec/implementation.rb +17 -0
- data/spec/input_spec.rb +39 -0
- data/spec/locator_spec_helper.rb +51 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/wait_spec.rb +98 -0
- data/support/html5.html +90243 -0
- data/watir-webdriver.gemspec +59 -0
- metadata +238 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module Watir
|
2
|
+
class TextFieldLocator < ElementLocator
|
3
|
+
|
4
|
+
NON_TEXT_TYPES = %w[file radio checkbox submit reset image button hidden url datetime date month week time datetime-local range color]
|
5
|
+
# TODO: better way of finding input text fields?
|
6
|
+
NEGATIVE_TYPE_EXPR = NON_TEXT_TYPES.map { |t| "@type!=#{t.inspect}" }.join(" and ")
|
7
|
+
|
8
|
+
def locate_all
|
9
|
+
find_all_by_multiple
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def build_xpath(selectors)
|
15
|
+
return if selectors.values.any? { |e| e.kind_of? Regexp }
|
16
|
+
|
17
|
+
selectors.delete(:tag_name)
|
18
|
+
|
19
|
+
@building = :textarea
|
20
|
+
textarea_attr_exp = attribute_expression(selectors)
|
21
|
+
|
22
|
+
@building = :input
|
23
|
+
input_attr_exp = attribute_expression(selectors)
|
24
|
+
|
25
|
+
xpath = ".//input[(not(@type) or (#{NEGATIVE_TYPE_EXPR}))"
|
26
|
+
xpath << " and #{input_attr_exp}" unless input_attr_exp.empty?
|
27
|
+
xpath << "] "
|
28
|
+
xpath << "| .//textarea"
|
29
|
+
xpath << "[#{textarea_attr_exp}]" unless textarea_attr_exp.empty?
|
30
|
+
|
31
|
+
p :build_xpath => xpath if $DEBUG
|
32
|
+
|
33
|
+
xpath
|
34
|
+
end
|
35
|
+
|
36
|
+
def lhs_for(key)
|
37
|
+
if @building == :input && key == :text
|
38
|
+
"@value"
|
39
|
+
elsif @building == :textarea && key == :value
|
40
|
+
"text()"
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def matches_selector?(element, rx_selector)
|
47
|
+
rx_selector = rx_selector.dup
|
48
|
+
|
49
|
+
[:text, :value, :label].each do |key|
|
50
|
+
if rx_selector.has_key?(key)
|
51
|
+
correct_key = element.tag_name == 'input' ? :value : :text
|
52
|
+
rx_selector[correct_key] = rx_selector.delete(key)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
VALID_TEXT_FIELD_TAGS = %w[input textarea]
|
60
|
+
|
61
|
+
def tag_name_matches?(element, _)
|
62
|
+
VALID_TEXT_FIELD_TAGS.include?(element.tag_name)
|
63
|
+
end
|
64
|
+
end # TextFieldLocator
|
65
|
+
end # Watir
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Watir
|
2
|
+
module RowContainer
|
3
|
+
|
4
|
+
def row(*args)
|
5
|
+
row = tr(*args)
|
6
|
+
row.locator_class = ChildRowLocator
|
7
|
+
|
8
|
+
row
|
9
|
+
end
|
10
|
+
|
11
|
+
def rows(*args)
|
12
|
+
rows = trs(*args)
|
13
|
+
rows.locator_class = ChildRowLocator
|
14
|
+
|
15
|
+
rows
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# The table as a 2D Array of strings with the text of each cell.
|
20
|
+
#
|
21
|
+
# @return [Array<Array<String>>]
|
22
|
+
#
|
23
|
+
|
24
|
+
def strings
|
25
|
+
assert_exists
|
26
|
+
|
27
|
+
rows.inject [] do |res, row|
|
28
|
+
res << row.cells.map { |cell| cell.text }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias_method :to_a, :strings
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Watir
|
2
|
+
module WindowSwitching
|
3
|
+
|
4
|
+
class NoMatchingWindowFoundException < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
def windows(*args)
|
8
|
+
all = @driver.window_handles.map { |id| Window.new(@driver, id) }
|
9
|
+
|
10
|
+
if args.empty?
|
11
|
+
all
|
12
|
+
else
|
13
|
+
filter_windows(args, all, :select)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def window(*args, &blk)
|
18
|
+
win = filter_windows(args, windows, :find)
|
19
|
+
|
20
|
+
if win && block_given?
|
21
|
+
win.use(&blk)
|
22
|
+
end
|
23
|
+
|
24
|
+
win or raise NoMatchingWindowFoundException, args.inspect
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def filter_windows(args, all, method)
|
30
|
+
sel = extract_selector(args)
|
31
|
+
|
32
|
+
if sel.empty?
|
33
|
+
all.find { |w| w.current? }
|
34
|
+
end
|
35
|
+
|
36
|
+
unless sel.keys.all? { |k| [:title, :url].include? k }
|
37
|
+
raise ArgumentError, "invalid window selector: #{sel.inspect}"
|
38
|
+
end
|
39
|
+
|
40
|
+
all.send(method) do |win|
|
41
|
+
sel.all? { |key, value| value === win.send(key) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end # WindowSwitching
|
45
|
+
|
46
|
+
class Window
|
47
|
+
def initialize(driver, id)
|
48
|
+
@driver, @id = driver, id
|
49
|
+
end
|
50
|
+
|
51
|
+
def inspect
|
52
|
+
'#<%s:0x%x id=%s>' % [self.class, hash*2, @id.to_s]
|
53
|
+
end
|
54
|
+
|
55
|
+
def ==(other)
|
56
|
+
return false unless other.kind_of?(self.class)
|
57
|
+
|
58
|
+
@id == other.id
|
59
|
+
end
|
60
|
+
alias_method :eql?, :==
|
61
|
+
|
62
|
+
def hash
|
63
|
+
@id.hash ^ self.class.hash
|
64
|
+
end
|
65
|
+
|
66
|
+
def current?
|
67
|
+
@driver.window_handle == @id
|
68
|
+
end
|
69
|
+
|
70
|
+
def close
|
71
|
+
use { @driver.close }
|
72
|
+
end
|
73
|
+
|
74
|
+
def title
|
75
|
+
title = nil
|
76
|
+
use { title = @driver.title }
|
77
|
+
|
78
|
+
title
|
79
|
+
end
|
80
|
+
|
81
|
+
def url
|
82
|
+
url = nil
|
83
|
+
use { url = @driver.current_url }
|
84
|
+
|
85
|
+
url
|
86
|
+
end
|
87
|
+
|
88
|
+
def use(&blk)
|
89
|
+
if current?
|
90
|
+
yield if block_given?
|
91
|
+
return self
|
92
|
+
end
|
93
|
+
|
94
|
+
@driver.switch_to.window(@id, &blk)
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def id
|
101
|
+
@id
|
102
|
+
end
|
103
|
+
|
104
|
+
end # Window
|
105
|
+
end # Watir
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Watir
|
3
|
+
module XpathSupport
|
4
|
+
include Selenium
|
5
|
+
|
6
|
+
#
|
7
|
+
# Find the first element matching the given XPath
|
8
|
+
#
|
9
|
+
|
10
|
+
def element_by_xpath(xpath)
|
11
|
+
e = wd.find_element(:xpath, xpath)
|
12
|
+
Watir.element_class_for(e.tag_name).new(self, :element => e)
|
13
|
+
rescue WebDriver::Error::NoSuchElementError
|
14
|
+
Element.new(self, :xpath => xpath)
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Find all elements matching the given XPath
|
19
|
+
#
|
20
|
+
|
21
|
+
def elements_by_xpath(xpath)
|
22
|
+
wd.find_elements(:xpath, xpath).map do |e|
|
23
|
+
Watir.element_class_for(e.tag_name).new(self, :element => e)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end # XpathSupport
|
28
|
+
end # Watir
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "watir-webdriver/core_ext/string"
|
2
|
+
|
3
|
+
module YARD
|
4
|
+
module Handlers
|
5
|
+
module Watir
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
#
|
9
|
+
|
10
|
+
class AttributesHandler < YARD::Handlers::Ruby::Base
|
11
|
+
handles method_call(:attributes)
|
12
|
+
|
13
|
+
TYPES = {
|
14
|
+
:string => "String",
|
15
|
+
:bool => "Boolean",
|
16
|
+
:int => "Integer"
|
17
|
+
}
|
18
|
+
|
19
|
+
def process
|
20
|
+
attributes = try_eval
|
21
|
+
|
22
|
+
if attributes.nil?
|
23
|
+
p :ignoring => statement.source, :in => namespace.to_s
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
TYPES.each do |type, return_type|
|
28
|
+
if attributes.member? type
|
29
|
+
create_attributes attributes[type], return_type
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def create_attributes(names, return_type)
|
37
|
+
names.each do |attribute_name|
|
38
|
+
p :adding => "#{namespace}##{attribute_name}"
|
39
|
+
attribute_name = "#{attribute_name}?".to_sym if return_type == "Boolean"
|
40
|
+
register MethodObject.new(namespace, attribute_name, scope) do |o|
|
41
|
+
o.visibility = :public
|
42
|
+
o.explicit = false
|
43
|
+
o.docstring.add_tag YARD::Tags::Tag.new(:return, "", return_type)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def try_eval
|
49
|
+
eval "{#{statement.parameters.source}}"
|
50
|
+
rescue SyntaxError, StandardError
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
54
|
+
end # AttributesHandler
|
55
|
+
end # Watir
|
56
|
+
end # Handlers
|
57
|
+
end
|
data/spec/alert_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path("watirspec/spec_helper", File.dirname(__FILE__))
|
2
|
+
require "watir-webdriver/extensions/alerts"
|
3
|
+
|
4
|
+
describe "AlertHelper" do
|
5
|
+
before do
|
6
|
+
browser.goto("file://" + File.expand_path("html/alerts.html", File.dirname(__FILE__)))
|
7
|
+
end
|
8
|
+
|
9
|
+
it "handles an alert()" do
|
10
|
+
returned = browser.alert do
|
11
|
+
browser.button(:id => "alert").click
|
12
|
+
end
|
13
|
+
|
14
|
+
returned.should == "ok"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "handles a confirmed confirm()" do
|
18
|
+
returned = browser.confirm(true) do
|
19
|
+
browser.button(:id => "confirm").click
|
20
|
+
end
|
21
|
+
|
22
|
+
returned.should == "set the value"
|
23
|
+
|
24
|
+
browser.button(:id => "confirm").value.should == "true"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "handles a cancelled confirm()" do
|
28
|
+
returned = browser.confirm(false) do
|
29
|
+
browser.button(:id => "confirm").click
|
30
|
+
end
|
31
|
+
|
32
|
+
returned.should == "set the value"
|
33
|
+
|
34
|
+
browser.button(:id => "confirm").value.should == "false"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "handles a prompt()" do
|
38
|
+
returned = browser.prompt("my name") do
|
39
|
+
browser.button(:id => "prompt").click
|
40
|
+
end
|
41
|
+
|
42
|
+
returned.should == {
|
43
|
+
:message => "enter your name",
|
44
|
+
:default => "John Doe"
|
45
|
+
}
|
46
|
+
|
47
|
+
browser.button(:id => "prompt").value.should == "my name"
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path('watirspec/spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Watir::Browser do
|
4
|
+
|
5
|
+
describe ".new" do
|
6
|
+
it "passes the args to webdriver" do
|
7
|
+
Selenium::WebDriver.should_receive(:for).with(:firefox, :foo).and_return(nil)
|
8
|
+
Watir::Browser.new(:firefox, :foo)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "takes a Driver instance as argument" do
|
12
|
+
mock_driver = mock(Selenium::WebDriver::Driver)
|
13
|
+
Selenium::WebDriver::Driver.should_receive(:===).with(mock_driver).and_return(true)
|
14
|
+
|
15
|
+
lambda { Watir::Browser.new(mock_driver) }.should_not raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it "raises ArgumentError for invalid args" do
|
19
|
+
lambda { Watir::Browser.new(Object.new) }.should raise_error(ArgumentError)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#execute_script" do
|
24
|
+
it "returns DOM elements as Watir objects" do
|
25
|
+
browser.goto(WatirSpec.files + "/definition_lists.html")
|
26
|
+
returned = browser.execute_script("return document.getElementById('experience-list')")
|
27
|
+
returned.should be_kind_of(Watir::DList)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
bug "http://github.com/jarib/watirspec/issues/issue/8", [:webdriver, :ie], [:webdriver, :chrome] do
|
32
|
+
it "raises an error when trying to interact with a closed browser" do
|
33
|
+
b = WatirSpec.new_browser
|
34
|
+
b.goto(WatirSpec.files + "/definition_lists.html")
|
35
|
+
b.close
|
36
|
+
|
37
|
+
lambda { b.dl(:id => "experience-list").id }.should raise_error(Error, "browser was closed")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path('watirspec/spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Watir::Container do
|
4
|
+
before { @container = Object.new.extend(Watir::Container) }
|
5
|
+
|
6
|
+
describe "#extract_selector" do
|
7
|
+
before do
|
8
|
+
def @container.public_extract_selector(*args)
|
9
|
+
extract_selector(*args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "converts 2-arg selector into a hash" do
|
14
|
+
@container.public_extract_selector([:how, 'what']).
|
15
|
+
should == { :how => 'what' }
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns the hash given" do
|
19
|
+
@container.public_extract_selector([:how => "what"]).
|
20
|
+
should == { :how => "what" }
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns an empty hash if given no args" do
|
24
|
+
@container.public_extract_selector([]).should == {}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises ArgumentError if given 1 arg which is not a Hash" do
|
28
|
+
lambda {
|
29
|
+
@container.public_extract_selector([:how])
|
30
|
+
}.should raise_error(ArgumentError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "raises ArgumentError if given > 2 args" do
|
34
|
+
lambda {
|
35
|
+
@container.public_extract_selector([:how, 'what', 'value'])
|
36
|
+
}.should raise_error(ArgumentError)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,304 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Watir::ElementLocator do
|
4
|
+
include LocatorSpecHelper
|
5
|
+
|
6
|
+
describe "finds a single element" do
|
7
|
+
describe "by delegating to webdriver" do
|
8
|
+
WEBDRIVER_SELECTORS.each do |loc|
|
9
|
+
it "delegates to webdriver's #{loc} locator" do
|
10
|
+
expect_one(loc, "bar").and_return(element(:tag_name => "div"))
|
11
|
+
locate_one loc => "bar"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "with selectors not supported by webdriver" do
|
17
|
+
it "handles selector with tag name and a single attribute" do
|
18
|
+
expect_one :xpath, ".//div[@class='foo']"
|
19
|
+
|
20
|
+
locate_one :tag_name => "div",
|
21
|
+
:class => "foo"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "handles selector with no tag name and and a single attribute" do
|
25
|
+
expect_one :xpath, ".//*[@title='foo']"
|
26
|
+
locate_one :title => "foo"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "handles selector with tag name and multiple attributes" do
|
30
|
+
expect_one :xpath, ".//div[@class='foo' and @title='bar']"
|
31
|
+
|
32
|
+
locate_one [:tag_name, "div",
|
33
|
+
:class , "foo",
|
34
|
+
:title , 'bar']
|
35
|
+
end
|
36
|
+
|
37
|
+
it "handles selector with no tag name and multiple attributes" do
|
38
|
+
expect_one :xpath, ".//*[@class='foo' and @title='bar']"
|
39
|
+
|
40
|
+
locate_one [:class, "foo",
|
41
|
+
:title, "bar"]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
describe "with special cased selectors" do
|
47
|
+
it "normalizes space for :text" do
|
48
|
+
expect_one :xpath, ".//div[normalize-space()='foo']"
|
49
|
+
locate_one :tag_name => "div",
|
50
|
+
:text => "foo"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "translates :caption to :text" do
|
54
|
+
expect_one :xpath, ".//div[normalize-space()='foo']"
|
55
|
+
|
56
|
+
locate_one :tag_name => "div",
|
57
|
+
:caption => "foo"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "translates :class_name to :class" do
|
61
|
+
expect_one :xpath, ".//div[@class='foo']"
|
62
|
+
|
63
|
+
locate_one :tag_name => "div",
|
64
|
+
:class_name => "foo"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "handles data-* attributes" do
|
68
|
+
expect_one :xpath, ".//div[@data-name='foo']"
|
69
|
+
|
70
|
+
locate_one :tag_name => "div",
|
71
|
+
:data_name => "foo"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "normalizes space for the :href attribute" do
|
75
|
+
expect_one :xpath, ".//a[normalize-space(@href)='foo']"
|
76
|
+
|
77
|
+
selector = {
|
78
|
+
:tag_name => "a",
|
79
|
+
:href => "foo"
|
80
|
+
}
|
81
|
+
|
82
|
+
locate_one selector, Watir::Anchor.attributes
|
83
|
+
end
|
84
|
+
|
85
|
+
it "uses the corresponding <label>'s @for attribute when locating by label" do
|
86
|
+
expect_one :xpath, ".//input[@type='text' and @id=//label[normalize-space()='foo']/@for]"
|
87
|
+
|
88
|
+
selector = [
|
89
|
+
:tag_name, "input",
|
90
|
+
:type , "text",
|
91
|
+
:label , "foo"
|
92
|
+
]
|
93
|
+
|
94
|
+
locate_one selector, Watir::Input.attributes
|
95
|
+
end
|
96
|
+
|
97
|
+
it "does not use the label element for <option> elements" do
|
98
|
+
expect_one :xpath, ".//option[@label='foo']"
|
99
|
+
|
100
|
+
locate_one :tag_name => "option",
|
101
|
+
:label => "foo"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "translates ruby attribute names to content attribute names" do
|
105
|
+
expect_one :xpath, ".//meta[@http-equiv='foo']"
|
106
|
+
|
107
|
+
selector = {
|
108
|
+
:tag_name => "meta",
|
109
|
+
:http_equiv => "foo"
|
110
|
+
}
|
111
|
+
|
112
|
+
locate_one selector, Watir::Meta.attributes
|
113
|
+
|
114
|
+
# TODO: check edge cases
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "with regexp selectors" do
|
119
|
+
it "handles selector with tag name and a single regexp attribute" do
|
120
|
+
elements = [
|
121
|
+
element(:tag_name => "div", :attributes => { :class => "foo" }),
|
122
|
+
element(:tag_name => "div", :attributes => { :class => "foob"})
|
123
|
+
]
|
124
|
+
|
125
|
+
expect_all(:xpath, ".//div").and_return(elements)
|
126
|
+
locate_one(:tag_name => "div", :class => /oob/).should == elements[1]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "handles :tag_name, :index and a single regexp attribute" do
|
130
|
+
elements = [
|
131
|
+
element(:tag_name => "div", :attributes => { :class => "foo" }),
|
132
|
+
element(:tag_name => "div", :attributes => { :class => "foo" })
|
133
|
+
]
|
134
|
+
|
135
|
+
expect_all(:xpath, ".//div").and_return(elements)
|
136
|
+
|
137
|
+
selector = {
|
138
|
+
:tag_name => "div",
|
139
|
+
:class => /foo/,
|
140
|
+
:index => 1
|
141
|
+
}
|
142
|
+
|
143
|
+
locate_one(selector).should == elements[1]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "handles mix of string and regexp attributes" do
|
147
|
+
elements = [
|
148
|
+
element(:tag_name => "div", :attributes => { :class => "foo", :title => "bar" }),
|
149
|
+
element(:tag_name => "div", :attributes => { :class => "foo", :title => "baz" })
|
150
|
+
]
|
151
|
+
|
152
|
+
expect_all(:xpath, ".//div[@class='foo']").and_return(elements)
|
153
|
+
|
154
|
+
selector = {
|
155
|
+
:tag_name => "div",
|
156
|
+
:class => "foo",
|
157
|
+
:title => /baz/
|
158
|
+
}
|
159
|
+
|
160
|
+
locate_one(selector).should == elements[1]
|
161
|
+
end
|
162
|
+
|
163
|
+
it "handles :label => /regexp/ selector" do
|
164
|
+
label_elements = [
|
165
|
+
element(:tag_name => "label", :text => "foo", :attributes => { :for => "bar"}),
|
166
|
+
element(:tag_name => "label", :text => "foob", :attributes => { :for => "baz"})
|
167
|
+
]
|
168
|
+
div_elements = [element(:tag_name => "div")]
|
169
|
+
|
170
|
+
expect_all(:tag_name, "label").ordered.and_return(label_elements)
|
171
|
+
expect_all(:xpath, ".//div[@id='baz']").ordered.and_return(div_elements)
|
172
|
+
|
173
|
+
locate_one(:tag_name => "div", :label => /oob/).should == div_elements.first
|
174
|
+
end
|
175
|
+
|
176
|
+
it "returns nil when no label matching the regexp is found" do
|
177
|
+
expect_all(:tag_name, "label").and_return([])
|
178
|
+
locate_one(:tag_name => "div", :label => /foo/).should be_nil
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
it "finds all if :index is given" do
|
184
|
+
# or could we use XPath indeces reliably instead?
|
185
|
+
elements = [
|
186
|
+
element(:tag_name => "div"),
|
187
|
+
element(:tag_name => "div")
|
188
|
+
]
|
189
|
+
|
190
|
+
expect_all(:xpath, ".//div[@class='foo']").and_return(elements)
|
191
|
+
|
192
|
+
selector = {
|
193
|
+
:tag_name => "div",
|
194
|
+
:class => "foo",
|
195
|
+
:index => 1
|
196
|
+
}
|
197
|
+
|
198
|
+
locate_one(selector).should == elements[1]
|
199
|
+
end
|
200
|
+
|
201
|
+
it "returns nil if found element didn't match the selector tag_name" do
|
202
|
+
expect_one(:xpath, "//div").and_return(element(:tag_name => "div"))
|
203
|
+
|
204
|
+
selector = {
|
205
|
+
:tag_name => "input",
|
206
|
+
:xpath => "//div"
|
207
|
+
}
|
208
|
+
|
209
|
+
locate_one(selector, Watir::Input.attributes).should be_nil
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "errors" do
|
213
|
+
it "raises a TypeError if :index is not a Fixnum" do
|
214
|
+
lambda {
|
215
|
+
locate_one(:tag_name => "div", :index => "bar")
|
216
|
+
}.should raise_error(TypeError, %[expected Fixnum, got "bar":String])
|
217
|
+
end
|
218
|
+
|
219
|
+
it "raises a TypeError if selector value is not a String or Regexp" do
|
220
|
+
lambda {
|
221
|
+
locate_one(:tag_name => 123)
|
222
|
+
}.should raise_error(TypeError, %[expected one of [String, Regexp], got 123:Fixnum])
|
223
|
+
end
|
224
|
+
|
225
|
+
it "raises a MissingWayOfFindingObjectException if the attribute is not valid" do
|
226
|
+
bad_selector = {:tag_name => "input", :href => "foo"}
|
227
|
+
valid_attributes = Watir::Input.attributes
|
228
|
+
|
229
|
+
lambda {
|
230
|
+
locate_one(bad_selector, valid_attributes)
|
231
|
+
}.should raise_error(MissingWayOfFindingObjectException, "invalid attribute: :href")
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "finds several elements" do
|
237
|
+
describe "by delegating to webdriver" do
|
238
|
+
WEBDRIVER_SELECTORS.each do |loc|
|
239
|
+
it "delegates to webdriver's #{loc} locator" do
|
240
|
+
expect_all(loc, "bar").and_return([element(:tag_name => "div")])
|
241
|
+
locate_all(loc => "bar")
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe "with selectors not supported by webdriver" do
|
247
|
+
it "handles selector with tag name and a single attribute" do
|
248
|
+
expect_all :xpath, ".//div[@class='foo']"
|
249
|
+
|
250
|
+
locate_all :tag_name => "div",
|
251
|
+
:class => "foo"
|
252
|
+
end
|
253
|
+
|
254
|
+
it "handles selector with tag name and multiple attributes" do
|
255
|
+
expect_all :xpath, ".//div[@class='foo' and @title='bar']"
|
256
|
+
|
257
|
+
locate_all [:tag_name, "div",
|
258
|
+
:class , "foo",
|
259
|
+
:title , 'bar']
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe "with regexp selectors" do
|
264
|
+
it "handles selector with tag name and a single regexp attribute" do
|
265
|
+
elements = [
|
266
|
+
element(:tag_name => "div", :attributes => { :class => "foo" }),
|
267
|
+
element(:tag_name => "div", :attributes => { :class => "foob"}),
|
268
|
+
element(:tag_name => "div", :attributes => { :class => "doob"}),
|
269
|
+
element(:tag_name => "div", :attributes => { :class => "noob"})
|
270
|
+
]
|
271
|
+
|
272
|
+
expect_all(:xpath, ".//div").and_return(elements)
|
273
|
+
locate_all(:tag_name => "div", :class => /oob/).should == elements.last(3)
|
274
|
+
end
|
275
|
+
|
276
|
+
it "handles mix of string and regexp attributes" do
|
277
|
+
elements = [
|
278
|
+
element(:tag_name => "div", :attributes => { :class => "foo", :title => "bar" }),
|
279
|
+
element(:tag_name => "div", :attributes => { :class => "foo", :title => "baz" }),
|
280
|
+
element(:tag_name => "div", :attributes => { :class => "foo", :title => "bazt"})
|
281
|
+
]
|
282
|
+
|
283
|
+
expect_all(:xpath, ".//div[@class='foo']").and_return(elements)
|
284
|
+
|
285
|
+
selector = {
|
286
|
+
:tag_name => "div",
|
287
|
+
:class => "foo",
|
288
|
+
:title => /baz/
|
289
|
+
}
|
290
|
+
|
291
|
+
locate_all(selector).should == elements.last(2)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "errors" do
|
296
|
+
it "raises ArgumentError if :index is given" do
|
297
|
+
lambda {
|
298
|
+
locate_all(:tag_name => "div", :index => 1)
|
299
|
+
}.should raise_error(ArgumentError, "can't locate all elements by :index")
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|