watir 5.0.0 → 6.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/.document +5 -0
  3. data/.gitignore +21 -0
  4. data/.gitmodules +3 -0
  5. data/.travis.yml +35 -0
  6. data/CHANGES.md +1756 -0
  7. data/Gemfile +12 -0
  8. data/LICENSE +23 -0
  9. data/README.md +92 -0
  10. data/Rakefile +161 -32
  11. data/lib/watir.rb +127 -1
  12. data/lib/watir/after_hooks.rb +132 -0
  13. data/lib/watir/alert.rb +104 -0
  14. data/lib/watir/aliases.rb +6 -0
  15. data/lib/watir/atoms.rb +24 -0
  16. data/lib/watir/atoms/README +3 -0
  17. data/lib/watir/atoms/fireEvent.js +29 -0
  18. data/lib/watir/atoms/getAttribute.js +18 -0
  19. data/lib/watir/atoms/getInnerHtml.js +18 -0
  20. data/lib/watir/atoms/getOuterHtml.js +18 -0
  21. data/lib/watir/atoms/getParentElement.js +17 -0
  22. data/lib/watir/atoms/selectText.js +61 -0
  23. data/lib/watir/attribute_helper.rb +98 -0
  24. data/lib/watir/browser.rb +346 -0
  25. data/lib/watir/cell_container.rb +25 -0
  26. data/lib/watir/container.rb +51 -0
  27. data/lib/watir/cookies.rb +132 -0
  28. data/lib/watir/element_collection.rb +126 -0
  29. data/lib/watir/elements/area.rb +12 -0
  30. data/lib/watir/elements/button.rb +37 -0
  31. data/lib/watir/elements/cell.rb +17 -0
  32. data/lib/watir/elements/checkbox.rb +54 -0
  33. data/lib/watir/elements/dlist.rb +12 -0
  34. data/lib/watir/elements/element.rb +646 -0
  35. data/lib/watir/elements/file_field.rb +41 -0
  36. data/lib/watir/elements/font.rb +11 -0
  37. data/lib/watir/elements/form.rb +17 -0
  38. data/lib/watir/elements/hidden.rb +20 -0
  39. data/lib/watir/elements/html_elements.rb +2063 -0
  40. data/lib/watir/elements/iframe.rb +163 -0
  41. data/lib/watir/elements/image.rb +62 -0
  42. data/lib/watir/elements/input.rb +7 -0
  43. data/lib/watir/elements/link.rb +18 -0
  44. data/lib/watir/elements/option.rb +74 -0
  45. data/lib/watir/elements/radio.rb +42 -0
  46. data/lib/watir/elements/row.rb +17 -0
  47. data/lib/watir/elements/select.rb +238 -0
  48. data/lib/watir/elements/svg_elements.rb +667 -0
  49. data/lib/watir/elements/table.rb +42 -0
  50. data/lib/watir/elements/table_cell.rb +6 -0
  51. data/lib/watir/elements/table_row.rb +15 -0
  52. data/lib/watir/elements/table_section.rb +15 -0
  53. data/lib/watir/elements/text_area.rb +5 -0
  54. data/lib/watir/elements/text_field.rb +37 -0
  55. data/lib/watir/exception.rb +17 -0
  56. data/lib/watir/extensions/nokogiri.rb +14 -0
  57. data/lib/watir/extensions/select_text.rb +10 -0
  58. data/lib/watir/generator.rb +3 -0
  59. data/lib/watir/generator/base.rb +11 -0
  60. data/lib/watir/generator/base/generator.rb +115 -0
  61. data/lib/watir/generator/base/idl_sorter.rb +47 -0
  62. data/lib/watir/generator/base/spec_extractor.rb +138 -0
  63. data/lib/watir/generator/base/util.rb +21 -0
  64. data/lib/watir/generator/base/visitor.rb +157 -0
  65. data/lib/watir/generator/html.rb +15 -0
  66. data/lib/watir/generator/html/generator.rb +36 -0
  67. data/lib/watir/generator/html/spec_extractor.rb +50 -0
  68. data/lib/watir/generator/html/visitor.rb +21 -0
  69. data/lib/watir/generator/svg.rb +7 -0
  70. data/lib/watir/generator/svg/generator.rb +38 -0
  71. data/lib/watir/generator/svg/spec_extractor.rb +46 -0
  72. data/lib/watir/generator/svg/visitor.rb +21 -0
  73. data/lib/watir/has_window.rb +53 -0
  74. data/lib/watir/locators.rb +22 -0
  75. data/lib/watir/locators/button/locator.rb +38 -0
  76. data/lib/watir/locators/button/selector_builder.rb +27 -0
  77. data/lib/watir/locators/button/selector_builder/xpath.rb +29 -0
  78. data/lib/watir/locators/button/validator.rb +15 -0
  79. data/lib/watir/locators/cell/locator.rb +17 -0
  80. data/lib/watir/locators/cell/selector_builder.rb +24 -0
  81. data/lib/watir/locators/element/locator.rb +249 -0
  82. data/lib/watir/locators/element/selector_builder.rb +147 -0
  83. data/lib/watir/locators/element/selector_builder/css.rb +65 -0
  84. data/lib/watir/locators/element/selector_builder/xpath.rb +72 -0
  85. data/lib/watir/locators/element/validator.rb +23 -0
  86. data/lib/watir/locators/row/locator.rb +17 -0
  87. data/lib/watir/locators/row/selector_builder.rb +29 -0
  88. data/lib/watir/locators/text_area/locator.rb +13 -0
  89. data/lib/watir/locators/text_area/selector_builder.rb +22 -0
  90. data/lib/watir/locators/text_field/locator.rb +44 -0
  91. data/lib/watir/locators/text_field/selector_builder.rb +34 -0
  92. data/lib/watir/locators/text_field/selector_builder/xpath.rb +19 -0
  93. data/lib/watir/locators/text_field/validator.rb +20 -0
  94. data/lib/watir/row_container.rb +36 -0
  95. data/lib/watir/screenshot.rb +50 -0
  96. data/lib/watir/user_editable.rb +38 -0
  97. data/lib/watir/version.rb +3 -3
  98. data/lib/watir/wait.rb +250 -0
  99. data/lib/watir/wait/timer.rb +19 -0
  100. data/lib/watir/window.rb +244 -0
  101. data/lib/watir/xpath_support.rb +20 -0
  102. data/spec/always_locate_spec.rb +43 -0
  103. data/spec/browser_spec.rb +130 -0
  104. data/spec/click_spec.rb +19 -0
  105. data/spec/container_spec.rb +34 -0
  106. data/spec/element_locator_spec.rb +532 -0
  107. data/spec/element_spec.rb +136 -0
  108. data/spec/implementation.rb +216 -0
  109. data/spec/input_spec.rb +14 -0
  110. data/spec/locator_spec_helper.rb +57 -0
  111. data/spec/spec_helper.rb +35 -0
  112. data/spec/special_chars_spec.rb +13 -0
  113. data/support/doctest_helper.rb +78 -0
  114. data/support/travis.sh +44 -0
  115. data/support/version_differ.rb +59 -0
  116. data/watir.gemspec +37 -25
  117. metadata +288 -23
  118. data/lib/watir/loader.rb +0 -64
@@ -0,0 +1,346 @@
1
+ module Watir
2
+
3
+ #
4
+ # The main class through which you control the browser.
5
+ #
6
+
7
+ class Browser
8
+ include Container
9
+ include HasWindow
10
+ include Waitable
11
+
12
+ attr_reader :driver
13
+ attr_reader :after_hooks
14
+ alias_method :wd, :driver # ensures duck typing with Watir::Element
15
+
16
+ class << self
17
+ #
18
+ # Creates a Watir::Browser instance and goes to URL.
19
+ #
20
+ # @example
21
+ # browser = Watir::Browser.start "www.google.com", :chrome
22
+ # #=> #<Watir::Browser:0x..fa45a499cb41e1752 url="http://www.google.com" title="Google">
23
+ #
24
+ # @param [String] url
25
+ # @param [Symbol, Selenium::WebDriver] browser :firefox, :ie, :chrome, :remote or Selenium::WebDriver instance
26
+ # @return [Watir::Browser]
27
+ #
28
+ def start(url, browser = :chrome, *args)
29
+ b = new(browser, *args)
30
+ b.goto url
31
+
32
+ b
33
+ end
34
+ end
35
+
36
+ #
37
+ # Creates a Watir::Browser instance.
38
+ #
39
+ # @param [Symbol, Selenium::WebDriver] browser :firefox, :ie, :chrome, :remote or Selenium::WebDriver instance
40
+ # @param args Passed to the underlying driver
41
+ #
42
+
43
+ def initialize(browser = :chrome, *args)
44
+ case browser
45
+ when ::Symbol, String
46
+ @driver = Selenium::WebDriver.for browser.to_sym, *args
47
+ when Selenium::WebDriver::Driver
48
+ @driver = browser
49
+ else
50
+ raise ArgumentError, "expected Symbol or Selenium::WebDriver::Driver, got #{browser.class}"
51
+ end
52
+
53
+ @after_hooks = AfterHooks.new(self)
54
+ @current_frame = nil
55
+ @closed = false
56
+ end
57
+
58
+ def inspect
59
+ '#<%s:0x%x url=%s title=%s>' % [self.class, hash*2, url.inspect, title.inspect]
60
+ rescue
61
+ '#<%s:0x%x closed=%s>' % [self.class, hash*2, @closed.to_s]
62
+ end
63
+
64
+ #
65
+ # Goes to the given URL.
66
+ #
67
+ # @example
68
+ # browser.goto "watir.github.io"
69
+ #
70
+ # @param [String] uri The url.
71
+ # @return [String] The url you end up at.
72
+ #
73
+
74
+ def goto(uri)
75
+ uri = "http://#{uri}" unless uri =~ URI.regexp
76
+
77
+ @driver.navigate.to uri
78
+ @after_hooks.run
79
+
80
+ uri
81
+ end
82
+
83
+ #
84
+ # Navigates back in history.
85
+ #
86
+
87
+ def back
88
+ @driver.navigate.back
89
+ end
90
+
91
+ #
92
+ # Navigates forward in history.
93
+ #
94
+
95
+ def forward
96
+ @driver.navigate.forward
97
+ end
98
+
99
+ #
100
+ # Returns URL of current page.
101
+ #
102
+ # @example
103
+ # browser.goto "watir.github.io"
104
+ # browser.url
105
+ # #=> "http://watir.github.io/"
106
+ #
107
+ # @return [String]
108
+ #
109
+
110
+ def url
111
+ assert_exists
112
+ @driver.current_url
113
+ end
114
+
115
+ #
116
+ # Returns title of current page.
117
+ #
118
+ # @example
119
+ # browser.goto "watir.github.io"
120
+ # browser.title
121
+ # #=> "Watir is... – Watir Project – Watir stands for Web Application Testing In Ruby. It facilitates the writing of automated tests by mimicking the behavior of a user interacting with a website."
122
+ #
123
+ # @return [String]
124
+ #
125
+
126
+ def title
127
+ @driver.title
128
+ end
129
+
130
+ #
131
+ # Closes browser.
132
+ #
133
+
134
+ def close
135
+ return if @closed
136
+ @driver.quit
137
+ @closed = true
138
+ end
139
+ alias_method :quit, :close # TODO: close vs quit
140
+
141
+ #
142
+ # Handles cookies.
143
+ #
144
+ # @return [Watir::Cookies]
145
+ #
146
+
147
+ def cookies
148
+ @cookies ||= Cookies.new driver.manage
149
+ end
150
+
151
+ #
152
+ # Returns browser name.
153
+ #
154
+ # @example
155
+ # browser = Watir::Browser.new :chrome
156
+ # browser.name
157
+ # #=> :chrome
158
+ #
159
+ # @return [Symbol]
160
+ #
161
+
162
+ def name
163
+ @driver.browser
164
+ end
165
+
166
+ #
167
+ # Returns text of page body.
168
+ #
169
+ # @return [String]
170
+ #
171
+
172
+ def text
173
+ body.text
174
+ end
175
+
176
+ #
177
+ # Returns HTML code of current page.
178
+ #
179
+ # @return [String]
180
+ #
181
+
182
+ def html
183
+ # use body.html instead?
184
+ @driver.page_source
185
+ end
186
+
187
+ #
188
+ # Handles JavaScript alerts, confirms and prompts.
189
+ #
190
+ # @return [Watir::Alert]
191
+ #
192
+
193
+ def alert
194
+ Alert.new(self)
195
+ end
196
+
197
+ #
198
+ # Refreshes current page.
199
+ #
200
+
201
+ def refresh
202
+ @driver.navigate.refresh
203
+ @after_hooks.run
204
+ end
205
+
206
+ #
207
+ # Waits until readyState of document is complete.
208
+ #
209
+ # @param [Fixnum] timeout
210
+ # @raise [Watir::Wait::TimeoutError] if timeout is exceeded
211
+ #
212
+
213
+ def wait(timeout = 5)
214
+ wait_until(timeout, "waiting for document.readyState == 'complete'") do
215
+ ready_state == "complete"
216
+ end
217
+ end
218
+
219
+ #
220
+ # Returns readyState of document.
221
+ #
222
+ # @return [String]
223
+ #
224
+
225
+ def ready_state
226
+ execute_script 'return document.readyState'
227
+ end
228
+
229
+ #
230
+ # Returns the text of status bar.
231
+ #
232
+ # @return [String]
233
+ #
234
+
235
+ def status
236
+ execute_script "return window.status;"
237
+ end
238
+
239
+ #
240
+ # Executes JavaScript snippet.
241
+ #
242
+ # If you are going to use the value snippet returns, make sure to use
243
+ # `return` explicitly.
244
+ #
245
+ # @example Check that Ajax requests are completed with jQuery
246
+ # browser.execute_script("return jQuery.active") == 0
247
+ # #=> true
248
+ #
249
+ # @param [String] script JavaScript snippet to execute
250
+ # @param *args Arguments will be available in the given script in the 'arguments' pseudo-array
251
+ #
252
+
253
+ def execute_script(script, *args)
254
+ args.map! { |e| e.kind_of?(Watir::Element) ? e.wd : e }
255
+ returned = @driver.execute_script(script, *args)
256
+
257
+ wrap_elements_in(returned)
258
+ end
259
+
260
+ #
261
+ # Sends sequence of keystrokes to currently active element.
262
+ #
263
+ # @example
264
+ # browser.goto "www.google.com"
265
+ # browser.send_keys "Watir", :return
266
+ #
267
+ # @param [String, Symbol] *args
268
+ #
269
+
270
+ def send_keys(*args)
271
+ @driver.switch_to.active_element.send_keys(*args)
272
+ end
273
+
274
+ #
275
+ # Handles screenshots of current pages.
276
+ #
277
+ # @return [Watir::Screenshot]
278
+ #
279
+
280
+ def screenshot
281
+ Screenshot.new driver
282
+ end
283
+
284
+ #
285
+ # Returns true if browser is not closed and false otherwise.
286
+ #
287
+ # @return [Boolean]
288
+ #
289
+
290
+ def exist?
291
+ assert_exists
292
+ true
293
+ rescue Exception::NoMatchingWindowFoundException, Exception::Error
294
+ false
295
+ end
296
+ alias_method :exists?, :exist?
297
+
298
+ #
299
+ # Protocol shared with Watir::Element
300
+ #
301
+ # @api private
302
+ #
303
+
304
+ def assert_exists
305
+ if @closed
306
+ raise Exception::Error, "browser was closed"
307
+ elsif !window.present?
308
+ raise Exception::NoMatchingWindowFoundException, "browser window was closed"
309
+ else
310
+ driver.switch_to.default_content
311
+ true
312
+ end
313
+ end
314
+ alias_method :ensure_not_stale, :assert_exists
315
+
316
+ def reset!
317
+ # no-op
318
+ end
319
+
320
+ def browser
321
+ self
322
+ end
323
+
324
+ private
325
+
326
+ def wrap_elements_in(obj)
327
+ case obj
328
+ when Selenium::WebDriver::Element
329
+ wrap_element(obj)
330
+ when Array
331
+ obj.map { |e| wrap_elements_in(e) }
332
+ when Hash
333
+ obj.each { |k,v| obj[k] = wrap_elements_in(v) }
334
+
335
+ obj
336
+ else
337
+ obj
338
+ end
339
+ end
340
+
341
+ def wrap_element(element)
342
+ Watir.element_class_for(element.tag_name.downcase).new(self, element: element)
343
+ end
344
+
345
+ end # Browser
346
+ end # Watir
@@ -0,0 +1,25 @@
1
+ module Watir
2
+ module CellContainer
3
+
4
+ #
5
+ # Returns table cell.
6
+ #
7
+ # @return [Cell]
8
+ #
9
+
10
+ def cell(*args)
11
+ Cell.new(self, extract_selector(args).merge(tag_name: /^(th|td)$/))
12
+ end
13
+
14
+ #
15
+ # Returns table cells collection.
16
+ #
17
+ # @return [Cell]
18
+ #
19
+
20
+ def cells(*args)
21
+ CellCollection.new(self, extract_selector(args).merge(tag_name: /^(th|td)$/))
22
+ end
23
+
24
+ end # CellContainer
25
+ end # Watir
@@ -0,0 +1,51 @@
1
+ module Watir
2
+ module Container
3
+ include XpathSupport
4
+ include Atoms
5
+
6
+ #
7
+ # Returns element.
8
+ #
9
+ # @example
10
+ # browser.element(data_bind: 'func')
11
+ #
12
+ # @return [HTMLElement]
13
+ #
14
+
15
+ def element(*args)
16
+ HTMLElement.new(self, extract_selector(args))
17
+ end
18
+
19
+ #
20
+ # Returns element collection.
21
+ #
22
+ # @example
23
+ # browser.elements(data_bind: 'func')
24
+ #
25
+ # @return [HTMLElementCollection]
26
+ #
27
+
28
+ def elements(*args)
29
+ HTMLElementCollection.new(self, extract_selector(args))
30
+ end
31
+
32
+ #
33
+ # @api private
34
+ #
35
+
36
+ def extract_selector(selectors)
37
+ case selectors.size
38
+ when 2
39
+ return { selectors[0] => selectors[1] }
40
+ when 1
41
+ obj = selectors.first
42
+ return obj if obj.kind_of? Hash
43
+ when 0
44
+ return {}
45
+ end
46
+
47
+ raise ArgumentError, "expected Hash or (:how, 'what'), got #{selectors.inspect}"
48
+ end
49
+
50
+ end # Container
51
+ end # Watir
@@ -0,0 +1,132 @@
1
+ require 'yaml'
2
+
3
+ module Watir
4
+ class Cookies
5
+
6
+ def initialize(control)
7
+ @control = control
8
+ end
9
+
10
+ #
11
+ # Returns array of cookies.
12
+ #
13
+ # @example
14
+ # browser.cookies.to_a
15
+ # #=> {:name=>"my_session", :value=>"BAh7B0kiD3Nlc3Npb25faWQGOgZFRkk", :domain=>"mysite.com"}
16
+ #
17
+ # @return [Array<Hash>]
18
+ #
19
+
20
+ def to_a
21
+ @control.all_cookies.map do |e|
22
+ e.merge(expires: e[:expires] ? to_time(e[:expires]) : nil)
23
+ end
24
+ end
25
+
26
+ #
27
+ # Returns a cookie by name.
28
+ #
29
+ # @example
30
+ # browser.cookies[:my_session]
31
+ # #=> {:name=>"my_session", :value=>"BAh7B0kiD3Nlc3Npb25faWQGOgZFRkk", :domain=>"mysite.com"}
32
+ #
33
+ # @param [Symbol] name
34
+ # @return <Hash> or nil if not found
35
+ #
36
+
37
+ def [](name)
38
+ to_a.find { |c| c[:name] == name.to_s }
39
+ end
40
+
41
+ #
42
+ # Adds new cookie.
43
+ #
44
+ # @example
45
+ # browser.cookies.add 'my_session', 'BAh7B0kiD3Nlc3Npb25faWQGOgZFRkk', secure: true
46
+ #
47
+ # @param [String] name
48
+ # @param [String] value
49
+ # @param [Hash] opts
50
+ # @option opts [Boolean] :secure
51
+ # @option opts [String] :path
52
+ # @option opts [Time, DateTime, NilClass] :expires
53
+ # @option opts [String] :domain
54
+ #
55
+
56
+ def add(name, value, opts = {})
57
+ cookie = {
58
+ name: name,
59
+ value: value,
60
+ secure: opts[:secure],
61
+ path: opts[:path],
62
+ expires: opts[:expires],
63
+ domain: opts[:domain]
64
+ }
65
+
66
+ @control.add_cookie cookie
67
+ end
68
+
69
+ #
70
+ # Deletes cookie by given name.
71
+ #
72
+ # @example
73
+ # browser.cookies.delete 'my_session'
74
+ #
75
+ # @param [String] name
76
+ #
77
+
78
+ def delete(name)
79
+ @control.delete_cookie(name)
80
+ end
81
+
82
+ #
83
+ # Deletes all cookies.
84
+ #
85
+ # @example
86
+ # browser.cookies.clear
87
+ #
88
+
89
+ def clear
90
+ @control.delete_all_cookies
91
+ end
92
+
93
+ #
94
+ # Save cookies to file
95
+ #
96
+ # @example
97
+ # browser.cookies.save '.cookies'
98
+ #
99
+ # @param [String] file
100
+ #
101
+
102
+ def save(file = '.cookies')
103
+ IO.write(file, to_a.to_yaml)
104
+ end
105
+
106
+ #
107
+ # Load cookies from file
108
+ #
109
+ # @example
110
+ # browser.cookies.load '.cookies'
111
+ #
112
+ # @param [String] file
113
+ #
114
+
115
+ def load(file = '.cookies')
116
+ YAML.load(IO.read(file)).each do |c|
117
+ add(c.delete(:name), c.delete(:value), c)
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ def to_time(t)
124
+ if t.respond_to?(:to_time)
125
+ t.to_time
126
+ else
127
+ ::Time.local t.year, t.month, t.day, t.hour, t.min, t.sec
128
+ end
129
+ end
130
+
131
+ end # Cookies
132
+ end # Watir