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.
Files changed (74) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +55 -0
  7. data/Rakefile +139 -0
  8. data/VERSION +1 -0
  9. data/lib/watir-webdriver.rb +71 -0
  10. data/lib/watir-webdriver/attribute_helper.rb +128 -0
  11. data/lib/watir-webdriver/browser.rb +164 -0
  12. data/lib/watir-webdriver/browserbot.js +49 -0
  13. data/lib/watir-webdriver/cell_container.rb +19 -0
  14. data/lib/watir-webdriver/container.rb +40 -0
  15. data/lib/watir-webdriver/core_ext/string.rb +22 -0
  16. data/lib/watir-webdriver/element_collection.rb +96 -0
  17. data/lib/watir-webdriver/elements/button.rb +75 -0
  18. data/lib/watir-webdriver/elements/checkbox.rb +73 -0
  19. data/lib/watir-webdriver/elements/element.rb +265 -0
  20. data/lib/watir-webdriver/elements/file_field.rb +69 -0
  21. data/lib/watir-webdriver/elements/font.rb +11 -0
  22. data/lib/watir-webdriver/elements/form.rb +17 -0
  23. data/lib/watir-webdriver/elements/frame.rb +110 -0
  24. data/lib/watir-webdriver/elements/generated.rb +2541 -0
  25. data/lib/watir-webdriver/elements/hidden.rb +24 -0
  26. data/lib/watir-webdriver/elements/image.rb +51 -0
  27. data/lib/watir-webdriver/elements/input.rb +42 -0
  28. data/lib/watir-webdriver/elements/link.rb +7 -0
  29. data/lib/watir-webdriver/elements/option.rb +55 -0
  30. data/lib/watir-webdriver/elements/radio.rb +49 -0
  31. data/lib/watir-webdriver/elements/select.rb +216 -0
  32. data/lib/watir-webdriver/elements/table.rb +37 -0
  33. data/lib/watir-webdriver/elements/table_cell.rb +36 -0
  34. data/lib/watir-webdriver/elements/table_row.rb +45 -0
  35. data/lib/watir-webdriver/elements/table_section.rb +9 -0
  36. data/lib/watir-webdriver/elements/text_field.rb +97 -0
  37. data/lib/watir-webdriver/exception.rb +21 -0
  38. data/lib/watir-webdriver/extensions/alerts.rb +69 -0
  39. data/lib/watir-webdriver/extensions/cookies.rb +39 -0
  40. data/lib/watir-webdriver/extensions/firefox/webdriver.xpi +0 -0
  41. data/lib/watir-webdriver/extensions/nokogiri.rb +14 -0
  42. data/lib/watir-webdriver/extensions/performance.rb +54 -0
  43. data/lib/watir-webdriver/extensions/wait.rb +141 -0
  44. data/lib/watir-webdriver/html.rb +19 -0
  45. data/lib/watir-webdriver/html/generator.rb +112 -0
  46. data/lib/watir-webdriver/html/idl_sorter.rb +49 -0
  47. data/lib/watir-webdriver/html/spec_extractor.rb +111 -0
  48. data/lib/watir-webdriver/html/util.rb +22 -0
  49. data/lib/watir-webdriver/html/visitor.rb +174 -0
  50. data/lib/watir-webdriver/locators/button_locator.rb +74 -0
  51. data/lib/watir-webdriver/locators/child_cell_locator.rb +32 -0
  52. data/lib/watir-webdriver/locators/child_row_locator.rb +37 -0
  53. data/lib/watir-webdriver/locators/element_locator.rb +352 -0
  54. data/lib/watir-webdriver/locators/text_field_locator.rb +65 -0
  55. data/lib/watir-webdriver/row_container.rb +34 -0
  56. data/lib/watir-webdriver/window_switching.rb +105 -0
  57. data/lib/watir-webdriver/xpath_support.rb +28 -0
  58. data/lib/yard/handlers/watir.rb +57 -0
  59. data/spec/alert_spec.rb +49 -0
  60. data/spec/browser_spec.rb +42 -0
  61. data/spec/container_spec.rb +42 -0
  62. data/spec/element_locator_spec.rb +304 -0
  63. data/spec/element_spec.rb +13 -0
  64. data/spec/html/alerts.html +11 -0
  65. data/spec/html/keylogger.html +15 -0
  66. data/spec/html/wait.html +27 -0
  67. data/spec/implementation.rb +17 -0
  68. data/spec/input_spec.rb +39 -0
  69. data/spec/locator_spec_helper.rb +51 -0
  70. data/spec/spec_helper.rb +14 -0
  71. data/spec/wait_spec.rb +98 -0
  72. data/support/html5.html +90243 -0
  73. data/watir-webdriver.gemspec +59 -0
  74. 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
@@ -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