selenium-webdriver 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -77,11 +77,16 @@ function parsePortMessage(message) {
77
77
  element.scrollIntoView(true);
78
78
  //TODO: Work out a way of firing events,
79
79
  //now that synthesising them gives appendMessage errors
80
+ console.log("mouse downing");
80
81
  Utils.fireMouseEventOn(element, "mousedown");
82
+ console.log("mouse up");
81
83
  Utils.fireMouseEventOn(element, "mouseup");
84
+ console.log("mouse click");
82
85
  Utils.fireMouseEventOn(element, "click");
86
+
83
87
  if (element.click) {
84
- element.click();
88
+ console.log("click");
89
+ execute("try { arguments[0].click(); } catch(e){}", {type: "ELEMENT", value: getElementId_(element)});
85
90
  }
86
91
  response.value = {statusCode: 0};
87
92
  break;
@@ -535,6 +540,23 @@ function internalGetElement(elementIdAsString) {
535
540
  }
536
541
  }
537
542
 
543
+ /**
544
+ * Given an element, returning the index that can be used to locate it
545
+ *
546
+ * @param element the element to look up the internal ID of
547
+ * @return A positive integer on success or -1 otherwise
548
+ */
549
+ function getElementId_(element) {
550
+ var length = ChromeDriverContentScript.internalElementArray.length;
551
+ for (var i = 0; i < length; i++) {
552
+ if (ChromeDriverContentScript.internalElementArray[i] === element) {
553
+ return i;
554
+ }
555
+ }
556
+
557
+ return -1;
558
+ }
559
+
538
560
  /**
539
561
  * Ensures the passed element is in view, so that the native click event can be sent
540
562
  * @return object to send back to background page to trigger a native click
@@ -763,6 +785,8 @@ function toggleElement(element) {
763
785
  } catch (e) {
764
786
  return e;
765
787
  }
788
+ console.log("New value: " + newValue);
789
+
766
790
  if (changed) {
767
791
  //TODO: Work out a way of firing events,
768
792
  //now that synthesising them gives appendMessage errors
@@ -842,9 +866,10 @@ function parseWrappedArguments(argument) {
842
866
  * We can't share objects between content script and page, so have to wrap up arguments as JSON
843
867
  * @param script script to execute as a string
844
868
  * @param passedArgs array of arguments to pass to the script
869
+ * @param callback function to call when the result is returned
845
870
  */
846
- function execute(script, passedArgs) {
847
- console.log("execing " + script + ", args: " + JSON.stringify(passedArgs));
871
+ function execute_(script, passedArgs, callback) {
872
+ console.log("executing " + script + ", args: " + JSON.stringify(passedArgs));
848
873
  var func = "function(){" + script + "}";
849
874
  var args = [];
850
875
  for (var i = 0; i < passedArgs.length; ++i) {
@@ -899,11 +924,15 @@ function execute(script, passedArgs) {
899
924
  '}' +
900
925
  'document.getElementsByTagName("script")[document.getElementsByTagName("script").length - 1].dispatchEvent(e);' +
901
926
  'document.getElementsByTagName("html")[0].removeChild(document.getElementsByTagName("script")[document.getElementsByTagName("script").length - 1]);';
902
- scriptTag.addEventListener('DOMAttrModified', returnFromJavascriptInPage, false);
927
+ scriptTag.addEventListener('DOMAttrModified', callback, false);
903
928
  console.log("Injecting script element");
904
929
  ChromeDriverContentScript.currentDocument.getElementsByTagName("html")[0].appendChild(scriptTag);
905
930
  }
906
931
 
932
+ function execute(script, passedArgs) {
933
+ execute_(script, passedArgs, returnFromJavascriptInPage);
934
+ }
935
+
907
936
  function parseReturnValueFromScript(result) {
908
937
  console.log("Parsing: " + JSON.stringify(result));
909
938
  var value = {"type":"NULL"};
@@ -944,7 +973,7 @@ function returnFromJavascriptInPage(e) {
944
973
  console.log("Result was: " + e.newValue.value);
945
974
  var result = JSON.parse(e.newValue).value;
946
975
  var value = parseReturnValueFromScript(result);
947
- console.log("reutrn value: " + JSON.stringify(value));
976
+ console.log("Return value: " + JSON.stringify(value));
948
977
  ChromeDriverContentScript.port.postMessage({sequenceNumber: ChromeDriverContentScript.currentSequenceNumber, response: {response: "execute", value: {statusCode: 0, value: value}}});
949
978
  }
950
979
 
@@ -150,13 +150,11 @@ Utils.getStyleProperty = function(node, propertyName) {
150
150
  function collapseWhitespace(textSoFar) {
151
151
  return textSoFar.replace(/\s+/g, " ");
152
152
  }
153
- ;
154
153
 
155
154
  function getPreformattedText(node) {
156
155
  var textToAdd = "";
157
156
  return getTextFromNode(node, "", textToAdd, true)[1];
158
157
  }
159
- ;
160
158
 
161
159
  function isWhiteSpace(character) {
162
160
  return character == '\n' || character == ' ' || character == '\t' || character == '\r';
@@ -177,9 +175,19 @@ Utils.getText = function(element) {
177
175
  };
178
176
 
179
177
  Utils.fireHtmlEvent = function(element, eventName) {
180
- var e = document.createEvent("HTMLEvents");
181
- e.initEvent(eventName, true, true);
182
- element.dispatchEvent(e);
178
+ var args = [
179
+ {type: "ELEMENT", value: getElementId_(element)},
180
+ {type: "STRING", value: eventName}
181
+ ];
182
+
183
+ // We need to do this because event handlers refer to functions that
184
+ // the content script can't reah. See:
185
+ // http://code.google.com/p/chromium/issues/detail?id=29071
186
+ var script = "var e = document.createEvent('HTMLEvents'); "
187
+ + "e.initEvent(arguments[1], true, true); "
188
+ + "arguments[0].dispatchEvent(e);";
189
+
190
+ execute_(script, args, function(){});
183
191
  };
184
192
 
185
193
 
@@ -188,9 +196,22 @@ Utils.fireMouseEventOn = function(element, eventName) {
188
196
  };
189
197
 
190
198
  Utils.triggerMouseEvent = function(element, eventType, clientX, clientY) {
191
- var event = element.ownerDocument.createEvent("MouseEvents");
192
- var view = element.ownerDocument.defaultView;
193
-
194
- event.initMouseEvent(eventType, true, true, view, 1, 0, 0, clientX, clientY, false, false, false, false, 0, element);
195
- element.dispatchEvent(event);
199
+ var args = [
200
+ {type: "ELEMENT", value: getElementId_(element)},
201
+ {type: "STRING", value: eventType},
202
+ {type: "NUMBER", value: clientX},
203
+ {type: "NUMBER", value: clientY}
204
+ ];
205
+
206
+ // We need to do this because event handlers refer to functions that
207
+ // the content script can't reah. See:
208
+ // http://code.google.com/p/chromium/issues/detail?id=29071
209
+ var script =
210
+ "var event = arguments[0].ownerDocument.createEvent('MouseEvents'); "
211
+ + "var view = arguments[0].ownerDocument.defaultView; "
212
+ + "event.initMouseEvent(arguments[1], true, true, view, 1, 0, 0, arguments[2], arguments[3], false, false, false, false, 0, arguments[0]);"
213
+ + " arguments[0].dispatchEvent(event);";
214
+
215
+ execute_(script, args, function(){});
196
216
  };
217
+
@@ -56,8 +56,12 @@ module Selenium
56
56
  end
57
57
 
58
58
  def quit
59
- @launcher.kill # FIXME: let chrome extension take care of this
60
- execute :request => 'quit'
59
+ begin
60
+ execute :request => 'quit'
61
+ rescue IOError
62
+ end
63
+
64
+ @launcher.kill
61
65
  @executor.close
62
66
  end
63
67
 
@@ -92,6 +96,7 @@ module Selenium
92
96
  :script => script,
93
97
  :args => typed_args
94
98
 
99
+ return if resp.nil?
95
100
  unwrap_script_argument resp
96
101
  end
97
102
 
@@ -310,7 +315,10 @@ module Selenium
310
315
  private
311
316
 
312
317
  def execute(command)
318
+ puts "--> #{command.inspect}" if $DEBUG
313
319
  resp = raw_execute command
320
+ puts "<-- #{resp.inspect}" if $DEBUG
321
+
314
322
  code = resp['statusCode']
315
323
  if e = Error.for_code(code)
316
324
  msg = resp['value']['message'] if resp['value']
@@ -26,9 +26,9 @@ goog.require('goog.Disposable');
26
26
  goog.require('goog.array');
27
27
  goog.require('goog.object');
28
28
  goog.require('webdriver.CommandName');
29
- goog.require('webdriver.Context');
30
29
  goog.require('webdriver.Future');
31
30
  goog.require('webdriver.Response');
31
+ goog.require('webdriver.WebElement');
32
32
  goog.require('webdriver.timing');
33
33
 
34
34
 
@@ -57,11 +57,14 @@ webdriver.AbstractCommandProcessor.resolveFutureParams_ = function(
57
57
  function getValue(obj) {
58
58
  if (obj instanceof webdriver.Future) {
59
59
  return obj.getValue();
60
- } else if (goog.isFunction(obj)) {
60
+ } else if (goog.isFunction(obj) ||
61
+ obj instanceof webdriver.WebElement) {
61
62
  return obj;
62
63
  } else if (goog.isObject(obj)) {
63
64
  goog.object.forEach(obj, function(value, key) {
64
- obj[key] = getValue(value);
65
+ if (value instanceof webdriver.Future) {
66
+ obj[key] = value.getValue();
67
+ }
65
68
  });
66
69
  }
67
70
  return obj;
@@ -80,36 +83,41 @@ webdriver.AbstractCommandProcessor.resolveFutureParams_ = function(
80
83
  /**
81
84
  * Executes a command.
82
85
  * @param {webdriver.Command} command The command to execute.
83
- * @param {string} sessionId The current session ID.
84
- * @param {webdriver.Context} context The context to execute the command in.
85
86
  */
86
- webdriver.AbstractCommandProcessor.prototype.execute = function(command,
87
- sessionId,
88
- context) {
87
+ webdriver.AbstractCommandProcessor.prototype.execute = function(command) {
88
+ var driver = command.getDriver();
89
89
  webdriver.AbstractCommandProcessor.resolveFutureParams_(command);
90
- switch (command.name) {
90
+ var parameters = command.getParameters();
91
+ switch (command.getName()) {
91
92
  case webdriver.CommandName.SLEEP:
92
- var ms = command.parameters[0];
93
+ var ms = parameters[0];
93
94
  webdriver.timing.setTimeout(function() {
94
- command.setResponse(new webdriver.Response(false, context, ms));
95
+ command.setResponse(new webdriver.Response(
96
+ false, driver.getContext(), ms));
95
97
  }, ms);
96
98
  break;
97
99
 
98
100
  case webdriver.CommandName.WAIT:
99
101
  case webdriver.CommandName.FUNCTION:
100
102
  try {
101
- var result = command.parameters[0]();
102
- command.setResponse(new webdriver.Response(false, context, result));
103
+ var fn = parameters[0];
104
+ var selfObj = parameters[1];
105
+ var args = parameters[2];
106
+ var result = fn.apply(selfObj, args);
107
+ command.setResponse(new webdriver.Response(
108
+ false, driver.getContext(), result));
103
109
  } catch (ex) {
104
- command.setResponse(new webdriver.Response(true, context, null, ex));
110
+ command.setResponse(new webdriver.Response(
111
+ true, driver.getContext(), null, ex));
105
112
  }
106
113
  break;
107
114
 
108
115
  default:
109
116
  try {
110
- this.executeDriverCommand(command, sessionId, context);
117
+ this.dispatchDriverCommand(command);
111
118
  } catch (ex) {
112
- command.setResponse(new webdriver.Response(true, context, null, ex));
119
+ command.setResponse(new webdriver.Response(
120
+ true, driver.getContext(), null, ex));
113
121
  }
114
122
  break;
115
123
  }
@@ -120,9 +128,7 @@ webdriver.AbstractCommandProcessor.prototype.execute = function(command,
120
128
  * Sends a command to be executed by a browser driver. This method must be
121
129
  * implemented by each subclass.
122
130
  * @param {webdriver.Command} command The command to execute.
123
- * @param {string} sessionId The current session ID.
124
- * @param {webdriver.Context} context The context to execute the command in.
125
131
  * @protected
126
132
  */
127
- webdriver.AbstractCommandProcessor.prototype.executeDriverCommand =
133
+ webdriver.AbstractCommandProcessor.prototype.dispatchDriverCommand =
128
134
  goog.abstractMethod;
@@ -79,24 +79,6 @@ webdriver.Command = function(driver, name, opt_element) {
79
79
  */
80
80
  this.parameters = [];
81
81
 
82
- /**
83
- * Callback for when the command processor successfully finishes this command.
84
- * The result of this function is included in the final result of the command.
85
- * @type {?function}
86
- */
87
- this.onSuccessCallbackFn = null;
88
-
89
- /**
90
- * Callback for when the command processor fails to successfully finish a
91
- * command. The function should take a single argument, the
92
- * {@code webdriver.Response} from the command processor. The response may be
93
- * modified (for example, to turn an expect failure into a success). If the
94
- * error state is cleared, the {@code onSucessCallbackFn} will still not be
95
- * called.
96
- * @type {?function}
97
- */
98
- this.onFailureCallbackFn = null;
99
-
100
82
  /**
101
83
  * The response to this command.
102
84
  * @type {?webdriver.Response}
@@ -123,8 +105,6 @@ webdriver.Command.prototype.disposeInternal = function() {
123
105
  delete this.name;
124
106
  delete this.element;
125
107
  delete this.parameters;
126
- delete this.onSuccessCallbackFn;
127
- delete this.onFailureCallbackFn;
128
108
  delete this.response;
129
109
  };
130
110
 
@@ -180,35 +160,10 @@ webdriver.Command.prototype.setParameters = function(var_args) {
180
160
 
181
161
 
182
162
  /**
183
- * Set the function to call with the {@code webdriver.Response} when the
184
- * command processor successfully runs this command. This function is considered
185
- * part of the command and any errors will cause the command as a whole to fail.
186
- * @param {function} callbackFn The function to call on success.
187
- * @param {Object} opt_selfObj The object in whose context to execute the
188
- * function.
163
+ * @return {Array.<*>} The parameters to send with this command.
189
164
  */
190
- webdriver.Command.prototype.setSuccessCallback = function(callbackFn,
191
- opt_selfObj) {
192
- if (callbackFn) {
193
- this.onSuccessCallbackFn = goog.bind(callbackFn, opt_selfObj);
194
- }
195
- return this;
196
- };
197
-
198
-
199
- /**
200
- * Set the function to call with the {@code webdriver.Response} when the
201
- * command processor encounters an error while executing this command.
202
- * @param {function} callbackFn The function to call on failure.
203
- * @param {Object} opt_selfObj The object in whose context to execute the
204
- * function.
205
- */
206
- webdriver.Command.prototype.setFailureCallback = function(callbackFn,
207
- opt_selfObj) {
208
- if (callbackFn) {
209
- this.onFailureCallbackFn = goog.bind(callbackFn, opt_selfObj);
210
- }
211
- return this;
165
+ webdriver.Command.prototype.getParameters = function() {
166
+ return this.parameters;
212
167
  };
213
168
 
214
169
 
@@ -231,26 +186,7 @@ webdriver.Command.prototype.setResponse = function(response) {
231
186
  return;
232
187
  }
233
188
  this.response = response;
234
-
235
- var sandbox = goog.bind(function(fn) {
236
- try {
237
- fn.call(this, this.response);
238
- } catch (ex) {
239
- this.response.isFailure = true;
240
- this.response.errors.push(ex);
241
- }
242
- }, this);
243
-
244
- if (!this.response.errors.length) {
245
- if (this.response.isFailure &&
246
- goog.isFunction(this.onFailureCallbackFn)) {
247
- sandbox(this.onFailureCallbackFn);
248
- } else if (!this.response.isFailure &&
249
- goog.isFunction(this.onSuccessCallbackFn)) {
250
- sandbox(this.onSuccessCallbackFn);
251
- }
252
- }
253
-
189
+ this.driver_.setContext(this.response.context);
254
190
  if (!this.response.isFailure) {
255
191
  this.futureResult_.setValue(this.response.value);
256
192
  } else {
@@ -116,7 +116,11 @@ webdriver.Future.prototype.setValue = function(value) {
116
116
  }
117
117
  if (value instanceof webdriver.Future) {
118
118
  if (value.isSet()) {
119
- this.value_ = value.getValue();
119
+ value = value.getValue();
120
+ this.value_ = value;
121
+ goog.array.forEach(this.linkedFutures_, function(future) {
122
+ future.setValue(value);
123
+ });
120
124
  } else {
121
125
  value.linkedFutures_.push(this);
122
126
  }
@@ -0,0 +1,40 @@
1
+ /** @license
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * @fileoverview File to include for turnning any HTML page into a WebDriver
20
+ * JSUnit test suite by configuring an onload listener to the body that will
21
+ * instantiate and start the test runner.
22
+ */
23
+
24
+ goog.provide('webdriver.jsunit');
25
+
26
+ goog.require('goog.testing.jsunit');
27
+ goog.require('webdriver.TestCase');
28
+ goog.require('webdriver.asserts');
29
+ goog.require('webdriver.factory');
30
+
31
+
32
+ (function() {
33
+ window.onload = function() {
34
+ var test = new webdriver.TestCase(document.title,
35
+ webdriver.factory.createLocalWebDriver);
36
+ test.autoDiscoverTests();
37
+ G_testRunner.initialize(test);
38
+ G_testRunner.execute(test);
39
+ };
40
+ })();
@@ -24,6 +24,7 @@ limitations under the License.
24
24
  goog.provide('webdriver.LocalCommandProcessor');
25
25
 
26
26
  goog.require('goog.array');
27
+ goog.require('goog.debug.Logger');
27
28
  goog.require('goog.dom');
28
29
  goog.require('goog.events');
29
30
  goog.require('goog.json');
@@ -123,9 +124,8 @@ webdriver.LocalCommandProcessor.onResponse_ = function(command, e) {
123
124
  }
124
125
 
125
126
  var rawResponse = goog.json.parse(jsonResponse);
126
- webdriver.logging.info(
127
- 'receiving:\n' +
128
- webdriver.logging.describe(rawResponse, ' '));
127
+ goog.debug.Logger.getLogger('webdriver.LocalCommandProcessor').fine(
128
+ 'receiving:\n' + jsonResponse);
129
129
 
130
130
  var response = new webdriver.Response(
131
131
  rawResponse['isError'],
@@ -144,29 +144,34 @@ webdriver.LocalCommandProcessor.onResponse_ = function(command, e) {
144
144
  /**
145
145
  * @override
146
146
  */
147
- webdriver.LocalCommandProcessor.prototype.executeDriverCommand = function(
148
- command, sessionId, context) {
149
- if (command.name == webdriver.CommandName.SEND_KEYS) {
150
- command.parameters = [command.parameters.join('')];
147
+ webdriver.LocalCommandProcessor.prototype.dispatchDriverCommand = function(
148
+ command) {
149
+ if (command.getName() == webdriver.CommandName.SEND_KEYS) {
150
+ command.setParameters(command.getParameters().join(''));
151
151
  }
152
152
 
153
153
  var jsonCommand = {
154
- 'commandName': command.name,
155
- 'context': context.toString(),
156
- 'parameters': command.parameters
154
+ 'commandName': command.getName(),
155
+ 'context': command.getDriver().getContext().toString(),
156
+ 'parameters': command.getParameters()
157
157
  };
158
158
 
159
159
  if (command.element) {
160
- jsonCommand['elementId'] = command.element.getId().getValue();
160
+ try {
161
+ jsonCommand['elementId'] = command.element.getId().getValue();
162
+ } catch (ex) {
163
+ window.console.dir(command);
164
+ throw ex;
165
+ }
161
166
  }
162
167
 
163
- webdriver.logging.info(
164
- 'sending:\n' +
165
- webdriver.logging.describe(jsonCommand, ' '));
168
+ jsonCommand = goog.json.serialize(jsonCommand);
169
+ goog.debug.Logger.getLogger('webdriver.LocalCommandProcessor').fine(
170
+ 'sending:\n' + jsonCommand);
166
171
 
167
172
  this.documentElement_.setAttribute(
168
173
  webdriver.LocalCommandProcessor.MessageAttribute_.COMMAND,
169
- goog.json.serialize(jsonCommand));
174
+ jsonCommand);
170
175
 
171
176
  goog.events.listen(this.documentElement_,
172
177
  webdriver.LocalCommandProcessor.EventType_.RESPONSE,