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,46 @@
1
+ require 'websocket'
2
+ require 'pathname'
3
+
4
+ module Selenium
5
+ module WebDriver
6
+ module Safari
7
+
8
+ class << self
9
+ def path=(path)
10
+ Platform.assert_executable(path)
11
+ @path = path
12
+ end
13
+
14
+ def path
15
+ @path ||= (
16
+ path = case Platform.os
17
+ when :windows
18
+ Platform.find_in_program_files("Safari\\Safari.exe")
19
+ when :macosx
20
+ "/Applications/Safari.app/Contents/MacOS/Safari"
21
+ else
22
+ Platform.find_binary("Safari")
23
+ end
24
+
25
+ unless File.file?(path) && File.executable?(path)
26
+ raise Error::WebDriverError, "unable to find the Safari executable, please set Selenium::WebDriver::Safari.path= or add it to your PATH."
27
+ end
28
+
29
+ path
30
+ )
31
+ end
32
+
33
+ def resource_path
34
+ @resource_path ||= Pathname.new(File.expand_path("../safari/resources", __FILE__))
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+
42
+ require 'selenium/webdriver/safari/browser'
43
+ require 'selenium/webdriver/safari/server'
44
+ require 'selenium/webdriver/safari/extension'
45
+ require 'selenium/webdriver/safari/bridge'
46
+
@@ -0,0 +1,110 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Safari
4
+
5
+ class Bridge < Remote::Bridge
6
+ COMMAND_TIMEOUT = 60
7
+
8
+ def initialize(opts = {})
9
+ port = Integer(opts[:port] || PortProber.random)
10
+ timeout = Integer(opts[:timeout] || COMMAND_TIMEOUT)
11
+ custom_data_dir = opts[:custom_data_dir]
12
+ install_extension = opts.fetch(:install_extension) { true }
13
+
14
+ @command_id ||= 0
15
+
16
+ if install_extension
17
+ @extension = Extension.new(:custom_data_dir => custom_data_dir)
18
+ @extension.install
19
+ end
20
+
21
+ @server = Server.new(port, timeout)
22
+ @server.start
23
+
24
+ @safari = Browser.new
25
+ @safari.start(prepare_connect_file)
26
+
27
+ @server.wait_for_connection
28
+
29
+ super(:desired_capabilities => :safari)
30
+ end
31
+
32
+ def quit
33
+ super
34
+
35
+ @server.stop
36
+ @safari.stop
37
+ @extension && @extension.uninstall
38
+ end
39
+
40
+ def driver_extensions
41
+ [
42
+ DriverExtensions::TakesScreenshot,
43
+ DriverExtensions::HasInputDevices
44
+ ]
45
+ end
46
+
47
+ private
48
+
49
+ def create_session(desired_capabilities)
50
+ resp = raw_execute :newSession, {}, :desiredCapabilities => desired_capabilities
51
+ Remote::Capabilities.json_create resp.fetch('value')
52
+ end
53
+
54
+ def raw_execute(command, opts = {}, command_hash = nil)
55
+ @command_id += 1
56
+
57
+ params = {}
58
+ opts.each do |key, value|
59
+ params[camel_case(key.to_s)] = value
60
+ end
61
+
62
+ params.merge!(command_hash) if command_hash
63
+
64
+ @server.send(
65
+ :origin => "webdriver",
66
+ :type => "command",
67
+ :command => { :id => @command_id.to_s, :name => command, :parameters => params}
68
+ )
69
+
70
+ raw = @server.receive
71
+ response = raw.fetch('response')
72
+
73
+ status_code = response['status']
74
+ if status_code != 0
75
+ raise Error.for_code(status_code), response['value']['message']
76
+ end
77
+
78
+ if raw['id'] != @command_id.to_s
79
+ raise Error::WebDriverError, "response id does not match command id"
80
+ end
81
+
82
+ response
83
+ end
84
+
85
+ def camel_case(str)
86
+ parts = str.split('_')
87
+ parts[1..-1].map { |e| e.capitalize! }
88
+
89
+ parts.join
90
+ end
91
+
92
+ def prepare_connect_file
93
+ # TODO: use tempfile?
94
+ path = File.join(Dir.tmpdir, "safaridriver-#{Time.now.to_i}.html")
95
+
96
+ File.open(path, 'w') do |io|
97
+ io << "<!DOCTYPE html><script>window.location = '#{@server.uri}';</script>"
98
+ end
99
+
100
+ FileReaper << path
101
+ path.gsub! "/", "\\" if Platform.windows?
102
+
103
+ path
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,20 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Safari
4
+
5
+ class Browser
6
+ def start(*args)
7
+ @process = ChildProcess.new(Safari.path, *args)
8
+ @process.io.inherit! if $DEBUG
9
+ @process.start
10
+ end
11
+
12
+ def stop
13
+ @process.stop if @process
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,120 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Safari
4
+ class Extension
5
+
6
+ PLIST = <<-XML
7
+ <?xml version="1.0" encoding="UTF-8"?>
8
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
9
+ <plist version="1.0">
10
+ <dict>
11
+ <key>Available Updates</key>
12
+ <dict>
13
+ <key>Last Update Check Time</key>
14
+ <real>370125644.75941497</real>
15
+ <key>Updates List</key>
16
+ <array/>
17
+ </dict>
18
+ <key>Installed Extensions</key>
19
+ <array>
20
+ <dict>
21
+ <key>Added Non-Default Toolbar Items</key>
22
+ <array/>
23
+ <key>Archive File Name</key>
24
+ <string>WebDriver.safariextz</string>
25
+ <key>Bundle Directory Name</key>
26
+ <string>WebDriver.safariextension</string>
27
+ <key>Enabled</key>
28
+ <true/>
29
+ <key>Hidden Bars</key>
30
+ <array/>
31
+ <key>Removed Default Toolbar Items</key>
32
+ <array/>
33
+ </dict>
34
+ </array>
35
+ <key>Version</key>
36
+ <integer>1</integer>
37
+ </dict>
38
+ </plist>
39
+ XML
40
+
41
+ def initialize(opts = {})
42
+ @custom_data_dir = opts[:custom_data_dir]
43
+ @installed = false
44
+ end
45
+
46
+ def install
47
+ return if @installed
48
+
49
+ if install_directory.exist?
50
+ FileUtils.mv install_directory.to_s, backup_directory.to_s
51
+ end
52
+
53
+ install_directory.mkpath
54
+
55
+ extension_destination.rmtree if extension_destination.exist?
56
+ FileUtils.cp extension_source.to_s, extension_destination.to_s
57
+
58
+ plist_destination.open('w') { |io| io << PLIST }
59
+
60
+ at_exit { uninstall }
61
+ @installed = true
62
+ end
63
+
64
+ def uninstall
65
+ return unless @installed
66
+
67
+ install_directory.rmtree if install_directory.exist?
68
+
69
+ if backup_directory.exist?
70
+ FileUtils.mv backup_directory.to_s, install_directory.to_s
71
+ end
72
+ ensure
73
+ @installed = false
74
+ end
75
+
76
+ def extension_source
77
+ Safari.resource_path.join('SafariDriver.safariextz')
78
+ end
79
+
80
+ def extension_destination
81
+ install_directory.join('WebDriver.safariextz')
82
+ end
83
+
84
+ def backup_directory
85
+ Pathname.new("#{install_directory.to_s}.bak")
86
+ end
87
+
88
+ def plist_destination
89
+ install_directory.join('Extensions.plist')
90
+ end
91
+
92
+ def install_directory
93
+ @install_directory ||= (
94
+ data_dir = Pathname.new(@custom_data_dir || safari_data_dir)
95
+
96
+ unless data_dir.exist? && data_dir.directory?
97
+ raise Errno::ENOENT, "Safari data directory not found at #{data_dir.to_s}"
98
+ end
99
+
100
+ data_dir.join('Extensions')
101
+ )
102
+ end
103
+
104
+ def safari_data_dir
105
+ current = Platform.os
106
+
107
+ case current
108
+ when :macosx
109
+ Pathname.new(Platform.home).join('Library/Safari')
110
+ when :windows
111
+ Pathname.new(ENV['APPDATA']).join('Apple Computer/Safari')
112
+ else
113
+ raise Error::WebDriverError, "unsupported platform: #{current}"
114
+ end
115
+ end
116
+
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,145 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Safari
4
+
5
+ class Server
6
+ def initialize(port, command_timeout)
7
+ @port = port
8
+ @command_timeout = command_timeout
9
+ end
10
+
11
+ def start
12
+ @server = TCPServer.new(Platform.localhost, @port)
13
+ end
14
+
15
+ def stop
16
+ @server.close if @server && !@server.closed?
17
+ @ws.close if @ws && !@ws.closed?
18
+ end
19
+
20
+ def send(command)
21
+ json = WebDriver.json_dump(command)
22
+ puts ">>> #{json}" if $DEBUG
23
+
24
+ frame = WebSocket::Frame::Outgoing::Server.new(:version => @version, :data => json, :type => :text)
25
+
26
+ @ws.write frame.to_s
27
+ @ws.flush
28
+ end
29
+
30
+ def receive
31
+ @frame ||= WebSocket::Frame::Incoming::Server.new(:version => @version)
32
+
33
+ until msg = @frame.next
34
+ end_time = Time.now + @command_timeout
35
+
36
+ begin
37
+ data = @ws.read_nonblock(1)
38
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
39
+ now = Time.now
40
+ if now >= end_time
41
+ raise Error::TimeOutError, "timed out waiting for Safari to respond"
42
+ end
43
+
44
+ IO.select([@ws], nil, nil, end_time - now)
45
+ retry
46
+ end
47
+
48
+ @frame << data
49
+ end
50
+
51
+ puts "<<< #{msg}" if $DEBUG
52
+
53
+ WebDriver.json_load msg.to_s
54
+ end
55
+
56
+ def ws_uri
57
+ "ws://#{Platform.localhost}:#{@port}/wd"
58
+ end
59
+
60
+ def uri
61
+ "http://#{Platform.localhost}:#{@port}"
62
+ end
63
+
64
+ def wait_for_connection
65
+ # TODO: timeouts / non-blocking accept
66
+ process_initial_http_request
67
+ process_handshake
68
+ end
69
+
70
+ HEADERS = <<-HEADERS
71
+ HTTP/1.1 %d %s
72
+ Content-Type: text/html; charset=utf-8
73
+ Server: safaridriver-ruby
74
+ HEADERS
75
+
76
+ HEADERS.gsub!("\n", "\r\n")
77
+
78
+ HTML = "<!DOCTYPE html><script>#{Safari.resource_path.join('client.js').read}</script>"
79
+
80
+ def process_initial_http_request
81
+ http = @server.accept
82
+
83
+ req = ''
84
+ until req.include?("\r\n\r\n")
85
+ req << http.read(1)
86
+ end
87
+
88
+ if !req.include?("?url=")
89
+ http << HEADERS % [302, 'Moved Temporarily']
90
+ http << "Location: #{uri}?url=#{encode_form_component ws_uri}\r\n"
91
+ http << "\r\n\r\n"
92
+ http.close
93
+
94
+ process_initial_http_request
95
+ else
96
+ http << HEADERS % [200, 'OK']
97
+ http << "\r\n\r\n"
98
+ http << HTML
99
+ http.close
100
+ end
101
+ end
102
+
103
+ def process_handshake
104
+ @ws = @server.accept
105
+ hs = WebSocket::Handshake::Server.new
106
+
107
+ req = ''
108
+ until hs.finished?
109
+ data = @ws.getc || next
110
+
111
+ req << data.chr
112
+ hs << data
113
+ end
114
+
115
+ unless hs.valid?
116
+ if req.include? "favicon.ico"
117
+ @ws.close
118
+ process_handshake
119
+ return
120
+ else
121
+ raise Error::WebDriverError, "#{hs.error}: #{req}"
122
+ end
123
+ end
124
+
125
+ @ws.write(hs.to_s)
126
+ @ws.flush
127
+
128
+ puts "handshake complete, v#{hs.version}" if $DEBUG
129
+ @server.close
130
+ @version = hs.version
131
+ end
132
+
133
+ def encode_form_component(str)
134
+ if URI.respond_to?(:encode_www_form_component) # >= 1.9
135
+ URI.encode_www_form_component(str)
136
+ else
137
+ # best effort for 1.8
138
+ str.gsub(":", '%3A').gsub('/', '%2F')
139
+ end
140
+ end
141
+ end
142
+
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,5 @@
1
+ require 'selenium/webdriver/support/event_firing_bridge'
2
+ require 'selenium/webdriver/support/abstract_event_listener'
3
+ require 'selenium/webdriver/support/block_event_listener'
4
+ require 'selenium/webdriver/support/select'
5
+ require 'selenium/webdriver/support/color'