browserstack-webdriver 0.0.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 (202) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +791 -0
  3. data/README.md +31 -0
  4. data/build.desc +334 -0
  5. data/lib/selenium-client.rb +2 -0
  6. data/lib/selenium-webdriver.rb +1 -0
  7. data/lib/selenium/client.rb +37 -0
  8. data/lib/selenium/client/base.rb +132 -0
  9. data/lib/selenium/client/driver.rb +10 -0
  10. data/lib/selenium/client/errors.rb +9 -0
  11. data/lib/selenium/client/extensions.rb +118 -0
  12. data/lib/selenium/client/idiomatic.rb +488 -0
  13. data/lib/selenium/client/javascript_expression_builder.rb +116 -0
  14. data/lib/selenium/client/javascript_frameworks/jquery.rb +13 -0
  15. data/lib/selenium/client/javascript_frameworks/prototype.rb +13 -0
  16. data/lib/selenium/client/legacy_driver.rb +1720 -0
  17. data/lib/selenium/client/protocol.rb +104 -0
  18. data/lib/selenium/client/selenium_helper.rb +34 -0
  19. data/lib/selenium/rake/server_task.rb +157 -0
  20. data/lib/selenium/server.rb +248 -0
  21. data/lib/selenium/webdriver.rb +71 -0
  22. data/lib/selenium/webdriver/android.rb +9 -0
  23. data/lib/selenium/webdriver/android/bridge.rb +47 -0
  24. data/lib/selenium/webdriver/chrome.rb +26 -0
  25. data/lib/selenium/webdriver/chrome/bridge.rb +120 -0
  26. data/lib/selenium/webdriver/chrome/profile.rb +90 -0
  27. data/lib/selenium/webdriver/chrome/service.rb +75 -0
  28. data/lib/selenium/webdriver/common.rb +44 -0
  29. data/lib/selenium/webdriver/common/action_builder.rb +352 -0
  30. data/lib/selenium/webdriver/common/alert.rb +30 -0
  31. data/lib/selenium/webdriver/common/bridge_helper.rb +67 -0
  32. data/lib/selenium/webdriver/common/core_ext/base64.rb +9 -0
  33. data/lib/selenium/webdriver/common/core_ext/dir.rb +42 -0
  34. data/lib/selenium/webdriver/common/core_ext/string.rb +5 -0
  35. data/lib/selenium/webdriver/common/driver.rb +301 -0
  36. data/lib/selenium/webdriver/common/driver_extensions/has_browser_connection.rb +17 -0
  37. data/lib/selenium/webdriver/common/driver_extensions/has_input_devices.rb +39 -0
  38. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +25 -0
  39. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +13 -0
  40. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +22 -0
  41. data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +19 -0
  42. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +22 -0
  43. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +45 -0
  44. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +43 -0
  45. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +46 -0
  46. data/lib/selenium/webdriver/common/element.rb +293 -0
  47. data/lib/selenium/webdriver/common/error.rb +207 -0
  48. data/lib/selenium/webdriver/common/file_reaper.rb +47 -0
  49. data/lib/selenium/webdriver/common/html5/local_storage.rb +42 -0
  50. data/lib/selenium/webdriver/common/html5/location.rb +0 -0
  51. data/lib/selenium/webdriver/common/html5/session_storage.rb +44 -0
  52. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +42 -0
  53. data/lib/selenium/webdriver/common/json_helper.rb +34 -0
  54. data/lib/selenium/webdriver/common/keyboard.rb +55 -0
  55. data/lib/selenium/webdriver/common/keys.rb +109 -0
  56. data/lib/selenium/webdriver/common/log_entry.rb +29 -0
  57. data/lib/selenium/webdriver/common/logs.rb +23 -0
  58. data/lib/selenium/webdriver/common/mouse.rb +72 -0
  59. data/lib/selenium/webdriver/common/navigation.rb +43 -0
  60. data/lib/selenium/webdriver/common/options.rb +136 -0
  61. data/lib/selenium/webdriver/common/platform.rb +218 -0
  62. data/lib/selenium/webdriver/common/port_prober.rb +42 -0
  63. data/lib/selenium/webdriver/common/profile_helper.rb +67 -0
  64. data/lib/selenium/webdriver/common/proxy.rb +149 -0
  65. data/lib/selenium/webdriver/common/search_context.rb +92 -0
  66. data/lib/selenium/webdriver/common/socket_poller.rb +105 -0
  67. data/lib/selenium/webdriver/common/target_locator.rb +81 -0
  68. data/lib/selenium/webdriver/common/timeouts.rb +38 -0
  69. data/lib/selenium/webdriver/common/touch_action_builder.rb +64 -0
  70. data/lib/selenium/webdriver/common/touch_screen.rb +105 -0
  71. data/lib/selenium/webdriver/common/wait.rb +63 -0
  72. data/lib/selenium/webdriver/common/window.rb +104 -0
  73. data/lib/selenium/webdriver/common/zipper.rb +82 -0
  74. data/lib/selenium/webdriver/firefox.rb +37 -0
  75. data/lib/selenium/webdriver/firefox/binary.rb +158 -0
  76. data/lib/selenium/webdriver/firefox/bridge.rb +70 -0
  77. data/lib/selenium/webdriver/firefox/extension.rb +52 -0
  78. data/lib/selenium/webdriver/firefox/launcher.rb +106 -0
  79. data/lib/selenium/webdriver/firefox/profile.rb +263 -0
  80. data/lib/selenium/webdriver/firefox/profiles_ini.rb +62 -0
  81. data/lib/selenium/webdriver/firefox/socket_lock.rb +61 -0
  82. data/lib/selenium/webdriver/firefox/util.rb +29 -0
  83. data/lib/selenium/webdriver/ie.rb +19 -0
  84. data/lib/selenium/webdriver/ie/bridge.rb +68 -0
  85. data/lib/selenium/webdriver/ie/server.rb +86 -0
  86. data/lib/selenium/webdriver/iphone.rb +9 -0
  87. data/lib/selenium/webdriver/iphone/bridge.rb +45 -0
  88. data/lib/selenium/webdriver/opera.rb +24 -0
  89. data/lib/selenium/webdriver/opera/bridge.rb +112 -0
  90. data/lib/selenium/webdriver/opera/service.rb +49 -0
  91. data/lib/selenium/webdriver/phantomjs.rb +22 -0
  92. data/lib/selenium/webdriver/phantomjs/bridge.rb +59 -0
  93. data/lib/selenium/webdriver/phantomjs/service.rb +90 -0
  94. data/lib/selenium/webdriver/remote.rb +22 -0
  95. data/lib/selenium/webdriver/remote/bridge.rb +644 -0
  96. data/lib/selenium/webdriver/remote/capabilities.rb +267 -0
  97. data/lib/selenium/webdriver/remote/commands.rb +193 -0
  98. data/lib/selenium/webdriver/remote/http/common.rb +74 -0
  99. data/lib/selenium/webdriver/remote/http/curb.rb +79 -0
  100. data/lib/selenium/webdriver/remote/http/default.rb +139 -0
  101. data/lib/selenium/webdriver/remote/http/persistent.rb +38 -0
  102. data/lib/selenium/webdriver/remote/response.rb +97 -0
  103. data/lib/selenium/webdriver/remote/server_error.rb +17 -0
  104. data/lib/selenium/webdriver/safari.rb +46 -0
  105. data/lib/selenium/webdriver/safari/bridge.rb +110 -0
  106. data/lib/selenium/webdriver/safari/browser.rb +20 -0
  107. data/lib/selenium/webdriver/safari/extension.rb +120 -0
  108. data/lib/selenium/webdriver/safari/server.rb +145 -0
  109. data/lib/selenium/webdriver/support.rb +5 -0
  110. data/lib/selenium/webdriver/support/abstract_event_listener.rb +28 -0
  111. data/lib/selenium/webdriver/support/block_event_listener.rb +17 -0
  112. data/lib/selenium/webdriver/support/color.rb +110 -0
  113. data/lib/selenium/webdriver/support/event_firing_bridge.rb +112 -0
  114. data/lib/selenium/webdriver/support/select.rb +293 -0
  115. data/ruby.iml +13 -0
  116. data/spec/integration/selenium/client/api/backward_compatible_api_spec.rb +22 -0
  117. data/spec/integration/selenium/client/api/browser_xpath_library_spec.rb +17 -0
  118. data/spec/integration/selenium/client/api/click_spec.rb +39 -0
  119. data/spec/integration/selenium/client/api/cookie_spec.rb +39 -0
  120. data/spec/integration/selenium/client/api/element_spec.rb +14 -0
  121. data/spec/integration/selenium/client/api/highlight_located_element_spec.rb +19 -0
  122. data/spec/integration/selenium/client/api/retrieve_last_remote_control_logs_spec.rb +33 -0
  123. data/spec/integration/selenium/client/api/screenshot_spec.rb +31 -0
  124. data/spec/integration/selenium/client/api/select_window_spec.rb +46 -0
  125. data/spec/integration/selenium/client/api/start_stop_spec.rb +9 -0
  126. data/spec/integration/selenium/client/api/wait_for_ajax_spec.rb +27 -0
  127. data/spec/integration/selenium/client/api/wait_for_element_spec.rb +56 -0
  128. data/spec/integration/selenium/client/api/wait_for_field_value_spec.rb +52 -0
  129. data/spec/integration/selenium/client/api/wait_for_text_spec.rb +98 -0
  130. data/spec/integration/selenium/client/api/webdriver_backed_spec.rb +21 -0
  131. data/spec/integration/selenium/client/sample-app/public/jquery-1.3.2.js +4376 -0
  132. data/spec/integration/selenium/client/sample-app/public/jquery.html +55 -0
  133. data/spec/integration/selenium/client/sample-app/public/prototype-1.6.0.3.js +4320 -0
  134. data/spec/integration/selenium/client/sample-app/public/prototype.html +59 -0
  135. data/spec/integration/selenium/client/sample-app/sample_app.rb +32 -0
  136. data/spec/integration/selenium/client/spec_helper.rb +139 -0
  137. data/spec/integration/selenium/webdriver/app_cache_spec.rb +47 -0
  138. data/spec/integration/selenium/webdriver/browser_connection_spec.rb +20 -0
  139. data/spec/integration/selenium/webdriver/chrome/driver_spec.rb +28 -0
  140. data/spec/integration/selenium/webdriver/chrome/profile_spec.rb +63 -0
  141. data/spec/integration/selenium/webdriver/driver_spec.rb +266 -0
  142. data/spec/integration/selenium/webdriver/element_spec.rb +191 -0
  143. data/spec/integration/selenium/webdriver/error_spec.rb +30 -0
  144. data/spec/integration/selenium/webdriver/firefox/driver_spec.rb +21 -0
  145. data/spec/integration/selenium/webdriver/firefox/profile_spec.rb +141 -0
  146. data/spec/integration/selenium/webdriver/keyboard_spec.rb +57 -0
  147. data/spec/integration/selenium/webdriver/location_spec.rb +29 -0
  148. data/spec/integration/selenium/webdriver/mouse_spec.rb +57 -0
  149. data/spec/integration/selenium/webdriver/navigation_spec.rb +46 -0
  150. data/spec/integration/selenium/webdriver/opera/driver_spec.rb +47 -0
  151. data/spec/integration/selenium/webdriver/options_spec.rb +77 -0
  152. data/spec/integration/selenium/webdriver/remote/driver_spec.rb +19 -0
  153. data/spec/integration/selenium/webdriver/remote/element_spec.rb +26 -0
  154. data/spec/integration/selenium/webdriver/spec_helper.rb +36 -0
  155. data/spec/integration/selenium/webdriver/spec_support.rb +12 -0
  156. data/spec/integration/selenium/webdriver/spec_support/guards.rb +110 -0
  157. data/spec/integration/selenium/webdriver/spec_support/helpers.rb +51 -0
  158. data/spec/integration/selenium/webdriver/spec_support/rack_server.rb +123 -0
  159. data/spec/integration/selenium/webdriver/spec_support/test_environment.rb +239 -0
  160. data/spec/integration/selenium/webdriver/sql_database_spec.rb +59 -0
  161. data/spec/integration/selenium/webdriver/storage_spec.rb +96 -0
  162. data/spec/integration/selenium/webdriver/target_locator_spec.rb +186 -0
  163. data/spec/integration/selenium/webdriver/timeout_spec.rb +69 -0
  164. data/spec/integration/selenium/webdriver/touch_spec.rb +176 -0
  165. data/spec/integration/selenium/webdriver/window_spec.rb +70 -0
  166. data/spec/integration/selenium/webdriver/zipper_spec.rb +66 -0
  167. data/spec/unit/selenium/client/base_spec.rb +239 -0
  168. data/spec/unit/selenium/client/extensions_spec.rb +174 -0
  169. data/spec/unit/selenium/client/idiomatic_spec.rb +500 -0
  170. data/spec/unit/selenium/client/javascript_expression_builder_spec.rb +79 -0
  171. data/spec/unit/selenium/client/javascript_frameworks/jquery_spec.rb +10 -0
  172. data/spec/unit/selenium/client/javascript_frameworks/prototype_spec.rb +10 -0
  173. data/spec/unit/selenium/client/protocol_spec.rb +124 -0
  174. data/spec/unit/selenium/client/selenium_helper_spec.rb +56 -0
  175. data/spec/unit/selenium/client/spec_helper.rb +24 -0
  176. data/spec/unit/selenium/rake/task_spec.rb +79 -0
  177. data/spec/unit/selenium/server_spec.rb +150 -0
  178. data/spec/unit/selenium/webdriver/action_builder_spec.rb +97 -0
  179. data/spec/unit/selenium/webdriver/android/bridge_spec.rb +43 -0
  180. data/spec/unit/selenium/webdriver/chrome/bridge_spec.rb +137 -0
  181. data/spec/unit/selenium/webdriver/chrome/profile_spec.rb +57 -0
  182. data/spec/unit/selenium/webdriver/chrome/service_spec.rb +44 -0
  183. data/spec/unit/selenium/webdriver/error_spec.rb +41 -0
  184. data/spec/unit/selenium/webdriver/firefox/bridge_spec.rb +47 -0
  185. data/spec/unit/selenium/webdriver/ie/bridge_spec.rb +91 -0
  186. data/spec/unit/selenium/webdriver/iphone/bridge_spec.rb +42 -0
  187. data/spec/unit/selenium/webdriver/log_entry_spec.rb +11 -0
  188. data/spec/unit/selenium/webdriver/opera/bridge_spec.rb +44 -0
  189. data/spec/unit/selenium/webdriver/phantomjs/bridge_spec.rb +55 -0
  190. data/spec/unit/selenium/webdriver/proxy_spec.rb +106 -0
  191. data/spec/unit/selenium/webdriver/remote/bridge_spec.rb +16 -0
  192. data/spec/unit/selenium/webdriver/remote/capabilities_spec.rb +115 -0
  193. data/spec/unit/selenium/webdriver/remote/http/common_spec.rb +24 -0
  194. data/spec/unit/selenium/webdriver/remote/http/default_spec.rb +124 -0
  195. data/spec/unit/selenium/webdriver/search_context_spec.rb +61 -0
  196. data/spec/unit/selenium/webdriver/socket_poller_spec.rb +68 -0
  197. data/spec/unit/selenium/webdriver/spec_helper.rb +27 -0
  198. data/spec/unit/selenium/webdriver/support/color_spec.rb +119 -0
  199. data/spec/unit/selenium/webdriver/support/event_firing_spec.rb +111 -0
  200. data/spec/unit/selenium/webdriver/support/select_spec.rb +290 -0
  201. data/spec/unit/selenium/webdriver/wait_spec.rb +49 -0
  202. metadata +370 -0
@@ -0,0 +1,28 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Support
4
+
5
+ class AbstractEventListener
6
+ def before_navigate_to(url, driver) end
7
+ def after_navigate_to(url, driver) end
8
+ def before_navigate_back(driver) end
9
+ def after_navigate_back(driver) end
10
+ def before_navigate_forward(driver) end
11
+ def after_navigate_forward(driver) end
12
+ def before_find(by, what, driver) end
13
+ def after_find(by, what, driver) end
14
+ def before_click(element, driver) end
15
+ def after_click(element, driver) end
16
+ def before_change_value_of(element, driver) end
17
+ def after_change_value_of(element, driver) end
18
+ def before_execute_script(script, driver) end
19
+ def after_execute_script(script, driver) end
20
+ def before_quit(driver) end
21
+ def after_quit(driver) end
22
+ def before_close(driver) end
23
+ def after_close(driver) end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Support
4
+
5
+ class BlockEventListener
6
+ def initialize(callback)
7
+ @callback = callback
8
+ end
9
+
10
+ def method_missing(meth, *args, &blk)
11
+ @callback.call meth, *args
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,110 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Support
4
+ class Color
5
+ RGB_PATTERN = /^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$/
6
+ RGB_PCT_PATTERN = /^\s*rgb\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$/
7
+ RGBA_PATTERN = /^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0\.\d+)\s*\)\s*$/
8
+ RGBA_PCT_PATTERN = /^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(0|1|0\.\d+)\s*\)\s*$/
9
+ HEX_PATTERN = /#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})/ # \p{XDigit} or \h only works on Ruby 1.9
10
+ HEX3_PATTERN = /#([A-Fa-f0-9])([A-Fa-f0-9])([A-Fa-f0-9])/ # \p{XDigit} or \h only works on Ruby 1.9
11
+ HSL_PATTERN = /^\s*hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)\s*$/
12
+ HSLA_PATTERN = /^\s*hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,\s*(0|1|0\.\d+)\s*\)\s*$/
13
+
14
+ attr_reader :red, :green, :blue, :alpha
15
+
16
+ def self.from_string(str)
17
+ case str
18
+ when RGB_PATTERN
19
+ new $1, $2, $3
20
+ when RGB_PCT_PATTERN
21
+ new(*[$1, $2, $3].map { |e| Float(e) / 100 * 255 })
22
+ when RGBA_PATTERN
23
+ new $1, $2, $3, $4
24
+ when RGBA_PCT_PATTERN
25
+ new(*[$1, $2, $3].map { |e| Float(e) / 100 * 255 } << $4)
26
+ when HEX_PATTERN
27
+ new(*[$1, $2, $3].map { |e| e.to_i(16) })
28
+ when HEX3_PATTERN
29
+ new(*[$1, $2, $3].map { |e| (e * 2).to_i(16) })
30
+ when HSL_PATTERN, HSLA_PATTERN
31
+ from_hsl($1, $2, $3, $4)
32
+ else
33
+ raise ArgumentError, "could not convert #{str.inspect} into color"
34
+ end
35
+ end
36
+
37
+ def self.from_hsl(h, s, l, a)
38
+ h = Float(h) / 360
39
+ s = Float(s) / 100
40
+ l = Float(l) / 100
41
+ a = Float(a || 1)
42
+
43
+ if s == 0
44
+ r = l
45
+ g = r
46
+ b = r
47
+ else
48
+ luminocity2 = (l < 0.5) ? l * (1 + s) : l + s - l * s
49
+ luminocity1 = 2 * l - luminocity2
50
+
51
+ hue_to_rgb = lambda do |lum1, lum2, hue|
52
+ hue += 1 if hue < 0.0
53
+ hue -= 1 if hue > 1.0
54
+
55
+ if hue < 1.0 / 6.0
56
+ (lum1 + (lum2 - lum1) * 6.0 * hue)
57
+ elsif hue < 1.0 / 2.0
58
+ lum2
59
+ elsif hue < 2.0 / 3.0
60
+ lum1 + (lum2 - lum1) * ((2.0 / 3.0) - hue) * 6.0
61
+ else
62
+ lum1
63
+ end
64
+ end
65
+
66
+ r = hue_to_rgb.call(luminocity1, luminocity2, h + 1.0 / 3.0)
67
+ g = hue_to_rgb.call(luminocity1, luminocity2, h)
68
+ b = hue_to_rgb.call(luminocity1, luminocity2, h - 1.0 / 3.0)
69
+ end
70
+
71
+ new r * 256, g * 256, b * 256, a
72
+ end
73
+
74
+
75
+ def initialize(red, green, blue, alpha = 1)
76
+ @red = Integer(red)
77
+ @green = Integer(green)
78
+ @blue = Integer(blue)
79
+ @alpha = Float(alpha)
80
+ end
81
+
82
+ def ==(other)
83
+ return true if equal?(other)
84
+ return false unless other.kind_of?(self.class)
85
+
86
+ [red, green, blue, alpha] == [other.red, other.green, other.blue, other.alpha]
87
+ end
88
+ alias_method :eql?, :==
89
+
90
+ def hash
91
+ [red, green, blue, alpha].hash ^ self.class.hash
92
+ end
93
+
94
+ def rgb
95
+ "rgb(#{red}, #{green}, #{blue})"
96
+ end
97
+
98
+ def rgba
99
+ a = alpha == 1 ? '1' : alpha
100
+ "rgba(#{red}, #{green}, #{blue}, #{a})"
101
+ end
102
+
103
+ def hex
104
+ "#%02x%02x%02x" % [red, green, blue]
105
+ end
106
+
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,112 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Support
4
+
5
+ #
6
+ # @api private
7
+ #
8
+
9
+ class EventFiringBridge
10
+ def initialize(delegate, listener)
11
+ @delegate = delegate
12
+
13
+ if listener.respond_to? :call
14
+ @listener = BlockEventListener.new(listener)
15
+ else
16
+ @listener = listener
17
+ end
18
+ end
19
+
20
+ def get(url)
21
+ dispatch(:navigate_to, url, driver) {
22
+ @delegate.get(url)
23
+ }
24
+ end
25
+
26
+ def goForward
27
+ dispatch(:navigate_forward, driver) {
28
+ @delegate.goForward
29
+ }
30
+ end
31
+
32
+ def goBack
33
+ dispatch(:navigate_back, driver) {
34
+ @delegate.goBack
35
+ }
36
+ end
37
+
38
+ def clickElement(ref)
39
+ dispatch(:click, create_element(ref), driver) {
40
+ @delegate.clickElement(ref)
41
+ }
42
+ end
43
+
44
+ def clearElement(ref)
45
+ dispatch(:change_value_of, create_element(ref), driver) {
46
+ @delegate.clearElement(ref)
47
+ }
48
+ end
49
+
50
+ def sendKeysToElement(ref, keys)
51
+ dispatch(:change_value_of, create_element(ref), driver) {
52
+ @delegate.sendKeysToElement(ref, keys)
53
+ }
54
+ end
55
+
56
+ def find_element_by(how, what, parent = nil)
57
+ e = dispatch(:find, how, what, driver) {
58
+ @delegate.find_element_by how, what, parent
59
+ }
60
+
61
+ Element.new self, e.ref
62
+ end
63
+
64
+ def find_elements_by(how, what, parent = nil)
65
+ es = dispatch(:find, how, what, driver) {
66
+ @delegate.find_elements_by(how, what, parent)
67
+ }
68
+
69
+ es.map { |e| Element.new self, e.ref }
70
+ end
71
+
72
+ def executeScript(script, *args)
73
+ dispatch(:execute_script, script, driver) {
74
+ @delegate.executeScript(script, *args)
75
+ }
76
+ end
77
+
78
+ def quit
79
+ dispatch(:quit, driver) { @delegate.quit }
80
+ end
81
+
82
+ def close
83
+ dispatch(:close, driver) { @delegate.close }
84
+ end
85
+
86
+ private
87
+
88
+ def create_element(ref)
89
+ # hmm. we're not passing self here to not fire events for potential calls made by the listener
90
+ Element.new @delegate, ref
91
+ end
92
+
93
+ def driver
94
+ @driver ||= Driver.new(self)
95
+ end
96
+
97
+ def dispatch(name, *args, &blk)
98
+ @listener.__send__("before_#{name}", *args)
99
+ returned = yield
100
+ @listener.__send__("after_#{name}", *args)
101
+
102
+ returned
103
+ end
104
+
105
+ def method_missing(meth, *args, &blk)
106
+ @delegate.__send__(meth, *args, &blk)
107
+ end
108
+ end # EventFiringBridge
109
+
110
+ end # Support
111
+ end # WebDriver
112
+ end # Selenium
@@ -0,0 +1,293 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Support
4
+ class Select
5
+
6
+ #
7
+ # @param [Element] element The select element to use
8
+ #
9
+
10
+ def initialize(element)
11
+ tag_name = element.tag_name
12
+
13
+ unless tag_name.downcase == "select"
14
+ raise ArgumentError, "unexpected tag name #{tag_name.inspect}"
15
+ end
16
+
17
+ @element = element
18
+ @multi = ![nil, "false"].include?(element.attribute(:multiple))
19
+ end
20
+
21
+ #
22
+ # Does this select element support selecting multiple options?
23
+ #
24
+ # @return [Boolean]
25
+ #
26
+
27
+ def multiple?
28
+ @multi
29
+ end
30
+
31
+ #
32
+ # Get all options for this select element
33
+ #
34
+ # @return [Array<Element>]
35
+ #
36
+
37
+ def options
38
+ @element.find_elements :tag_name, 'option'
39
+ end
40
+
41
+ #
42
+ # Get all selected options for this select element
43
+ #
44
+ # @return [Array<Element>]
45
+ #
46
+
47
+ def selected_options
48
+ options.select { |e| e.selected? }
49
+ end
50
+
51
+ #
52
+ # Get the first selected option in this select element
53
+ #
54
+ # @raise [Error::NoSuchElementError] if no options are selected
55
+ # @return [Element]
56
+ #
57
+
58
+ def first_selected_option
59
+ option = options.find { |e| e.selected? }
60
+ option or raise Error::NoSuchElementError, 'no options are selected'
61
+ end
62
+
63
+ #
64
+ # Select options by visible text, index or value.
65
+ #
66
+ # When selecting by :text, selects options that display text matching the argument. That is, when given "Bar" this
67
+ # would select an option like:
68
+ #
69
+ # <option value="foo">Bar</option>
70
+ #
71
+ # When slecting by :value, selects all options that have a value matching the argument. That is, when given "foo" this
72
+ # would select an option like:
73
+ #
74
+ # <option value="foo">Bar</option>
75
+ #
76
+ # When selecting by :index, selects the option at the given index. This is done by examining the "index" attribute of an
77
+ # element, and not merely by counting.
78
+ #
79
+ # @param [:text, :index, :value] how How to find the option
80
+ # @param [String] what What value to find the option by.
81
+ #
82
+
83
+ def select_by(how, what)
84
+ case how
85
+ when :text
86
+ select_by_text what
87
+ when :index
88
+ select_by_index what
89
+ when :value
90
+ select_by_value what
91
+ else
92
+ raise ArgumentError, "can't select options by #{how.inspect}"
93
+ end
94
+ end
95
+
96
+ #
97
+ # Deselect options by visible text, index or value.
98
+ #
99
+ # @param [:text, :index, :value] how How to find the option
100
+ # @param [String] what What value to find the option by.
101
+ #
102
+ # @see Select#select_by
103
+ #
104
+
105
+ def deselect_by(how, what)
106
+ case how
107
+ when :text
108
+ deselect_by_text what
109
+ when :value
110
+ deselect_by_value what
111
+ when :index
112
+ deselect_by_index what
113
+ else
114
+ raise ArgumentError, "can't deselect options by #{how.inspect}"
115
+ end
116
+ end
117
+
118
+ #
119
+ # Select all unselected options. Only valid if the element supports multiple selections.
120
+ #
121
+ # @raise [Error::UnsupportedOperationError] if the element does not support multiple selections.
122
+ #
123
+
124
+ def select_all
125
+ unless multiple?
126
+ raise Error::UnsupportedOperationError, 'you may only select all options of a multi-select'
127
+ end
128
+
129
+ options.each { |e| select_option e }
130
+ end
131
+
132
+ #
133
+ # Deselect all selected options. Only valid if the element supports multiple selections.
134
+ #
135
+ # @raise [Error::UnsupportedOperationError] if the element does not support multiple selections.
136
+ #
137
+
138
+ def deselect_all
139
+ unless multiple?
140
+ raise Error::UnsupportedOperationError, 'you may only deselect all options of a multi-select'
141
+ end
142
+
143
+ options.each { |e| deselect_option e }
144
+ end
145
+
146
+ private
147
+
148
+ def select_by_text(text)
149
+ opts = find_by_text text
150
+
151
+ if opts.empty?
152
+ raise Error::NoSuchElementError, "cannot locate element with text: #{text.inspect}"
153
+ end
154
+
155
+ select_options opts
156
+ end
157
+
158
+ def select_by_index(index)
159
+ opts = find_by_index index
160
+
161
+ if opts.empty?
162
+ raise Error::NoSuchElementError, "cannot locate element with index: #{index.inspect}"
163
+ end
164
+
165
+ select_options opts
166
+ end
167
+
168
+ def select_by_value(value)
169
+ opts = find_by_value value
170
+
171
+ if opts.empty?
172
+ raise Error::NoSuchElementError, "cannot locate option with value: #{value.inspect}"
173
+ end
174
+
175
+ select_options opts
176
+ end
177
+
178
+ def deselect_by_text(text)
179
+ opts = find_by_text text
180
+
181
+ if opts.empty?
182
+ raise Error::NoSuchElementError, "cannot locate element with text: #{text.inspect}"
183
+ end
184
+
185
+ deselect_options opts
186
+ end
187
+
188
+ def deselect_by_value(value)
189
+ opts = find_by_value value
190
+
191
+ if opts.empty?
192
+ raise Error::NoSuchElementError, "cannot locate option with value: #{value.inspect}"
193
+ end
194
+
195
+ deselect_options opts
196
+ end
197
+
198
+ def deselect_by_index(index)
199
+ opts = find_by_index index
200
+
201
+ if opts.empty?
202
+ raise Error::NoSuchElementError, "cannot locate option with index: #{index}"
203
+ end
204
+
205
+ deselect_options opts
206
+ end
207
+
208
+ private
209
+
210
+ def select_option(option)
211
+ option.click unless option.selected?
212
+ end
213
+
214
+ def deselect_option(option)
215
+ option.click if option.selected?
216
+ end
217
+
218
+ def select_options(opts)
219
+ if multiple?
220
+ opts.each { |o| select_option o }
221
+ else
222
+ select_option opts.first
223
+ end
224
+ end
225
+
226
+ def deselect_options(opts)
227
+ if multiple?
228
+ opts.each { |o| deselect_option o }
229
+ else
230
+ deselect_option opts.first
231
+ end
232
+ end
233
+
234
+ def find_by_text(text)
235
+ xpath = ".//option[normalize-space(.) = #{Escaper.escape text}]"
236
+ opts = @element.find_elements(:xpath, xpath)
237
+
238
+ if opts.empty? && text =~ /\s+/
239
+ longest_word = text.split(/\s+/).max_by { |item| item.length }
240
+
241
+ if longest_word.empty?
242
+ candidates = options
243
+ else
244
+ xpath = ".//option[contains(., #{Escaper.escape longest_word})]"
245
+ candidates = @element.find_elements(:xpath, xpath)
246
+ end
247
+
248
+ if multiple?
249
+ candidates.select { |option| text == option.text }
250
+ else
251
+ Array(candidates.find { |option| text == option.text })
252
+ end
253
+ else
254
+ opts
255
+ end
256
+ end
257
+
258
+ def find_by_index(index)
259
+ index = index.to_s
260
+ options.select { |option| option.attribute(:index) == index }
261
+ end
262
+
263
+ def find_by_value(value)
264
+ @element.find_elements(:xpath, ".//option[@value = #{Escaper.escape value}]")
265
+ end
266
+
267
+ #
268
+ # @api private
269
+ #
270
+
271
+ module Escaper
272
+ def self.escape(str)
273
+ if str.include?('"') && str.include?("'")
274
+ parts = str.split('"', -1).map { |part| %{"#{part}"} }
275
+
276
+ quoted = parts.join(%{, '"', }).
277
+ gsub(/^"", |, ""$/, '')
278
+
279
+ "concat(#{quoted})"
280
+ elsif str.include?('"')
281
+ # escape string with just a quote into being single quoted: f"oo -> 'f"oo'
282
+ "'#{str}'"
283
+ else
284
+ # otherwise return the quoted string
285
+ %{"#{str}"}
286
+ end
287
+ end
288
+ end # Escaper
289
+
290
+ end # Select
291
+ end
292
+ end
293
+ end