selenium-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 (86) hide show
  1. data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
  2. data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
  3. data/chrome/src/extension/background.html +9 -0
  4. data/chrome/src/extension/background.js +933 -0
  5. data/chrome/src/extension/content_script.js +1286 -0
  6. data/chrome/src/extension/manifest-nonwin.json +15 -0
  7. data/chrome/src/extension/manifest-win.json +16 -0
  8. data/chrome/src/extension/toolstrip.html +28 -0
  9. data/chrome/src/extension/utils.js +196 -0
  10. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +8 -0
  11. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +324 -0
  12. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +70 -0
  13. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +119 -0
  14. data/common/src/js/abstractcommandprocessor.js +161 -0
  15. data/common/src/js/asserts.js +296 -0
  16. data/common/src/js/by.js +147 -0
  17. data/common/src/js/command.js +274 -0
  18. data/common/src/js/context.js +58 -0
  19. data/common/src/js/extension/README +2 -0
  20. data/common/src/js/extension/dommessenger.js +152 -0
  21. data/common/src/js/factory.js +55 -0
  22. data/common/src/js/future.js +118 -0
  23. data/common/src/js/key.js +117 -0
  24. data/common/src/js/localcommandprocessor.js +181 -0
  25. data/common/src/js/logging.js +249 -0
  26. data/common/src/js/testrunner.js +605 -0
  27. data/common/src/js/timing.js +89 -0
  28. data/common/src/js/wait.js +199 -0
  29. data/common/src/js/webdriver.js +853 -0
  30. data/common/src/js/webelement.js +683 -0
  31. data/common/src/rb/lib/selenium-webdriver.rb +1 -0
  32. data/common/src/rb/lib/selenium/webdriver.rb +52 -0
  33. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +88 -0
  34. data/common/src/rb/lib/selenium/webdriver/child_process.rb +85 -0
  35. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +41 -0
  36. data/common/src/rb/lib/selenium/webdriver/driver.rb +128 -0
  37. data/common/src/rb/lib/selenium/webdriver/element.rb +126 -0
  38. data/common/src/rb/lib/selenium/webdriver/error.rb +68 -0
  39. data/common/src/rb/lib/selenium/webdriver/find.rb +69 -0
  40. data/common/src/rb/lib/selenium/webdriver/navigation.rb +23 -0
  41. data/common/src/rb/lib/selenium/webdriver/options.rb +50 -0
  42. data/common/src/rb/lib/selenium/webdriver/platform.rb +82 -0
  43. data/common/src/rb/lib/selenium/webdriver/target_locator.rb +23 -0
  44. data/firefox/prebuilt/nsICommandProcessor.xpt +0 -0
  45. data/firefox/prebuilt/nsINativeEvents.xpt +0 -0
  46. data/firefox/prebuilt/nsIResponseHandler.xpt +0 -0
  47. data/firefox/src/extension/chrome.manifest +3 -0
  48. data/firefox/src/extension/components/context.js +37 -0
  49. data/firefox/src/extension/components/driver-component.js +127 -0
  50. data/firefox/src/extension/components/firefoxDriver.js +706 -0
  51. data/firefox/src/extension/components/json2.js +273 -0
  52. data/firefox/src/extension/components/keytest.html +554 -0
  53. data/firefox/src/extension/components/nsCommandProcessor.js +586 -0
  54. data/firefox/src/extension/components/screenshooter.js +70 -0
  55. data/firefox/src/extension/components/socketListener.js +185 -0
  56. data/firefox/src/extension/components/utils.js +1200 -0
  57. data/firefox/src/extension/components/webLoadingListener.js +57 -0
  58. data/firefox/src/extension/components/webdriverserver.js +101 -0
  59. data/firefox/src/extension/components/wrappedElement.js +609 -0
  60. data/firefox/src/extension/content/fxdriver.xul +30 -0
  61. data/firefox/src/extension/content/server.js +95 -0
  62. data/firefox/src/extension/idl/nsICommandProcessor.idl +38 -0
  63. data/firefox/src/extension/idl/nsIResponseHandler.idl +34 -0
  64. data/firefox/src/extension/install.rdf +29 -0
  65. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +21 -0
  66. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +86 -0
  67. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +426 -0
  68. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +82 -0
  69. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +132 -0
  70. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +174 -0
  71. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +60 -0
  72. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +23 -0
  73. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  74. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  75. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +14 -0
  76. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +552 -0
  77. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +94 -0
  78. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +147 -0
  79. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +16 -0
  80. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +374 -0
  81. data/remote/client/src/rb/lib/selenium/webdriver/remote/capabilities.rb +105 -0
  82. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +53 -0
  83. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +71 -0
  84. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +43 -0
  85. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +32 -0
  86. metadata +182 -0
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0"?>
2
+
3
+ <!--
4
+ Copyright 2007-2009 WebDriver committers
5
+ Copyright 2007-2009 Google Inc.
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
18
+ -->
19
+
20
+ <overlay id="fxdriver-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
21
+ <script src="dommessenger.js" />
22
+ <script src="server.js" />
23
+ <statusbar id="status-bar">
24
+ <statusbarpanel>
25
+ <hbox>
26
+ <label id="fxdriver-label" value="WebDriver" tooltiptext="This Firefox can be remote controlled with WebDriver." />
27
+ </hbox>
28
+ </statusbarpanel>
29
+ </statusbar>
30
+ </overlay>
@@ -0,0 +1,95 @@
1
+ /*
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+ Portions copyright 2007 ThoughtWorks, Inc
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ var driver = false;
20
+ var domMessenger = null;
21
+
22
+ // This will configure a FirefoxDriver and DomMessenger for each
23
+ // _browser window_ (not chrome window). Multiple tabs in the same window will
24
+ // share a FirefoxDriver and DomMessenger instance.
25
+ window.addEventListener("load", function(e) {
26
+ handle = Components.classes["@googlecode.com/webdriver/fxdriver;1"].createInstance(Components.interfaces.nsISupports);
27
+ var server = handle.wrappedJSObject;
28
+
29
+ if (!domMessenger) {
30
+ var appcontent = document.getElementById('appcontent');
31
+ if (appcontent) {
32
+ try {
33
+ var commandProcessor = Components.
34
+ classes['@googlecode.com/webdriver/command-processor;1'].
35
+ getService(Components.interfaces.nsICommandProcessor);
36
+ domMessenger = new DomMessenger(commandProcessor);
37
+ appcontent.addEventListener('DOMContentLoaded',
38
+ function(e) {
39
+ domMessenger.onPageLoad(e);
40
+ }, true);
41
+ appcontent.addEventListener('pagehide',
42
+ function(e) {
43
+ domMessenger.onPageUnload(e);
44
+ }, true);
45
+ } catch (ex) {
46
+ // Not catching this can really mess things up and lead to inexplicable
47
+ // and hard to debug behavior.
48
+ Components.utils.reportError(ex);
49
+ }
50
+ }
51
+ }
52
+
53
+ if (!driver) {
54
+ driver = server.newDriver(window);
55
+ } else {
56
+ if (window.content)
57
+ var frames = window.content.frames;
58
+
59
+ // If we are already focused on a frame, try and stay focused
60
+ if (driver.context.frameId !== undefined && frames) {
61
+ if (frames && frames.length > driver.context.frameId) {
62
+ // do nothing
63
+ } else {
64
+ if (frames && frames.length && "FRAME" == frames[0].frameElement.tagName) {
65
+ if (!frames[driver.context.frameId]) {
66
+ driver.context.frameId = 0;
67
+ }
68
+ } else {
69
+ driver.context.frameId = undefined;
70
+ }
71
+
72
+ }
73
+ } else {
74
+ // Other use a sensible default
75
+ if (frames && frames.length && "FRAME" == frames[0].frameElement.tagName) {
76
+ if (!frames[driver.context.frameId]) {
77
+ driver.context.frameId = 0;
78
+ }
79
+ } else {
80
+ driver.context.frameId = undefined;
81
+ }
82
+ }
83
+ }
84
+
85
+ server.startListening();
86
+
87
+ }, true);
88
+
89
+ //window.addEventListener("focus", function(e) {
90
+ // var active = e.originalTarget;
91
+ // var doc = gBrowser.selectedBrowser.contentDocument;
92
+ // if (active.ownerDocument == doc) {
93
+ // driver.activeElement = active;
94
+ // }
95
+ //}, true);
@@ -0,0 +1,38 @@
1
+ /*
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+ Portions copyright 2007 ThoughtWorks, Inc
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ #include "nsISupports.idl"
20
+ #include "nsIResponseHandler.idl"
21
+
22
+ /**
23
+ * Defines a single method for executing commands specified as a JSON string.
24
+ */
25
+ [scriptable, uuid(4427729b-441e-47c3-8380-df0350cac636)]
26
+ interface nsICommandProcessor : nsISupports {
27
+
28
+ /**
29
+ * Executes the given command specified in a JSON string. When the command
30
+ * is fully processed, the response will be sent to the given
31
+ * {@code nsIResponseHandler} callback as a JSON string.
32
+ *
33
+ * @param jsonCommandString The command to execute, specified in JSON format.
34
+ * @param responseHandler The callback to send the command response to.
35
+ */
36
+ void execute(in AUTF8String jsonCommandString,
37
+ in nsIResponseHandler responseHandler);
38
+ };
@@ -0,0 +1,34 @@
1
+ /*
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+ Portions copyright 2007 ThoughtWorks, Inc
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ #include "nsISupports.idl"
20
+
21
+ /**
22
+ * Defines a callback used to process the response to a command sent to the
23
+ * {@code nsICommandProcessor}.
24
+ */
25
+ [scriptable, function, uuid(0539a68f-b4a8-4543-bf2a-031cef89aff1)]
26
+ interface nsIResponseHandler : nsISupports {
27
+
28
+ /**
29
+ * Handle a response from the {@code nsICommandProcessor}.
30
+ *
31
+ * @param jsonResponseString The command response as a string.
32
+ */
33
+ void handleResponse(in AUTF8String jsonResponseString);
34
+ };
@@ -0,0 +1,29 @@
1
+ <?xml version="1.0"?>
2
+ <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
3
+
4
+ <Description about="urn:mozilla:install-manifest">
5
+ <em:id>fxdriver@googlecode.com</em:id>
6
+ <em:name>Firefox WebDriver</em:name>
7
+ <em:version>0.6.680</em:version>
8
+ <em:description>WebDriver implementation for Firefox</em:description>
9
+ <em:creator>Simon Stewart</em:creator>
10
+
11
+ <!-- Firefox -->
12
+ <em:targetApplication>
13
+ <Description>
14
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
15
+ <em:minVersion>2.0</em:minVersion>
16
+ <em:maxVersion>3.*</em:maxVersion>
17
+ </Description>
18
+ </em:targetApplication>
19
+
20
+ <!-- Platforms where we're not compiling the native events -->
21
+ <em:targetPlatform>Darwin</em:targetPlatform>
22
+ <em:targetPlatform>Linux</em:targetPlatform>
23
+ <!-- Platforms where we are -->
24
+ <em:targetPlatform>WINNT_x86-msvc</em:targetPlatform>
25
+
26
+ <!-- We're probably missing lots of platforms here -->
27
+ </Description>
28
+
29
+ </RDF>
@@ -0,0 +1,21 @@
1
+ require "timeout"
2
+ require "socket"
3
+
4
+ require "selenium/webdriver/firefox/util"
5
+ require "selenium/webdriver/firefox/binary"
6
+ require "selenium/webdriver/firefox/profiles_ini"
7
+ require "selenium/webdriver/firefox/profile"
8
+ require "selenium/webdriver/firefox/extension_connection"
9
+ require "selenium/webdriver/firefox/launcher"
10
+ require "selenium/webdriver/firefox/bridge"
11
+
12
+ module Selenium
13
+ module WebDriver
14
+ module Firefox
15
+
16
+ DEFAULT_PROFILE_NAME = "WebDriver".freeze
17
+ DEFAULT_PORT = 7055
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,86 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Firefox
4
+ class Binary
5
+ def initialize
6
+ ENV['MOZ_NO_REMOTE'] = '1' # able to launch multiple instances
7
+ check_binary_exists
8
+ end
9
+
10
+ def create_base_profile(name)
11
+ execute("-CreateProfile", name)
12
+ Timeout.timeout(15, Error::TimeOutError) { wait }
13
+
14
+ unless $?.success?
15
+ raise Error::WebDriverError, "could not create base profile: (#{$?.exitstatus})"
16
+ end
17
+ end
18
+
19
+ def start_with(profile, *args)
20
+ ENV['XRE_PROFILE_PATH'] = profile.absolute_path
21
+
22
+ # TODO: native lib loading
23
+ # if Platform.os == :unix && (profile.enable_native_events || profile.always_load_no_focus_lib)
24
+ # modify_link_library_path profile
25
+ # end
26
+
27
+ execute(*args)
28
+ end
29
+
30
+ def execute(*extra_args)
31
+ args = [path, "-no-remote", "--verbose"] + extra_args
32
+ @process = ChildProcess.new(*args).start
33
+ end
34
+
35
+ def kill
36
+ @process.kill if @process
37
+ end
38
+
39
+ def wait
40
+ @process.wait if @process
41
+ end
42
+
43
+ private
44
+
45
+ def path
46
+ @path ||= case Platform.os
47
+ when :macosx
48
+ "/Applications/Firefox.app/Contents/MacOS/firefox-bin"
49
+ when :windows
50
+ windows_path
51
+ when :unix
52
+ "/usr/bin/firefox"
53
+ else
54
+ raise "Unknown platform: #{Platform.os}"
55
+ end
56
+ end
57
+
58
+ def check_binary_exists
59
+ unless File.file?(path)
60
+ raise Error::WebDriverError, "Could not find Firefox binary. Make sure Firefox is installed (OS: #{Platform.os})"
61
+ end
62
+ end
63
+
64
+ def windows_path
65
+ windows_registry_path || (ENV['PROGRAMFILES'] || "\\Program Files") + "\\Mozilla Firefox\\firefox.exe"
66
+ end
67
+
68
+ def windows_registry_path
69
+ return if Platform.jruby?
70
+ require "win32/registry"
71
+
72
+ lm = Win32::Registry::HKEY_LOCAL_MACHINE
73
+ lm.open("SOFTWARE\\Mozilla\\Mozilla Firefox") do |reg|
74
+ main = lm.open("SOFTWARE\\Mozilla\\Mozilla Firefox\\#{reg.keys[0]}\\Main")
75
+ if entry = main.find {|key, type, data| key =~ /pathtoexe/i}
76
+ return entry.last
77
+ end
78
+ end
79
+ rescue Win32::Registry::Error
80
+ raise Error::WebDriverError, "Firefox not found in Windows registry, please make sure you have it installed."
81
+ end
82
+
83
+ end # Binary
84
+ end # Firefox
85
+ end # WebDriver
86
+ end # Selenium
@@ -0,0 +1,426 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Firefox
4
+ class Bridge
5
+ include BridgeHelper
6
+
7
+ def initialize
8
+ @binary = Binary.new
9
+ @launcher = Launcher.new(@binary).launch
10
+ @connection = @launcher.connection
11
+ @context = newSession
12
+ end
13
+
14
+ def browser
15
+ :firefox
16
+ end
17
+
18
+ def quit
19
+ @connection.quit
20
+ @binary.wait
21
+ nil
22
+ end
23
+
24
+ def getPageSource
25
+ execute :getPageSource
26
+ end
27
+
28
+ def getWindowHandles
29
+ execute(:getWindowHandles).to_s.split(", ")
30
+ end
31
+
32
+ def getCurrentWindowHandle
33
+ execute :getCurrentWindowHandle
34
+ end
35
+
36
+
37
+ def get(url)
38
+ execute :get,
39
+ :parameters => [url]
40
+ end
41
+
42
+ def close
43
+ execute :close
44
+ # TODO: rescue ?
45
+ end
46
+
47
+ def goBack
48
+ execute :goBack
49
+ end
50
+
51
+ def goForward
52
+ execute :goForward
53
+ end
54
+
55
+ def getCurrentUrl
56
+ execute :getCurrentUrl
57
+ end
58
+
59
+ def getTitle
60
+ execute :title
61
+ end
62
+
63
+ def executeScript(string, *args)
64
+ typed_args = args.map { |e| wrap_script_argument(e) }
65
+
66
+ resp = raw_execute :executeScript, :parameters => [string, typed_args]
67
+
68
+ unwrap_script_argument resp
69
+ end
70
+
71
+ #
72
+ # Finders - TODO: should be shared with Chrome::Bridge
73
+ #
74
+
75
+ def findElementByClassName(parent, class_name)
76
+ find_element_by 'class name', class_name, parent
77
+ end
78
+
79
+ def findElementsByClassName(parent, class_name)
80
+ find_elements_by 'class name', class_name, parent
81
+ end
82
+
83
+ def findElementById(parent, id)
84
+ find_element_by 'id', id, parent
85
+ end
86
+
87
+ def findElementsById(parent, id)
88
+ find_elements_by 'id', id, parent
89
+ end
90
+
91
+ def findElementByLinkText(parent, link_text)
92
+ find_element_by 'link text', link_text, parent
93
+ end
94
+
95
+ def findElementsByLinkText(parent, link_text)
96
+ find_elements_by 'link text', link_text, parent
97
+ end
98
+
99
+ def findElementByPartialLinkText(parent, link_text)
100
+ find_element_by 'partial link text', link_text, parent
101
+ end
102
+
103
+ def findElementsByPartialLinkText(parent, link_text)
104
+ find_elements_by 'partial link text', link_text, parent
105
+ end
106
+
107
+ def findElementByName(parent, name)
108
+ find_element_by 'name', name, parent
109
+ end
110
+
111
+ def findElementsByName(parent, name)
112
+ find_elements_by 'name', name, parent
113
+ end
114
+
115
+ def findElementByTagName(parent, tag_name)
116
+ find_element_by 'tag name', tag_name, parent
117
+ end
118
+
119
+ def findElementsByTagName(parent, tag_name)
120
+ find_elements_by 'tag name', tag_name, parent
121
+ end
122
+
123
+ def findElementByXpath(parent, xpath)
124
+ find_element_by 'xpath', xpath, parent
125
+ end
126
+
127
+ def findElementsByXpath(parent, xpath)
128
+ find_elements_by 'xpath', xpath, parent
129
+ end
130
+
131
+ #
132
+ # Element functions
133
+ #
134
+
135
+ def clickElement(element)
136
+ # execute :clickElement, :element_id => element
137
+ execute :click,
138
+ :element_id => element
139
+ end
140
+
141
+ def getElementTagName(element)
142
+ # execute :getElementTagName, :element_id => element
143
+ execute :getTagName,
144
+ :element_id => element
145
+ end
146
+
147
+ def getElementAttribute(element, name)
148
+ # execute :getElementAttribute, :element_id => element, :parameters => [name]
149
+ execute :getAttribute,
150
+ :element_id => element,
151
+ :parameters => [name]
152
+ end
153
+
154
+ def getElementValue(element)
155
+ # execute :getElementValue, :element_id => element
156
+ execute :getValue,
157
+ :element_id => element
158
+ end
159
+
160
+ def getElementText(element)
161
+ # execute :getElementText, :element_id => element
162
+ execute :getText,
163
+ :element_id => element
164
+ end
165
+
166
+ def getElementLocation(element)
167
+ # data = execute :getElementLocation, :element_id => element
168
+ data = execute :getLocation,
169
+ :element_id => element
170
+
171
+ Point.new(*data.split(",").map { |e| Integer(e.strip) })
172
+ end
173
+
174
+ def getElementSize(element)
175
+ # execute :getElementSize, :element_id => element
176
+ execute :getSize,
177
+ :element_id => element
178
+ end
179
+
180
+ def sendKeysToElement(element, string)
181
+ # execute :sendKeysToElement, :element_id => element, :parameters => [string.split(//u)]
182
+ execute :sendKeys,
183
+ :element_id => element,
184
+ :parameters => [string.to_s]
185
+ end
186
+
187
+ def clearElement(element)
188
+ # execute :clearElement, :element_id => element
189
+ execute :clear,
190
+ :element_id => element
191
+ end
192
+
193
+ def isElementEnabled(element)
194
+ # execute :isElementEnabled, :element_id => element
195
+ !getElementAttribute(element, "disabled")
196
+ end
197
+
198
+ def isElementSelected(element)
199
+ # execute :isElementSelected, :element_id => element
200
+ execute :isSelected,
201
+ :element_id => element
202
+ end
203
+
204
+ def isElementDisplayed(element)
205
+ # execute :isElementDisplayed, :element_id => element
206
+ execute :isDisplayed,
207
+ :element_id => element
208
+ end
209
+
210
+ def submitElement(element)
211
+ # execute :submitElement, :element_id => element
212
+ execute :submit,
213
+ :element_id => element
214
+ end
215
+
216
+ def toggleElement(element)
217
+ # execute :toggleElement, :element_id => element
218
+ execute :toggle,
219
+ :element_id => element
220
+ end
221
+
222
+ def setElementSelected(element)
223
+ # execute :setElementSelected, :element_id => element
224
+ execute :setSelected,
225
+ :element_id => element
226
+ end
227
+
228
+ def getElementValueOfCssProperty(element, prop)
229
+ # execute :getElementValueOfCssProperty, :element_id => element, :parameters => [prop]
230
+ execute :getValueOfCssProperty,
231
+ :element_id => element,
232
+ :parameters => [prop]
233
+ end
234
+
235
+ def hoverOverElement
236
+ execute :hover,
237
+ :element_id => element
238
+ # execute :hoverOverElement, :element_id => element
239
+ end
240
+
241
+ def dragElement(element, rigth_by, down_by)
242
+ execute :dragElement,
243
+ :element_id => element,
244
+ :parameters => [rigth_by, down_by]
245
+ end
246
+
247
+
248
+ def setSpeed(speed)
249
+ pixel_speed = case speed
250
+ when "SLOW" then '1'
251
+ when "MEDIUM" then '10'
252
+ when "FAST" then '100'
253
+ else
254
+ raise ArgumentError, "unknown speed: #{speed.inspect}"
255
+ end
256
+
257
+ execute :setMouseSpeed,
258
+ :parameters => [pixel_speed]
259
+ end
260
+
261
+ def getSpeed
262
+ case execute(:getMouseSpeed)
263
+ when '1' then "SLOW"
264
+ when '10' then "MEDIUM"
265
+ when '100' then "FAST"
266
+ else
267
+ "FAST"
268
+ end
269
+ end
270
+
271
+ def addCookie(cookie)
272
+ execute :addCookie,
273
+ :parameters => [cookie.to_json] # uhm, sending text instead of data
274
+ end
275
+
276
+ def deleteCookie(name)
277
+ execute :deleteCookie,
278
+ :parameters => [{:name => name}.to_json] # ditto
279
+ end
280
+
281
+ def getAllCookies
282
+ data = execute :getCookie
283
+
284
+ data.strip.split("\n").map do |c|
285
+ parse_cookie_string(c) unless c.strip.empty?
286
+ end.compact
287
+ end
288
+
289
+ #
290
+ # FF-specific?
291
+ #
292
+
293
+ def deleteAllCookies
294
+ execute :deleteAllCookies
295
+ end
296
+
297
+ def getCookieNamed(name)
298
+ getCookies.find { |c| c['name'] == name }
299
+ end
300
+
301
+ def switchToFrame(name)
302
+ execute :switchToFrame,
303
+ :parameters => [name.to_s]
304
+ end
305
+
306
+ def switchToWindow(name)
307
+ @context = execute :switchToWindow,
308
+ :parameters => [name.to_s]
309
+ end
310
+
311
+ def switchToActiveElement
312
+ Element.new self, element_id_from(execute(:switchToActiveElement))
313
+ end
314
+ alias_method :getActiveElement, :switchToActiveElement
315
+
316
+ private
317
+
318
+ def find_element_by(how, what, parent = nil)
319
+ if parent
320
+ id = execute :findChildElement,
321
+ :parameters => [{:id => parent, :using => how, :value => what}]
322
+ else
323
+ id = execute :findElement,
324
+ :parameters => [how, what]
325
+ end
326
+
327
+ Element.new self, element_id_from(id)
328
+ end
329
+
330
+ def find_elements_by(how, what, parent = nil)
331
+ if parent
332
+ id_string = execute :findChildElements,
333
+ :parameters => [{:id => parent, :using => how, :value => what}]
334
+ else
335
+ id_string = execute :findElements,
336
+ :parameters => [how, what]
337
+ end
338
+
339
+ id_string.split(",").map { |id| Element.new self, element_id_from(id) }
340
+ end
341
+
342
+ def newSession
343
+ execute :newSession
344
+ end
345
+
346
+ def execute(*args)
347
+ raw_execute(*args)['response']
348
+ end
349
+
350
+ def raw_execute(command, opts = {})
351
+ request = {:commandName => command, :context => @context.to_s}
352
+
353
+ if eid = opts[:element_id]
354
+ request[:elementId] = eid
355
+ end
356
+
357
+ if params = opts[:parameters]
358
+ request[:parameters] = params
359
+ end
360
+
361
+ puts "--> #{request.inspect}" if $DEBUG
362
+
363
+ @connection.send_string request.to_json
364
+ resp = @connection.read_response
365
+
366
+ puts "<-- #{resp.inspect}" if $DEBUG
367
+
368
+ if resp['isError']
369
+ msg = resp['response']['message'] rescue nil
370
+ msg ||= resp['response'] || resp.inspect
371
+ raise Error::WebDriverError, msg
372
+ end
373
+
374
+ if ctx = resp['context']
375
+ @context = ctx
376
+ end
377
+
378
+ resp
379
+ end
380
+
381
+ #
382
+ # wrap/unwrap will be shared with Chrome (overrides BridgeHelper for now)
383
+ #
384
+
385
+ def wrap_script_argument(arg)
386
+ case arg
387
+ when Integer, Float
388
+ { :type => "NUMBER", :value => arg }
389
+ when TrueClass, FalseClass, NilClass
390
+ { :type => "BOOLEAN", :value => !!arg }
391
+ when Element
392
+ { :type => "ELEMENT", :value => arg.ref }
393
+ when String
394
+ { :type => "STRING", :value => arg.to_s }
395
+ when Array # Enumerable?
396
+ arg.map { |e| wrap_script_argument(e) }
397
+ else
398
+ raise TypeError, "Parameter is not of recognized type: #{arg.inspect}:#{arg.class}"
399
+ end
400
+ end
401
+
402
+ def unwrap_script_argument(arg)
403
+ raise TypeError, "expected Hash" unless arg.kind_of? Hash
404
+ case arg["resultType"]
405
+ when "NULL"
406
+ nil
407
+ when "ELEMENT"
408
+ Element.new self, element_id_from(arg["response"])
409
+ when "ARRAY"
410
+ arg['response'].map { |e| unwrap_script_argument(e) }
411
+ # when "POINT"
412
+ # Point.new arg['x'], arg['y']
413
+ # when "DIMENSION"
414
+ # Dimension.new arg['width'], arg['height']
415
+ # when "COOKIE"
416
+ # {:name => arg['name'], :value => arg['value']}
417
+ else
418
+ arg["response"]
419
+ end
420
+ end
421
+
422
+
423
+ end # Bridge
424
+ end # Firefox
425
+ end # WebDriver
426
+ end # Selenium