selenium-webdriver 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/chrome/src/extension/background.js +19 -14
- data/chrome/src/extension/manifest-nonwin.json +1 -2
- data/chrome/src/extension/manifest-win.json +1 -2
- data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +5 -1
- data/common/src/js/abstractcommandprocessor.js +0 -33
- data/common/src/js/asserts.js +2 -2
- data/common/src/js/by.js +2 -0
- data/common/src/js/command.js +130 -36
- data/common/src/js/future.js +42 -23
- data/common/src/js/localcommandprocessor.js +0 -1
- data/common/src/js/testrunner.js +9 -16
- data/common/src/js/webdriver.js +225 -254
- data/common/src/js/webelement.js +76 -197
- data/common/src/rb/lib/selenium/webdriver/driver.rb +4 -0
- data/common/src/rb/lib/selenium/webdriver/element.rb +4 -0
- data/firefox/src/extension/components/badCertListener.js +186 -0
- data/firefox/src/extension/components/firefoxDriver.js +7 -16
- data/firefox/src/extension/components/nsCommandProcessor.js +10 -9
- data/firefox/src/extension/components/utils.js +5 -5
- data/firefox/src/extension/components/webdriverserver.js +5 -0
- data/firefox/src/extension/components/wrappedElement.js +10 -6
- data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +11 -12
- data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +2 -2
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +2 -1
- metadata +3 -4
- data/chrome/src/extension/toolstrip.html +0 -28
- data/common/src/js/wait.js +0 -199
@@ -131,7 +131,6 @@ webdriver.LocalCommandProcessor.onResponse_ = function(command, e) {
|
|
131
131
|
rawResponse['isError'],
|
132
132
|
webdriver.Context.fromString(rawResponse['context']),
|
133
133
|
rawResponse['response']);
|
134
|
-
response.extraData['resultType'] = rawResponse['resultType'];
|
135
134
|
|
136
135
|
// Only code in this file should be dispatching command events and listening
|
137
136
|
// for response events, so this is safe. If someone else decided to attach a
|
data/common/src/js/testrunner.js
CHANGED
@@ -230,12 +230,13 @@ webdriver.TestRunner.SINGLETON = null;
|
|
230
230
|
|
231
231
|
|
232
232
|
webdriver.TestRunner.start = function(factoryFn) {
|
233
|
-
if (webdriver.TestRunner.SINGLETON) {
|
234
|
-
|
233
|
+
if (!webdriver.TestRunner.SINGLETON) {
|
234
|
+
webdriver.TestRunner.SINGLETON = new webdriver.TestRunner(factoryFn);
|
235
|
+
webdriver.TestRunner.SINGLETON.go();
|
235
236
|
}
|
236
|
-
webdriver.TestRunner.SINGLETON
|
237
|
-
webdriver.TestRunner.SINGLETON.go();
|
237
|
+
return webdriver.TestRunner.SINGLETON;
|
238
238
|
};
|
239
|
+
goog.exportSymbol('WD_getTestRunner', webdriver.TestRunner.start);
|
239
240
|
|
240
241
|
|
241
242
|
/**
|
@@ -585,21 +586,13 @@ webdriver.TestRunner.prototype.tearDown_ = function(result, driver) {
|
|
585
586
|
*/
|
586
587
|
webdriver.TestRunner.prototype.handleDriverError_ = function(result, e) {
|
587
588
|
result.passed = false;
|
588
|
-
var failingCommand = e.target
|
589
|
-
var response = failingCommand
|
589
|
+
var failingCommand = e.target;
|
590
|
+
var response = failingCommand.getResponse();
|
590
591
|
if (response) {
|
591
|
-
result.errMsg =
|
592
|
-
if (response.value) {
|
593
|
-
result.errMsg.push(' ' + response.value);
|
594
|
-
}
|
595
|
-
goog.array.extend(
|
596
|
-
result.errMsg, goog.array.map(response.errors, function(error) {
|
597
|
-
return error.message + (error.stack ? ('\n' + error.stack) : '');
|
598
|
-
}));
|
599
|
-
result.errMsg = result.errMsg.join('\n');
|
592
|
+
result.errMsg = response.getErrorMessage();
|
600
593
|
} else {
|
601
594
|
// Should never happen, but just in case.
|
602
595
|
result.errMsg = 'Unknown error!';
|
603
596
|
}
|
604
|
-
this.reportResult_(result,
|
597
|
+
this.reportResult_(result, failingCommand.getDriver());
|
605
598
|
};
|
data/common/src/js/webdriver.js
CHANGED
@@ -22,15 +22,14 @@ limitations under the License.
|
|
22
22
|
|
23
23
|
goog.provide('webdriver.WebDriver');
|
24
24
|
goog.provide('webdriver.WebDriver.EventType');
|
25
|
+
goog.provide('webdriver.WebDriver.Speed');
|
25
26
|
|
26
27
|
goog.require('goog.events');
|
27
28
|
goog.require('goog.events.EventTarget');
|
28
29
|
goog.require('webdriver.Command');
|
29
30
|
goog.require('webdriver.CommandName');
|
30
31
|
goog.require('webdriver.Context');
|
31
|
-
goog.require('webdriver.Future');
|
32
32
|
goog.require('webdriver.Response');
|
33
|
-
goog.require('webdriver.Wait');
|
34
33
|
goog.require('webdriver.WebElement');
|
35
34
|
goog.require('webdriver.logging');
|
36
35
|
goog.require('webdriver.timing');
|
@@ -77,31 +76,23 @@ webdriver.WebDriver = function(commandProcessor) {
|
|
77
76
|
this.commandProcessor_ = commandProcessor;
|
78
77
|
|
79
78
|
/**
|
80
|
-
*
|
81
|
-
*
|
82
|
-
*
|
83
|
-
*
|
84
|
-
* 2: a command within a wait condition is pending with the command
|
85
|
-
* processor
|
86
|
-
* @type {Array.<webdriver.Command>}
|
87
|
-
* @private
|
88
|
-
*/
|
89
|
-
this.pendingCommands_ = [];
|
90
|
-
|
91
|
-
/**
|
92
|
-
* A stack of frames for managing batched command execution order.
|
79
|
+
* A stack of frames for queued commands. The list of commands at index 0
|
80
|
+
* are global commands. When the stack has more than 1 frame, the commands
|
81
|
+
* in the list at the top of the stack are the remaining subcommands for the
|
82
|
+
* command at the top of the {@code pendingCommands_} stack.
|
93
83
|
* @type {Array.<Array.<webdriver.Command>>}
|
94
84
|
* @private
|
95
85
|
*/
|
96
|
-
this.
|
86
|
+
this.queuedCommands_ = [[]];
|
97
87
|
|
98
88
|
/**
|
99
|
-
* A list of commands that
|
100
|
-
*
|
89
|
+
* A list of commands that are currently being executed. The command at index
|
90
|
+
* N+1 is a subcommand to the command at index N. It will always be the case
|
91
|
+
* that {@code queuedCommands_.length == pendingCommands_.length + 1;}.
|
101
92
|
* @type {Array.<webdriver.Command>}
|
102
|
-
* @
|
93
|
+
* @private
|
103
94
|
*/
|
104
|
-
this.
|
95
|
+
this.pendingCommands_ = [];
|
105
96
|
|
106
97
|
/**
|
107
98
|
* Whether this instance is paused. When paused, commands can still be issued,
|
@@ -188,10 +179,18 @@ webdriver.WebDriver.prototype.disposeInternal = function() {
|
|
188
179
|
this.commandProcessor_.dispose();
|
189
180
|
webdriver.timing.clearInterval(this.commandInterval_);
|
190
181
|
|
182
|
+
goog.array.forEach(this.pendingCommands_, function(command) {
|
183
|
+
command.dispose();
|
184
|
+
});
|
185
|
+
goog.array.forEach(this.queuedCommands_, function(frame) {
|
186
|
+
goog.array.forEach(frame, function(command) {
|
187
|
+
command.dispose();
|
188
|
+
});
|
189
|
+
});
|
190
|
+
|
191
191
|
delete this.commandProcessor_;
|
192
192
|
delete this.pendingCommands_;
|
193
|
-
delete this.
|
194
|
-
delete this.commandHistory_;
|
193
|
+
delete this.queuedCommands_;
|
195
194
|
delete this.isPaused_;
|
196
195
|
delete this.context_;
|
197
196
|
delete this.sessionLocked_;
|
@@ -204,44 +203,60 @@ webdriver.WebDriver.prototype.disposeInternal = function() {
|
|
204
203
|
|
205
204
|
/**
|
206
205
|
* Queues a command to execute.
|
207
|
-
* @param {webdriver.
|
208
|
-
* @param {
|
209
|
-
*
|
206
|
+
* @param {webdriver.CommandName} name The name of the command to execute.
|
207
|
+
* @param {webdriver.WebElement} opt_element The element that is the target
|
208
|
+
* of the new command.
|
209
|
+
* @return {webdriver.Command} The new command.
|
210
210
|
* @protected
|
211
211
|
*/
|
212
|
-
webdriver.WebDriver.prototype.addCommand = function(
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
}
|
217
|
-
var frame = goog.array.peek(this.frames_);
|
218
|
-
if (opt_addToFront) {
|
219
|
-
goog.array.insertAt(frame, command, 0);
|
220
|
-
} else {
|
221
|
-
frame.push(command);
|
222
|
-
}
|
212
|
+
webdriver.WebDriver.prototype.addCommand = function(name, opt_element) {
|
213
|
+
var command = new webdriver.Command(this, name, opt_element);
|
214
|
+
goog.array.peek(this.queuedCommands_).push(command);
|
215
|
+
return command;
|
223
216
|
};
|
224
217
|
|
225
218
|
|
226
219
|
/**
|
227
|
-
* @return {
|
228
|
-
*
|
220
|
+
* @return {boolean} Whether this driver is idle (there are no pending
|
221
|
+
* commands).
|
229
222
|
*/
|
230
|
-
webdriver.WebDriver.prototype.
|
231
|
-
|
223
|
+
webdriver.WebDriver.prototype.isIdle = function() {
|
224
|
+
// If there is a finished command on the pending command queue, but it
|
225
|
+
// failed, then the failure hasn't been dealt with yet and the driver will
|
226
|
+
// not process any more commands, so we consider this idle.
|
227
|
+
var pendingCommand = goog.array.peek(this.pendingCommands_);
|
228
|
+
if (pendingCommand && pendingCommand.isFinished() &&
|
229
|
+
pendingCommand.getResponse().isFailure) {
|
230
|
+
return true;
|
231
|
+
}
|
232
|
+
return !pendingCommand && this.queuedCommands_.length == 1 &&
|
233
|
+
!this.queuedCommands_[0].length;
|
232
234
|
};
|
233
235
|
|
234
236
|
|
235
237
|
/**
|
236
|
-
* Aborts the
|
237
|
-
*
|
238
|
+
* Aborts the specified command and all of its pending subcommands.
|
239
|
+
* @param {webdriver.Command} command The command to abort.
|
240
|
+
* @return {number} The total number of commands aborted. A value of 0
|
241
|
+
* indicates that the given command was not a pending command.
|
238
242
|
*/
|
239
|
-
webdriver.WebDriver.prototype.
|
240
|
-
goog.array.
|
241
|
-
|
243
|
+
webdriver.WebDriver.prototype.abortCommand = function(command) {
|
244
|
+
var index = goog.array.findIndexRight(this.pendingCommands_, function(cmd) {
|
245
|
+
return cmd == command;
|
242
246
|
});
|
243
|
-
|
244
|
-
|
247
|
+
if (index >= 0) {
|
248
|
+
var numAborted = this.pendingCommands_.length - index;
|
249
|
+
var totalNumAborted = numAborted;
|
250
|
+
for (var i = 0; i < numAborted; i++) {
|
251
|
+
this.pendingCommands_.pop().dispose();
|
252
|
+
goog.array.forEach(this.queuedCommands_.pop(), function(subCommand) {
|
253
|
+
totalNumAborted += 1;
|
254
|
+
subCommand.dispose();
|
255
|
+
});
|
256
|
+
}
|
257
|
+
return totalNumAborted;
|
258
|
+
}
|
259
|
+
return 0;
|
245
260
|
};
|
246
261
|
|
247
262
|
|
@@ -273,62 +288,38 @@ webdriver.WebDriver.prototype.resume = function() {
|
|
273
288
|
* @private
|
274
289
|
*/
|
275
290
|
webdriver.WebDriver.prototype.processCommands_ = function() {
|
276
|
-
|
291
|
+
var pendingCommand = goog.array.peek(this.pendingCommands_);
|
292
|
+
if (this.isPaused_ || (pendingCommand && !pendingCommand.isFinished())) {
|
277
293
|
return;
|
278
294
|
}
|
279
295
|
|
280
|
-
|
281
|
-
|
296
|
+
if (pendingCommand && pendingCommand.getResponse().isFailure) {
|
297
|
+
// Or should we be throwing this to be caught by window.onerror?
|
298
|
+
webdriver.logging.error(
|
299
|
+
'Unhandled command failure; halting command processing:\n' +
|
300
|
+
pendingCommand.getResponse().getErrorMessage());
|
282
301
|
return;
|
283
302
|
}
|
284
303
|
|
285
|
-
var currentFrame = goog.array.peek(this.
|
304
|
+
var currentFrame = goog.array.peek(this.queuedCommands_);
|
286
305
|
var nextCommand = currentFrame.shift();
|
306
|
+
while (!nextCommand && this.queuedCommands_.length > 1) {
|
307
|
+
this.queuedCommands_.pop();
|
308
|
+
this.pendingCommands_.pop();
|
309
|
+
currentFrame = goog.array.peek(this.queuedCommands_);
|
310
|
+
nextCommand = currentFrame.shift();
|
311
|
+
}
|
312
|
+
|
287
313
|
if (nextCommand) {
|
314
|
+
var parentTarget = goog.array.peek(this.pendingCommands_) || this;
|
315
|
+
nextCommand.setParentEventTarget(parentTarget);
|
288
316
|
this.pendingCommands_.push(nextCommand);
|
289
|
-
|
290
|
-
this.frames_.push([]);
|
291
|
-
} else if (nextCommand.name == webdriver.CommandName.WAIT) {
|
292
|
-
this.waitFrame_ = [];
|
293
|
-
this.frames_.push(this.waitFrame_);
|
294
|
-
}
|
295
|
-
|
296
|
-
nextCommand.setCompleteCallback(this.onCommandComplete_, this);
|
317
|
+
this.queuedCommands_.push([]);
|
297
318
|
this.commandProcessor_.execute(nextCommand, this.sessionId_, this.context_);
|
298
|
-
} else if (this.frames_.length > 1) {
|
299
|
-
if (currentFrame !== this.waitFrame_) {
|
300
|
-
this.frames_.pop();
|
301
|
-
}
|
302
|
-
}
|
303
|
-
};
|
304
|
-
|
305
|
-
|
306
|
-
/**
|
307
|
-
* Callback for when a pending {@code webdriver.Command} is finished.
|
308
|
-
* @private
|
309
|
-
*/
|
310
|
-
webdriver.WebDriver.prototype.onCommandComplete_ = function(command) {
|
311
|
-
this.commandHistory_.push(command);
|
312
|
-
if (command.response.isFailure || command.response.errors.length) {
|
313
|
-
if (webdriver.CommandName.WAIT == command.name) {
|
314
|
-
// The wait terminated early. Abort all other commands issued inside the
|
315
|
-
// wait condition.
|
316
|
-
for (var i = 1; i < this.pendingCommands_.length; i++) {
|
317
|
-
this.pendingCommands_[i].abort = true;
|
318
|
-
}
|
319
|
-
this.pendingCommands_ = [this.pendingCommands_[0]];
|
320
|
-
}
|
321
|
-
this.dispatchEvent(webdriver.WebDriver.EventType.ERROR);
|
322
|
-
} else {
|
323
|
-
this.pendingCommands_.pop();
|
324
|
-
if (webdriver.CommandName.WAIT == command.name) {
|
325
|
-
this.waitFrame_ = null;
|
326
|
-
}
|
327
319
|
}
|
328
320
|
};
|
329
321
|
|
330
322
|
|
331
|
-
|
332
323
|
/**
|
333
324
|
* @return {?string} This instance's current session ID or {@code null} if it
|
334
325
|
* does not have one yet.
|
@@ -346,6 +337,15 @@ webdriver.WebDriver.prototype.getContext = function() {
|
|
346
337
|
};
|
347
338
|
|
348
339
|
|
340
|
+
/**
|
341
|
+
* Sets this driver's context.
|
342
|
+
* @param {webdriver.Context} context The new context.
|
343
|
+
*/
|
344
|
+
webdriver.WebDriver.prototype.setContext = function(context) {
|
345
|
+
return this.context_ = context;
|
346
|
+
};
|
347
|
+
|
348
|
+
|
349
349
|
// ----------------------------------------------------------------------------
|
350
350
|
// Client command functions:
|
351
351
|
// ----------------------------------------------------------------------------
|
@@ -361,66 +361,32 @@ webdriver.WebDriver.prototype.getContext = function() {
|
|
361
361
|
*/
|
362
362
|
webdriver.WebDriver.prototype.catchExpectedError = function(opt_errorMsg,
|
363
363
|
opt_handlerFn) {
|
364
|
-
var currentFrame = goog.array.peek(this.
|
365
|
-
var previousCommand =
|
364
|
+
var currentFrame = goog.array.peek(this.queuedCommands_);
|
365
|
+
var previousCommand = goog.array.peek(currentFrame);
|
366
366
|
if (!previousCommand) {
|
367
367
|
throw new Error('No commands in the queue to expect an error from');
|
368
368
|
}
|
369
369
|
|
370
|
-
var
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
// Errors cause the pending command to hang. Go ahead and abort that command
|
389
|
-
// so we can proceed.
|
390
|
-
this.abortPendingCommand();
|
391
|
-
var frame = goog.array.peek(this.frames_);
|
392
|
-
while (frame !== currentFrame) {
|
393
|
-
this.frames_.pop();
|
394
|
-
frame = goog.array.peek(this.frames_);
|
370
|
+
var failedCommand = null;
|
371
|
+
var key = goog.events.listenOnce(previousCommand,
|
372
|
+
webdriver.Command.ERROR_EVENT, function(e) {
|
373
|
+
failedCommand = e.target;
|
374
|
+
this.abortCommand(e.currentTarget);
|
375
|
+
e.preventDefault();
|
376
|
+
e.stopPropagation();
|
377
|
+
return false;
|
378
|
+
}, /*capture phase*/true, this);
|
379
|
+
|
380
|
+
this.callFunction(function() {
|
381
|
+
if (null == failedCommand) {
|
382
|
+
goog.events.unlistenByKey(key);
|
383
|
+
throw new Error(
|
384
|
+
(opt_errorMsg ? (opt_errorMsg + '\n') : '') +
|
385
|
+
'Expected an error but none were raised.');
|
386
|
+
} else if (goog.isFunction(opt_handlerFn)) {
|
387
|
+
opt_handlerFn(failedCommand);
|
395
388
|
}
|
396
|
-
|
397
|
-
};
|
398
|
-
|
399
|
-
// Surround the last command with two new commands. The first enables our
|
400
|
-
// error listener which cancels any errors. The second verifies that we
|
401
|
-
// caught an error. If not, it fails the test.
|
402
|
-
var catchExpected = new webdriver.Command(webdriver.CommandName.FUNCTION).
|
403
|
-
setParameters(goog.bind(function() {
|
404
|
-
goog.events.listenOnce(this, webdriver.WebDriver.EventType.ERROR,
|
405
|
-
handleError, /*capture=*/true);
|
406
|
-
}, this));
|
407
|
-
|
408
|
-
var cleanupCatch = new webdriver.Command(webdriver.CommandName.FUNCTION).
|
409
|
-
setParameters(goog.bind(function() {
|
410
|
-
// Need to unlisten for error events so the error below doesn't get
|
411
|
-
// blocked.
|
412
|
-
goog.events.unlisten(this, webdriver.WebDriver.EventType.ERROR,
|
413
|
-
handleError, /*capture=*/true);
|
414
|
-
if (!caughtError) {
|
415
|
-
throw new Error(
|
416
|
-
(opt_errorMsg ? (opt_errorMsg + '\n') : '') +
|
417
|
-
'Expected an error but none were raised.');
|
418
|
-
}
|
419
|
-
}, this));
|
420
|
-
|
421
|
-
currentFrame.push(catchExpected);
|
422
|
-
currentFrame.push(previousCommand);
|
423
|
-
currentFrame.push(cleanupCatch);
|
389
|
+
});
|
424
390
|
};
|
425
391
|
|
426
392
|
|
@@ -441,8 +407,7 @@ webdriver.WebDriver.prototype.pause = function() {
|
|
441
407
|
* sleep.
|
442
408
|
*/
|
443
409
|
webdriver.WebDriver.prototype.sleep = function(ms) {
|
444
|
-
this.addCommand(
|
445
|
-
setParameters(ms));
|
410
|
+
this.addCommand(webdriver.CommandName.SLEEP).setParameters(ms);
|
446
411
|
};
|
447
412
|
|
448
413
|
|
@@ -453,24 +418,27 @@ webdriver.WebDriver.prototype.sleep = function(ms) {
|
|
453
418
|
* {@code webdriver.Response} and passed to any subsequent function commands.
|
454
419
|
* @param {function} fn The function to call; should take a single
|
455
420
|
* {@code webdriver.Response} object.
|
421
|
+
* @return {webdriver.Future} The result of the function wrapped in a future.
|
456
422
|
*/
|
457
423
|
webdriver.WebDriver.prototype.callFunction = function(fn, opt_selfObj,
|
458
424
|
var_args) {
|
459
425
|
var args = goog.array.slice(arguments, 2);
|
426
|
+
var frame = goog.array.peek(this.queuedCommands_);
|
427
|
+
var previousCommand = goog.array.peek(frame);
|
460
428
|
var wrappedFunction = goog.bind(function() {
|
461
|
-
|
462
|
-
|
463
|
-
fn.apply(opt_selfObj, args);
|
429
|
+
args.push(previousCommand ? previousCommand.getResponse() : null);
|
430
|
+
return fn.apply(opt_selfObj, args);
|
464
431
|
}, this);
|
465
|
-
this.addCommand(
|
466
|
-
setParameters(wrappedFunction)
|
432
|
+
return this.addCommand(webdriver.CommandName.FUNCTION).
|
433
|
+
setParameters(wrappedFunction).
|
434
|
+
getFutureResult();
|
467
435
|
};
|
468
436
|
|
469
437
|
|
470
438
|
/**
|
471
439
|
* Waits for a condition to be true before executing the next command. If the
|
472
440
|
* condition does not hold after the given {@code timeout}, an error will be
|
473
|
-
* raised.
|
441
|
+
* raised.
|
474
442
|
* Example:
|
475
443
|
* <code>
|
476
444
|
* driver.get('http://www.google.com');
|
@@ -481,23 +449,46 @@ webdriver.WebDriver.prototype.callFunction = function(fn, opt_selfObj,
|
|
481
449
|
* @param {number} timeout The maximum amount of time to wait, in milliseconds.
|
482
450
|
* @param {Object} opt_self (Optional) The object in whose context to execute
|
483
451
|
* the {@code conditionFn}.
|
484
|
-
* @
|
485
|
-
* @
|
486
|
-
*/
|
487
|
-
webdriver.WebDriver.prototype.wait = function(conditionFn, timeout, opt_self
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
452
|
+
* @param {boolean} opt_waitNot (Optional) Whether to wait for the inverse of
|
453
|
+
* the {@code conditionFn}.
|
454
|
+
*/
|
455
|
+
webdriver.WebDriver.prototype.wait = function(conditionFn, timeout, opt_self,
|
456
|
+
opt_waitNot) {
|
457
|
+
conditionFn = goog.bind(conditionFn, opt_self);
|
458
|
+
var waitOnInverse = !!opt_waitNot;
|
459
|
+
var callFunction = goog.bind(this.callFunction, this);
|
460
|
+
|
461
|
+
function pollFunction(opt_startTime, opt_future) {
|
462
|
+
var startTime = opt_startTime || goog.now();
|
463
|
+
|
464
|
+
function checkValue(value) {
|
465
|
+
var pendingFuture = null;
|
466
|
+
if (value instanceof webdriver.Future) {
|
467
|
+
if (value.isSet()) {
|
468
|
+
value = value.getValue();
|
469
|
+
} else {
|
470
|
+
pendingFuture = value;
|
471
|
+
value = null;
|
472
|
+
}
|
473
|
+
}
|
474
|
+
|
475
|
+
var done = !pendingFuture && (waitOnInverse != !!value);
|
476
|
+
if (!done) {
|
477
|
+
var ellapsed = goog.now() - startTime;
|
478
|
+
if (ellapsed > timeout) {
|
479
|
+
throw Error('Wait timed out after ' + ellapsed + 'ms');
|
480
|
+
}
|
481
|
+
callFunction(pollFunction, null, startTime, pendingFuture);
|
482
|
+
}
|
492
483
|
}
|
493
|
-
}
|
494
484
|
|
495
|
-
|
496
|
-
|
485
|
+
var result = opt_future || conditionFn();
|
486
|
+
checkValue(result);
|
497
487
|
}
|
498
|
-
|
499
|
-
|
500
|
-
|
488
|
+
|
489
|
+
// Binding pollFunction for our initial values.
|
490
|
+
var initialPoll = goog.bind(pollFunction, null, 0, null);
|
491
|
+
this.addCommand(webdriver.CommandName.WAIT).setParameters(initialPoll);
|
501
492
|
};
|
502
493
|
|
503
494
|
|
@@ -514,17 +505,10 @@ webdriver.WebDriver.prototype.wait = function(conditionFn, timeout, opt_self) {
|
|
514
505
|
* @param {number} timeout The maximum amount of time to wait, in milliseconds.
|
515
506
|
* @param {Object} opt_self (Optional) The object in whose context to execute
|
516
507
|
* the {@code conditionFn}.
|
517
|
-
* @see webdriver.Wait
|
518
508
|
*/
|
519
|
-
webdriver.WebDriver.prototype.waitNot = function(conditionFn, timeout,
|
520
|
-
|
521
|
-
|
522
|
-
conditionFn = goog.bind(conditionFn, opt_self);
|
523
|
-
}
|
524
|
-
var waitOp = new webdriver.Wait(conditionFn, timeout);
|
525
|
-
waitOp.waitOnInverse(true);
|
526
|
-
this.addCommand(new webdriver.Command(webdriver.CommandName.WAIT).
|
527
|
-
setParameters(waitOp));
|
509
|
+
webdriver.WebDriver.prototype.waitNot = function(conditionFn, timeout,
|
510
|
+
opt_self) {
|
511
|
+
this.wait(conditionFn, timeout, opt_self, true);
|
528
512
|
};
|
529
513
|
|
530
514
|
|
@@ -537,12 +521,12 @@ webdriver.WebDriver.prototype.waitNot = function(conditionFn, timeout, opt_self,
|
|
537
521
|
*/
|
538
522
|
webdriver.WebDriver.prototype.newSession = function(lockSession) {
|
539
523
|
if (lockSession) {
|
540
|
-
this.addCommand(
|
524
|
+
this.addCommand(webdriver.CommandName.NEW_SESSION).
|
541
525
|
setSuccessCallback(function(response) {
|
542
526
|
this.sessionLocked_ = lockSession;
|
543
527
|
this.sessionId_ = response.value;
|
544
528
|
this.context_ = response.context;
|
545
|
-
}, this)
|
529
|
+
}, this);
|
546
530
|
} else {
|
547
531
|
webdriver.logging.warn(
|
548
532
|
'Cannot start new session; driver is locked into current session');
|
@@ -558,11 +542,11 @@ webdriver.WebDriver.prototype.newSession = function(lockSession) {
|
|
558
542
|
* {@code #getWindowHandle()} or {@code #getAllWindowHandles()}.
|
559
543
|
*/
|
560
544
|
webdriver.WebDriver.prototype.switchToWindow = function(name) {
|
561
|
-
this.addCommand(
|
545
|
+
this.addCommand(webdriver.CommandName.SWITCH_TO_WINDOW).
|
562
546
|
setParameters(name).
|
563
547
|
setSuccessCallback(function(response) {
|
564
548
|
this.context_ = response.value;
|
565
|
-
}, this)
|
549
|
+
}, this);
|
566
550
|
};
|
567
551
|
|
568
552
|
|
@@ -580,13 +564,13 @@ webdriver.WebDriver.prototype.switchToFrame = function(frame) {
|
|
580
564
|
var commandName = webdriver.CommandName.SWITCH_TO_FRAME;
|
581
565
|
var command;
|
582
566
|
if (goog.isString(frame) || goog.isNumber(frame)) {
|
583
|
-
command =
|
567
|
+
command = this.addCommand(commandName).setParameters(frame);
|
584
568
|
} else {
|
585
|
-
command =
|
569
|
+
command = this.addCommand(commandName, frame);
|
586
570
|
}
|
587
|
-
|
571
|
+
command.setSuccessCallback(function(response) {
|
588
572
|
this.context_ = response.context;
|
589
|
-
}, this)
|
573
|
+
}, this);
|
590
574
|
};
|
591
575
|
|
592
576
|
|
@@ -595,13 +579,11 @@ webdriver.WebDriver.prototype.switchToFrame = function(frame) {
|
|
595
579
|
* contains iframes.
|
596
580
|
*/
|
597
581
|
webdriver.WebDriver.prototype.switchToDefaultContent = function() {
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
}, this);
|
604
|
-
this.addCommand(command);
|
582
|
+
this.addCommand(webdriver.CommandName.SWITCH_TO_DEFAULT_CONTENT).
|
583
|
+
setParameters(null).
|
584
|
+
setSuccessCallback(function(response) {
|
585
|
+
this.context_ = response.context;
|
586
|
+
}, this);
|
605
587
|
};
|
606
588
|
|
607
589
|
|
@@ -610,12 +592,8 @@ webdriver.WebDriver.prototype.switchToDefaultContent = function() {
|
|
610
592
|
* @return {webdriver.Future} The current handle wrapped in a Future.
|
611
593
|
*/
|
612
594
|
webdriver.WebDriver.prototype.getWindowHandle = function() {
|
613
|
-
|
614
|
-
|
615
|
-
new webdriver.Command(webdriver.CommandName.GET_CURRENT_WINDOW_HANDLE).
|
616
|
-
setSuccessCallback(handle.setValueFromResponse, handle);
|
617
|
-
this.addCommand(command);
|
618
|
-
return handle;
|
595
|
+
return this.addCommand(webdriver.CommandName.GET_CURRENT_WINDOW_HANDLE).
|
596
|
+
getFutureResult();
|
619
597
|
};
|
620
598
|
|
621
599
|
|
@@ -623,12 +601,7 @@ webdriver.WebDriver.prototype.getWindowHandle = function() {
|
|
623
601
|
* Retrieves the handles for all known windows.
|
624
602
|
*/
|
625
603
|
webdriver.WebDriver.prototype.getAllWindowHandles = function() {
|
626
|
-
|
627
|
-
new webdriver.Command(webdriver.CommandName.GET_WINDOW_HANDLES).
|
628
|
-
setSuccessCallback(function(response) {
|
629
|
-
response.value = response.value.split(',');
|
630
|
-
});
|
631
|
-
this.addCommand(command);
|
604
|
+
this.addCommand(webdriver.CommandName.GET_WINDOW_HANDLES);
|
632
605
|
};
|
633
606
|
|
634
607
|
|
@@ -637,11 +610,8 @@ webdriver.WebDriver.prototype.getAllWindowHandles = function() {
|
|
637
610
|
* @return {webdriver.Future} The page source wrapped in a Future.
|
638
611
|
*/
|
639
612
|
webdriver.WebDriver.prototype.getPageSource = function() {
|
640
|
-
|
641
|
-
|
642
|
-
setSuccessCallback(source.setValueFromResponse, source);
|
643
|
-
this.addCommand(command);
|
644
|
-
return source;
|
613
|
+
return this.addCommand(webdriver.CommandName.GET_PAGE_SOURCE).
|
614
|
+
getFutureResult();
|
645
615
|
};
|
646
616
|
|
647
617
|
|
@@ -651,7 +621,7 @@ webdriver.WebDriver.prototype.getPageSource = function() {
|
|
651
621
|
* script window (e.g. the window sending commands to the driver)</strong>
|
652
622
|
*/
|
653
623
|
webdriver.WebDriver.prototype.close = function() {
|
654
|
-
this.addCommand(
|
624
|
+
this.addCommand(webdriver.CommandName.CLOSE);
|
655
625
|
};
|
656
626
|
|
657
627
|
|
@@ -664,7 +634,7 @@ webdriver.WebDriver.prototype.close = function() {
|
|
664
634
|
* @see {webdriver.WebDriver.prototype.executeScript}
|
665
635
|
* @private
|
666
636
|
*/
|
667
|
-
webdriver.WebDriver.
|
637
|
+
webdriver.WebDriver.wrapScriptArgument_ = function(arg) {
|
668
638
|
var type, value;
|
669
639
|
if (arg instanceof webdriver.WebElement) {
|
670
640
|
type = 'ELEMENT';
|
@@ -674,6 +644,9 @@ webdriver.WebDriver.mapToExecuteScriptArgument_ = function(arg) {
|
|
674
644
|
goog.isString(arg)) {
|
675
645
|
type = goog.typeOf(arg).toUpperCase();
|
676
646
|
value = arg;
|
647
|
+
} else if (goog.isArray(arg)) {
|
648
|
+
type = goog.typeOf(arg).toUpperCase();
|
649
|
+
value = goog.array.map(arg, webdriver.WebDriver.wrapScriptArgument_);
|
677
650
|
} else {
|
678
651
|
throw new Error('Invalid script argument type: ' + goog.typeOf(arg));
|
679
652
|
}
|
@@ -681,6 +654,30 @@ webdriver.WebDriver.mapToExecuteScriptArgument_ = function(arg) {
|
|
681
654
|
};
|
682
655
|
|
683
656
|
|
657
|
+
/**
|
658
|
+
* Helper function for unwrapping an executeScript result.
|
659
|
+
* @param {{type:string,value:*}|Array.<{type:string,value:*}>} result The
|
660
|
+
* result to unwrap.
|
661
|
+
* @return {*} The unwrapped result.
|
662
|
+
* @private
|
663
|
+
*/
|
664
|
+
webdriver.WebDriver.prototype.unwrapScriptResult_ = function(result) {
|
665
|
+
switch (result.type) {
|
666
|
+
case 'ELEMENT':
|
667
|
+
var element = new webdriver.WebElement(this);
|
668
|
+
element.getId().setValue(result.value);
|
669
|
+
return element;
|
670
|
+
|
671
|
+
case 'ARRAY':
|
672
|
+
return goog.array.map(result.value, goog.bind(
|
673
|
+
this.unwrapScriptResult_, this));
|
674
|
+
|
675
|
+
default:
|
676
|
+
return result.value;
|
677
|
+
}
|
678
|
+
};
|
679
|
+
|
680
|
+
|
684
681
|
/**
|
685
682
|
* Adds a command to execute a JavaScript snippet in the window of the page
|
686
683
|
* currently under test.
|
@@ -692,29 +689,13 @@ webdriver.WebDriver.mapToExecuteScriptArgument_ = function(arg) {
|
|
692
689
|
webdriver.WebDriver.prototype.executeScript = function(script, var_args) {
|
693
690
|
var args = goog.array.map(
|
694
691
|
goog.array.slice(arguments, 1),
|
695
|
-
webdriver.WebDriver.
|
696
|
-
|
697
|
-
this.addCommand(new webdriver.Command(webdriver.CommandName.EXECUTE_SCRIPT).
|
692
|
+
webdriver.WebDriver.wrapScriptArgument_);
|
693
|
+
return this.addCommand(webdriver.CommandName.EXECUTE_SCRIPT).
|
698
694
|
setParameters(script, args).
|
699
695
|
setSuccessCallback(function(response) {
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
break;
|
704
|
-
|
705
|
-
case 'ELEMENT':
|
706
|
-
var id = response.value;
|
707
|
-
response.value = new webdriver.WebElement(this);
|
708
|
-
response.value.getId().setValue(id);
|
709
|
-
break;
|
710
|
-
|
711
|
-
case 'OTHER': // Fall-through
|
712
|
-
default:
|
713
|
-
break;
|
714
|
-
}
|
715
|
-
result.setValue(response.value);
|
716
|
-
}, this));
|
717
|
-
return result;
|
696
|
+
response.value = this.unwrapScriptResult_(response.value);
|
697
|
+
}, this).
|
698
|
+
getFutureResult();
|
718
699
|
};
|
719
700
|
|
720
701
|
|
@@ -723,11 +704,11 @@ webdriver.WebDriver.prototype.executeScript = function(script, var_args) {
|
|
723
704
|
* @param {goog.Uri|string} url The URL to fetch.
|
724
705
|
*/
|
725
706
|
webdriver.WebDriver.prototype.get = function(url) {
|
726
|
-
this.addCommand(
|
707
|
+
this.addCommand(webdriver.CommandName.GET).
|
727
708
|
setParameters(url.toString()).
|
728
709
|
setSuccessCallback(function(response) {
|
729
710
|
this.context_ = response.context;
|
730
|
-
}, this)
|
711
|
+
}, this);
|
731
712
|
};
|
732
713
|
|
733
714
|
|
@@ -735,7 +716,7 @@ webdriver.WebDriver.prototype.get = function(url) {
|
|
735
716
|
* Navigate backwards in the current browser window's history.
|
736
717
|
*/
|
737
718
|
webdriver.WebDriver.prototype.back = function() {
|
738
|
-
this.addCommand(
|
719
|
+
this.addCommand(webdriver.CommandName.BACK);
|
739
720
|
};
|
740
721
|
|
741
722
|
|
@@ -743,7 +724,7 @@ webdriver.WebDriver.prototype.back = function() {
|
|
743
724
|
* Navigate forwards in the current browser window's history.
|
744
725
|
*/
|
745
726
|
webdriver.WebDriver.prototype.forward = function() {
|
746
|
-
this.addCommand(
|
727
|
+
this.addCommand(webdriver.CommandName.FORWARD);
|
747
728
|
};
|
748
729
|
|
749
730
|
|
@@ -751,7 +732,7 @@ webdriver.WebDriver.prototype.forward = function() {
|
|
751
732
|
* Refresh the current page.
|
752
733
|
*/
|
753
734
|
webdriver.WebDriver.prototype.refresh = function() {
|
754
|
-
this.addCommand(
|
735
|
+
this.addCommand(webdriver.CommandName.REFRESH);
|
755
736
|
};
|
756
737
|
|
757
738
|
|
@@ -760,10 +741,8 @@ webdriver.WebDriver.prototype.refresh = function() {
|
|
760
741
|
* @return {webdriver.Future} The current URL in a webdriver.Future.
|
761
742
|
*/
|
762
743
|
webdriver.WebDriver.prototype.getCurrentUrl = function() {
|
763
|
-
|
764
|
-
|
765
|
-
setSuccessCallback(url.setValueFromResponse, url));
|
766
|
-
return url;
|
744
|
+
return this.addCommand(webdriver.CommandName.GET_CURRENT_URL).
|
745
|
+
getFutureResult();
|
767
746
|
};
|
768
747
|
|
769
748
|
|
@@ -772,10 +751,8 @@ webdriver.WebDriver.prototype.getCurrentUrl = function() {
|
|
772
751
|
* @return {webdriver.Future} The current page title.
|
773
752
|
*/
|
774
753
|
webdriver.WebDriver.prototype.getTitle = function() {
|
775
|
-
|
776
|
-
|
777
|
-
setSuccessCallback(title.setValueFromResponse, title));
|
778
|
-
return title;
|
754
|
+
return this.addCommand(webdriver.CommandName.GET_TITLE).
|
755
|
+
getFutureResult();
|
779
756
|
};
|
780
757
|
|
781
758
|
|
@@ -831,8 +808,8 @@ webdriver.WebDriver.prototype.findElements = function(by) {
|
|
831
808
|
* @param {webdriver.WebDriver.Speed} speed The new speed setting.
|
832
809
|
*/
|
833
810
|
webdriver.WebDriver.prototype.setMouseSpeed = function(speed) {
|
834
|
-
this.addCommand(
|
835
|
-
setParameters(speed)
|
811
|
+
this.addCommand(webdriver.CommandName.SET_MOUSE_SPEED).
|
812
|
+
setParameters(speed);
|
836
813
|
};
|
837
814
|
|
838
815
|
|
@@ -842,12 +819,6 @@ webdriver.WebDriver.prototype.setMouseSpeed = function(speed) {
|
|
842
819
|
* when the query command completes.
|
843
820
|
*/
|
844
821
|
webdriver.WebDriver.prototype.getMouseSpeed = function() {
|
845
|
-
|
846
|
-
|
847
|
-
new webdriver.Command(webdriver.CommandName.GET_MOUSE_SPEED).
|
848
|
-
setSuccessCallback(function(response) {
|
849
|
-
response.value = Number(response.value);
|
850
|
-
speed.setValue(response.value);
|
851
|
-
}));
|
852
|
-
return speed;
|
822
|
+
return this.addCommand(webdriver.CommandName.GET_MOUSE_SPEED).
|
823
|
+
getFutureResult();
|
853
824
|
};
|