selenium-webdriver
Version:
The official WebDriver JavaScript bindings from the Selenium project
1,558 lines (1,351 loc) • 71.2 kB
JavaScript
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
const testutil = require('./testutil');
const By = require('../../lib/by').By;
const Capabilities = require('../../lib/capabilities').Capabilities;
const Executor = require('../../lib/command').Executor;
const CName = require('../../lib/command').Name;
const error = require('../../lib/error');
const Button = require('../../lib/input').Button;
const Key = require('../../lib/input').Key;
const logging = require('../../lib/logging');
const Session = require('../../lib/session').Session;
const promise = require('../../lib/promise');
const {enablePromiseManager, promiseManagerSuite} = require('../../lib/test/promise');
const until = require('../../lib/until');
const Alert = require('../../lib/webdriver').Alert;
const AlertPromise = require('../../lib/webdriver').AlertPromise;
const UnhandledAlertError = require('../../lib/webdriver').UnhandledAlertError;
const WebDriver = require('../../lib/webdriver').WebDriver;
const WebElement = require('../../lib/webdriver').WebElement;
const WebElementPromise = require('../../lib/webdriver').WebElementPromise;
const assert = require('assert');
const sinon = require('sinon');
const SESSION_ID = 'test_session_id';
// Aliases for readability.
const NativePromise = Promise;
const StubError = testutil.StubError;
const assertIsInstance = testutil.assertIsInstance;
const assertIsStubError = testutil.assertIsStubError;
const throwStubError = testutil.throwStubError;
const fail = (msg) => assert.fail(msg);
describe('WebDriver', function() {
const LOG = logging.getLogger('webdriver.test');
// before(function() {
// logging.getLogger('webdriver').setLevel(logging.Level.ALL);
// logging.installConsoleHandler();
// });
// after(function() {
// logging.getLogger('webdriver').setLevel(null);
// logging.removeConsoleHandler();
// });
var driver;
var flow;
var uncaughtExceptions;
beforeEach(function setUp() {
flow = promise.controlFlow();
uncaughtExceptions = [];
flow.on('uncaughtException', onUncaughtException);
});
afterEach(function tearDown() {
if (!promise.USE_PROMISE_MANAGER) {
return;
}
return waitForIdle(flow).then(function() {
assert.deepEqual([], uncaughtExceptions);
flow.reset();
});
});
function onUncaughtException(e) {
uncaughtExceptions.push(e);
}
function defer() {
let d = {};
let promise = new Promise((resolve, reject) => {
Object.assign(d, {resolve, reject});
});
d.promise = promise;
return d;
}
function waitForIdle(opt_flow) {
if (!promise.USE_PROMISE_MANAGER) {
return Promise.resolve();
}
var theFlow = opt_flow || flow;
return new Promise(function(fulfill, reject) {
if (theFlow.isIdle()) {
fulfill();
return;
}
theFlow.once('idle', fulfill);
theFlow.once('uncaughtException', reject);
});
}
function waitForAbort(opt_flow, opt_n) {
var n = opt_n || 1;
var theFlow = opt_flow || flow;
theFlow.removeAllListeners(
promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);
return new Promise(function(fulfill, reject) {
theFlow.once('idle', function() {
reject(Error('expected flow to report an unhandled error'));
});
var errors = [];
theFlow.on('uncaughtException', onError);
function onError(e) {
errors.push(e);
if (errors.length === n) {
theFlow.removeListener('uncaughtException', onError);
fulfill(n === 1 ? errors[0] : errors);
}
}
});
}
function expectedError(ctor, message) {
return function(e) {
assertIsInstance(ctor, e);
assert.equal(message, e.message);
};
}
class Expectation {
constructor(executor, name, opt_parameters) {
this.executor_ = executor;
this.name_ = name;
this.times_ = 1;
this.sessionId_ = SESSION_ID;
this.check_ = null;
this.toDo_ = null;
this.withParameters(opt_parameters || {});
}
anyTimes() {
this.times_ = Infinity;
return this;
}
times(n) {
this.times_ = n;
return this;
}
withParameters(parameters) {
this.parameters_ = parameters;
if (this.name_ !== CName.NEW_SESSION) {
this.parameters_['sessionId'] = this.sessionId_;
}
return this;
}
andReturn(code, opt_value) {
this.toDo_ = function(command) {
LOG.info('executing ' + command.getName() + '; returning ' + code);
return Promise.resolve(opt_value !== void(0) ? opt_value : null);
};
return this;
}
andReturnSuccess(opt_value) {
this.toDo_ = function(command) {
LOG.info('executing ' + command.getName() + '; returning success');
return Promise.resolve(opt_value !== void(0) ? opt_value : null);
};
return this;
}
andReturnError(error) {
if (typeof error === 'number') {
throw Error('need error type');
}
this.toDo_ = function(command) {
LOG.info('executing ' + command.getName() + '; returning failure');
return Promise.reject(error);
};
return this;
}
expect(name, opt_parameters) {
this.end();
return this.executor_.expect(name, opt_parameters);
}
end() {
if (!this.toDo_) {
this.andReturnSuccess(null);
}
return this.executor_;
}
execute(command) {
assert.deepEqual(this.parameters_, command.getParameters());
return this.toDo_(command);
}
}
class FakeExecutor {
constructor() {
this.commands_ = new Map;
}
execute(command) {
let expectations = this.commands_.get(command.getName());
if (!expectations || !expectations.length) {
assert.fail('unexpected command: ' + command.getName());
return;
}
let next = expectations[0];
let result = next.execute(command);
if (next.times_ != Infinity) {
next.times_ -= 1;
if (!next.times_) {
expectations.shift();
}
}
return result;
}
expect(commandName, opt_parameters) {
if (!this.commands_.has(commandName)) {
this.commands_.set(commandName, []);
}
let e = new Expectation(this, commandName, opt_parameters);
this.commands_.get(commandName).push(e);
return e;
}
createDriver(opt_session) {
let session = opt_session || new Session(SESSION_ID, {});
return new WebDriver(session, this);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Tests
//
/////////////////////////////////////////////////////////////////////////////
describe('testAttachToSession', function() {
it('sessionIsAvailable', function() {
let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
let executor = new FakeExecutor().
expect(CName.DESCRIBE_SESSION).
withParameters({'sessionId': SESSION_ID}).
andReturnSuccess(aSession).
end();
let driver = WebDriver.attachToSession(executor, SESSION_ID);
return driver.getSession().then(v => assert.strictEqual(v, aSession));
});
it('failsToGetSessionInfo', function() {
let e = new Error('boom');
let executor = new FakeExecutor().
expect(CName.DESCRIBE_SESSION).
withParameters({'sessionId': SESSION_ID}).
andReturnError(e).
end();
let driver = WebDriver.attachToSession(executor, SESSION_ID);
return driver.getSession()
.then(() => assert.fail('should have failed!'),
(actual) => assert.strictEqual(actual, e));
});
it('remote end does not recognize DESCRIBE_SESSION command', function() {
let e = new error.UnknownCommandError;
let executor = new FakeExecutor().
expect(CName.DESCRIBE_SESSION).
withParameters({'sessionId': SESSION_ID}).
andReturnError(e).
end();
let driver = WebDriver.attachToSession(executor, SESSION_ID);
return driver.getSession().then(session => {
assert.ok(session instanceof Session);
assert.strictEqual(session.getId(), SESSION_ID);
assert.equal(session.getCapabilities().size, 0);
});
});
it('usesActiveFlowByDefault', function() {
let executor = new FakeExecutor().
expect(CName.DESCRIBE_SESSION).
withParameters({'sessionId': SESSION_ID}).
andReturnSuccess({}).
end();
var driver = WebDriver.attachToSession(executor, SESSION_ID);
assert.equal(driver.controlFlow(), promise.controlFlow());
return waitForIdle(driver.controlFlow());
});
enablePromiseManager(() => {
it('canAttachInCustomFlow', function() {
let executor = new FakeExecutor().
expect(CName.DESCRIBE_SESSION).
withParameters({'sessionId': SESSION_ID}).
andReturnSuccess({}).
end();
var otherFlow = new promise.ControlFlow();
var driver = WebDriver.attachToSession(executor, SESSION_ID, otherFlow);
assert.equal(otherFlow, driver.controlFlow());
assert.notEqual(otherFlow, promise.controlFlow());
return waitForIdle(otherFlow);
});
});
});
describe('testCreateSession', function() {
it('happyPathWithCapabilitiesHashObject', function() {
let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
let executor = new FakeExecutor().
expect(CName.NEW_SESSION).
withParameters({
'desiredCapabilities': {'browserName': 'firefox'}
}).
andReturnSuccess(aSession).
end();
var driver = WebDriver.createSession(executor, {
'browserName': 'firefox'
});
return driver.getSession().then(v => assert.strictEqual(v, aSession));
});
it('happyPathWithCapabilitiesInstance', function() {
let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
let executor = new FakeExecutor().
expect(CName.NEW_SESSION).
withParameters({'desiredCapabilities': {'browserName': 'firefox'}}).
andReturnSuccess(aSession).
end();
var driver = WebDriver.createSession(executor, Capabilities.firefox());
return driver.getSession().then(v => assert.strictEqual(v, aSession));
});
it('handles desired and required capabilities', function() {
let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
let executor = new FakeExecutor().
expect(CName.NEW_SESSION).
withParameters({
'desiredCapabilities': {'foo': 'bar'},
'requiredCapabilities': {'bim': 'baz'}
}).
andReturnSuccess(aSession).
end();
let desired = new Capabilities().set('foo', 'bar');
let required = new Capabilities().set('bim', 'baz');
var driver = WebDriver.createSession(executor, {desired, required});
return driver.getSession().then(v => assert.strictEqual(v, aSession));
});
it('failsToCreateSession', function() {
let executor = new FakeExecutor().
expect(CName.NEW_SESSION).
withParameters({'desiredCapabilities': {'browserName': 'firefox'}}).
andReturnError(new StubError()).
end();
var driver =
WebDriver.createSession(executor, {'browserName': 'firefox'});
return driver.getSession().then(fail, assertIsStubError);
});
it('invokes quit callback if it fails to create a session', function() {
let called = false;
let executor = new FakeExecutor()
.expect(CName.NEW_SESSION)
.withParameters({'desiredCapabilities': {'browserName': 'firefox'}})
.andReturnError(new StubError())
.end();
var driver =
WebDriver.createSession(executor, {'browserName': 'firefox'},
null, null, () => called = true);
return driver.getSession().then(fail, err => {
assert.ok(called);
assertIsStubError(err);
});
});
it('usesActiveFlowByDefault', function() {
let executor = new FakeExecutor().
expect(CName.NEW_SESSION).
withParameters({'desiredCapabilities': {}}).
andReturnSuccess(new Session(SESSION_ID)).
end();
var driver = WebDriver.createSession(executor, {});
assert.equal(promise.controlFlow(), driver.controlFlow());
return waitForIdle(driver.controlFlow());
});
enablePromiseManager(() => {
it('canCreateInCustomFlow', function() {
let executor = new FakeExecutor().
expect(CName.NEW_SESSION).
withParameters({'desiredCapabilities': {}}).
andReturnSuccess({}).
end();
var otherFlow = new promise.ControlFlow();
var driver = WebDriver.createSession(executor, {}, otherFlow);
assert.equal(otherFlow, driver.controlFlow());
assert.notEqual(otherFlow, promise.controlFlow());
return waitForIdle(otherFlow);
});
describe('creation failures bubble up in control flow', function() {
function runTest(...args) {
let executor = new FakeExecutor()
.expect(CName.NEW_SESSION)
.withParameters({'desiredCapabilities': {'browserName': 'firefox'}})
.andReturnError(new StubError())
.end();
WebDriver.createSession(
executor, {'browserName': 'firefox'}, ...args);
return waitForAbort().then(assertIsStubError);
}
it('no onQuit callback', () => runTest());
it('has onQuit callback', () => runTest(null, null, function() {}));
it('onQuit callback failure suppress creation failure', function() {
let e = new Error('hi!');
let executor = new FakeExecutor()
.expect(CName.NEW_SESSION)
.withParameters({'desiredCapabilities': {'browserName': 'firefox'}})
.andReturnError(new StubError())
.end();
WebDriver.createSession(
executor, {'browserName': 'firefox'}, null, null,
() => {throw e});
return waitForAbort().then(err => assert.strictEqual(err, e));
});
});
});
});
it('testDoesNotExecuteCommandIfSessionDoesNotResolve', function() {
var session = Promise.reject(new StubError);
return new FakeExecutor().createDriver(session)
.getTitle()
.then(_ => assert.fail('should have failed'), assertIsStubError);
});
it('testCommandReturnValuesArePassedToFirstCallback', function() {
let executor = new FakeExecutor().
expect(CName.GET_TITLE).andReturnSuccess('Google Search').
end();
var driver = executor.createDriver();
return driver.getTitle()
.then(title => assert.equal('Google Search', title));
});
it('testStopsCommandExecutionWhenAnErrorOccurs', function() {
let e = new error.NoSuchWindowError('window not found');
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW).
withParameters({
'name': 'foo',
'handle': 'foo'
}).
andReturnError(e).
end();
let driver = executor.createDriver();
return driver.switchTo().window('foo')
.then(
_ => driver.getTitle(), // mock should blow if this gets executed
v => assert.strictEqual(v, e));
});
it('testCanSuppressCommandFailures', function() {
let e = new error.NoSuchWindowError('window not found');
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW).
withParameters({
'name': 'foo',
'handle': 'foo'
}).
andReturnError(e).
expect(CName.GET_TITLE).
andReturnSuccess('Google Search').
end();
var driver = executor.createDriver();
driver.switchTo().window('foo')
.catch(v => assert.strictEqual(v, e));
driver.getTitle();
return waitForIdle();
});
it('testErrorsPropagateUpToTheRunningApplication', function() {
let e = new error.NoSuchWindowError('window not found');
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW).
withParameters({
'name': 'foo',
'handle': 'foo'
}).
andReturnError(e).
end();
return executor.createDriver()
.switchTo().window('foo')
.then(_ => assert.fail(), v => assert.strictEqual(v, e));
});
it('testErrbacksThatReturnErrorsStillSwitchToCallbackChain', function() {
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW).
withParameters({
'name': 'foo',
'handle': 'foo'
}).
andReturnError(new error.NoSuchWindowError('window not found')).
end();
var driver = executor.createDriver();
return driver.switchTo().window('foo').
catch(function() { return new StubError; });
then(assertIsStubError, () => assert.fail());
});
it('testErrbacksThrownCanOverrideOriginalError', function() {
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW, {
'name': 'foo',
'handle': 'foo'
}).
andReturnError(new error.NoSuchWindowError('window not found')).
end();
var driver = executor.createDriver();
return driver.switchTo().window('foo')
.catch(throwStubError)
.then(assert.fail, assertIsStubError);
});
it('testReportsErrorWhenExecutingCommandsAfterExecutingAQuit', function() {
let executor = new FakeExecutor().
expect(CName.QUIT).
end();
let verifyError = expectedError(
error.NoSuchSessionError,
'This driver instance does not have a valid session ID ' +
'(did you call WebDriver.quit()?) and may no longer be used.');
let driver = executor.createDriver();
return driver.quit()
.then(_ => driver.get('http://www.google.com'))
.then(assert.fail, verifyError);
});
it('testCallbackCommandsExecuteBeforeNextCommand', function() {
let executor = new FakeExecutor().
expect(CName.GET_CURRENT_URL).
expect(CName.GET, {'url': 'http://www.google.com'}).
expect(CName.CLOSE).
expect(CName.GET_TITLE).
end();
var driver = executor.createDriver();
driver.getCurrentUrl().then(function() {
driver.get('http://www.google.com').then(function() {
driver.close();
});
});
driver.getTitle();
return waitForIdle();
});
enablePromiseManager(() => {
it('testEachCallbackFrameRunsToCompletionBeforeTheNext', function() {
let executor = new FakeExecutor().
expect(CName.GET_TITLE).
expect(CName.GET_CURRENT_URL).
expect(CName.GET_CURRENT_WINDOW_HANDLE).
expect(CName.CLOSE).
expect(CName.QUIT).
end();
var driver = executor.createDriver();
driver.getTitle().
// Everything in this callback...
then(function() {
driver.getCurrentUrl();
driver.getWindowHandle();
}).
// ...should execute before everything in this callback.
then(function() {
driver.close();
});
// This should execute after everything above
driver.quit();
return waitForIdle();
});
});
describe('returningAPromise', function() {
it('fromACallback', function() {
let executor = new FakeExecutor().
expect(CName.GET_TITLE).
expect(CName.GET_CURRENT_URL).
andReturnSuccess('http://www.google.com').
end();
var driver = executor.createDriver();
return driver.getTitle().
then(function() {
return driver.getCurrentUrl();
}).
then(function(value) {
assert.equal('http://www.google.com', value);
});
});
it('fromAnErrbackSuppressesTheError', function() {
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW, {
'name': 'foo',
'handle': 'foo'
}).
andReturnError(new StubError()).
expect(CName.GET_CURRENT_URL).
andReturnSuccess('http://www.google.com').
end();
var driver = executor.createDriver();
return driver.switchTo().window('foo').
catch(function(e) {
assertIsStubError(e);
return driver.getCurrentUrl();
}).
then(url => assert.equal('http://www.google.com', url));
});
});
describe('customFunctions', function() {
it('returnsANonPromiseValue', function() {
var driver = new FakeExecutor().createDriver();
return driver.call(() => 'abc123').then(function(value) {
assert.equal('abc123', value);
});
});
enablePromiseManager(() => {
it('executionOrderWithCustomFunctions', function() {
var msg = [];
let executor = new FakeExecutor().
expect(CName.GET_TITLE).andReturnSuccess('cheese ').
expect(CName.GET_CURRENT_URL).andReturnSuccess('tasty').
end();
var driver = executor.createDriver();
var pushMsg = msg.push.bind(msg);
driver.getTitle().then(pushMsg);
driver.call(() => 'is ').then(pushMsg);
driver.getCurrentUrl().then(pushMsg);
driver.call(() => '!').then(pushMsg);
return waitForIdle().then(function() {
assert.equal('cheese is tasty!', msg.join(''));
});
});
});
it('passingArgumentsToACustomFunction', function() {
var add = function(a, b) {
return a + b;
};
var driver = new FakeExecutor().createDriver();
return driver.call(add, null, 1, 2).then(function(value) {
assert.equal(3, value);
});
});
it('passingPromisedArgumentsToACustomFunction', function() {
var promisedArg = Promise.resolve(2);
var add = function(a, b) {
return a + b;
};
var driver = new FakeExecutor().createDriver();
return driver.call(add, null, 1, promisedArg).then(function(value) {
assert.equal(3, value);
});
});
it('passingArgumentsAndScopeToACustomFunction', function() {
function Foo(name) {
this.name = name;
}
Foo.prototype.getName = function() {
return this.name;
};
var foo = new Foo('foo');
var driver = new FakeExecutor().createDriver();
return driver.call(foo.getName, foo).then(function(value) {
assert.equal('foo', value);
});
});
it('customFunctionThrowsAnError', function() {
var driver = new FakeExecutor().createDriver();
return driver.call(throwStubError).then(fail, assertIsStubError);
});
it('customFunctionSchedulesCommands', function() {
let executor = new FakeExecutor().
expect(CName.GET_TITLE).
expect(CName.CLOSE).
expect(CName.QUIT).
end();
var driver = executor.createDriver();
driver.call(function() {
driver.getTitle();
driver.close();
});
driver.quit();
return waitForIdle();
});
it('returnsATaskResultAfterSchedulingAnother', function() {
let executor = new FakeExecutor().
expect(CName.GET_TITLE).
andReturnSuccess('Google Search').
expect(CName.CLOSE).
end();
var driver = executor.createDriver();
return driver.call(function() {
var title = driver.getTitle();
driver.close();
return title;
}).then(function(title) {
assert.equal('Google Search', title);
});
});
it('hasANestedCommandThatFails', function() {
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW, {
'name': 'foo',
'handle': 'foo'
}).
andReturnError(new StubError()).
end();
var driver = executor.createDriver();
return driver.call(function() {
return driver.switchTo().window('foo');
}).then(fail, assertIsStubError);
});
enablePromiseManager(() => {
it('doesNotCompleteUntilReturnedPromiseIsResolved', function() {
var order = [];
var driver = new FakeExecutor().createDriver();
var d = promise.defer();
d.promise.then(function() {
order.push('b');
});
driver.call(function() {
order.push('a');
return d.promise;
});
driver.call(function() {
order.push('c');
});
// timeout to ensure the first function starts its execution before we
// trigger d's callbacks.
return new Promise(f => setTimeout(f, 0)).then(function() {
assert.deepEqual(['a'], order);
d.fulfill();
return waitForIdle().then(function() {
assert.deepEqual(['a', 'b', 'c'], order);
});
});
});
});
it('returnsADeferredAction', function() {
let executor = new FakeExecutor().
expect(CName.GET_TITLE).andReturnSuccess('Google').
end();
var driver = executor.createDriver();
driver.call(function() {
return driver.getTitle();
}).then(function(title) {
assert.equal('Google', title);
});
return waitForIdle();
});
});
describe('nestedCommands', function() {
enablePromiseManager(() => {
it('commandExecutionOrder', function() {
var msg = [];
var driver = new FakeExecutor().createDriver();
driver.call(msg.push, msg, 'a');
driver.call(function() {
driver.call(msg.push, msg, 'c');
driver.call(function() {
driver.call(msg.push, msg, 'e');
driver.call(msg.push, msg, 'f');
});
driver.call(msg.push, msg, 'd');
});
driver.call(msg.push, msg, 'b');
return waitForIdle().then(function() {
assert.equal('acefdb', msg.join(''));
});
});
it('basicUsage', function() {
var msg = [];
var driver = new FakeExecutor().createDriver();
var pushMsg = msg.push.bind(msg);
driver.call(() => 'cheese ').then(pushMsg);
driver.call(function() {
driver.call(() => 'is ').then(pushMsg);
driver.call(() => 'tasty').then(pushMsg);
});
driver.call(() => '!').then(pushMsg);
return waitForIdle().then(function() {
assert.equal('cheese is tasty!', msg.join(''));
});
});
it('normalCommandAfterNestedCommandThatReturnsAnAction', function() {
var msg = [];
let executor = new FakeExecutor().
expect(CName.CLOSE).
end();
var driver = executor.createDriver();
driver.call(function() {
return driver.call(function() {
msg.push('a');
return driver.call(() => 'foobar');
});
});
driver.close().then(function() {
msg.push('b');
});
return waitForIdle().then(function() {
assert.equal('ab', msg.join(''));
});
});
});
it('canReturnValueFromNestedFunction', function() {
var driver = new FakeExecutor().createDriver();
return driver.call(function() {
return driver.call(function() {
return driver.call(() => 'foobar');
});
}).then(function(value) {
assert.equal('foobar', value);
});
});
it('errorsBubbleUp_caught', function() {
var driver = new FakeExecutor().createDriver();
var result = driver.call(function() {
return driver.call(function() {
return driver.call(throwStubError);
});
}).then(fail, assertIsStubError);
return Promise.all([waitForIdle(), result]);
});
it('errorsBubbleUp_uncaught', function() {
var driver = new FakeExecutor().createDriver();
return driver.call(function() {
return driver.call(function() {
return driver.call(throwStubError);
});
})
.then(_ => assert.fail('should have failed'), assertIsStubError);
});
it('canScheduleCommands', function() {
let executor = new FakeExecutor().
expect(CName.GET_TITLE).
expect(CName.CLOSE).
end();
var driver = executor.createDriver();
driver.call(function() {
driver.call(function() {
driver.getTitle();
});
driver.close();
});
return waitForIdle();
});
});
describe('WebElementPromise', function() {
let driver = new FakeExecutor().createDriver();
it('resolvesWhenUnderlyingElementDoes', function() {
let el = new WebElement(driver, {'ELEMENT': 'foo'});
return new WebElementPromise(driver, Promise.resolve(el))
.then(e => assert.strictEqual(e, el));
});
it('resolvesBeforeCallbacksOnWireValueTrigger', function() {
var el = defer();
var element = new WebElementPromise(driver, el.promise);
var messages = [];
let steps = [
element.then(_ => messages.push('element resolved')),
element.getId().then(_ => messages.push('wire value resolved'))
];
el.resolve(new WebElement(driver, {'ELEMENT': 'foo'}));
return Promise.all(steps).then(function() {
assert.deepEqual([
'element resolved',
'wire value resolved'
], messages);
});
});
it('isRejectedIfUnderlyingIdIsRejected', function() {
let element =
new WebElementPromise(driver, Promise.reject(new StubError));
return element.then(fail, assertIsStubError);
});
});
describe('executeScript', function() {
it('nullReturnValue', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return document.body;',
'args': []
}).
andReturnSuccess(null).
end();
var driver = executor.createDriver();
return driver.executeScript('return document.body;')
.then((result) => assert.equal(null, result));
});
it('primitiveReturnValue', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return document.body;',
'args': []
}).
andReturnSuccess(123).
end();
var driver = executor.createDriver();
return driver.executeScript('return document.body;')
.then((result) => assert.equal(123, result));
});
it('webElementReturnValue', function() {
var json = WebElement.buildId('foo');
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return document.body;',
'args': []
}).
andReturnSuccess(json).
end();
var driver = executor.createDriver();
return driver.executeScript('return document.body;')
.then((element) => element.getId())
.then((id) => assert.equal(id, 'foo'));
});
it('arrayReturnValue', function() {
var json = [WebElement.buildId('foo')];
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return document.body;',
'args': []
}).
andReturnSuccess(json).
end();
var driver = executor.createDriver();
return driver.executeScript('return document.body;')
.then(function(array) {
assert.equal(1, array.length);
return array[0].getId();
})
.then((id) => assert.equal('foo', id));
});
it('objectReturnValue', function() {
var json = {'foo': WebElement.buildId('foo')};
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return document.body;',
'args': []
}).
andReturnSuccess(json).
end();
var driver = executor.createDriver();
var callback;
return driver.executeScript('return document.body;')
.then((obj) => obj['foo'].getId())
.then((id) => assert.equal(id, 'foo'));
});
it('scriptAsFunction', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return (' + function() {} +
').apply(null, arguments);',
'args': []
}).
andReturnSuccess(null).
end();
var driver = executor.createDriver();
return driver.executeScript(function() {});
});
it('simpleArgumentConversion', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return 1;',
'args': ['abc', 123, true, [123, {'foo': 'bar'}]]
}).
andReturnSuccess(null).
end();
var driver = executor.createDriver();
return driver.executeScript(
'return 1;', 'abc', 123, true, [123, {'foo': 'bar'}]);
});
it('webElementArgumentConversion', function() {
var elementJson = WebElement.buildId('fefifofum');
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return 1;',
'args': [elementJson]
}).
andReturnSuccess(null).
end();
var driver = executor.createDriver();
return driver.executeScript('return 1;',
new WebElement(driver, 'fefifofum'));
});
it('webElementPromiseArgumentConversion', function() {
var elementJson = WebElement.buildId('bar');
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENT,
{'using': 'css selector', 'value': '*[id="foo"]'}).
andReturnSuccess(elementJson).
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return 1;',
'args': [elementJson]
}).
andReturnSuccess(null).
end();
var driver = executor.createDriver();
var element = driver.findElement(By.id('foo'));
return driver.executeScript('return 1;', element);
});
it('argumentConversion', function() {
var elementJson = WebElement.buildId('fefifofum');
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'return 1;',
'args': ['abc', 123, true, elementJson, [123, {'foo': 'bar'}]]
}).
andReturnSuccess(null).
end();
var driver = executor.createDriver();
var element = new WebElement(driver, 'fefifofum');
return driver.executeScript('return 1;',
'abc', 123, true, element, [123, {'foo': 'bar'}]);
});
it('scriptReturnsAnError', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT).
withParameters({
'script': 'throw Error(arguments[0]);',
'args': ['bam']
}).
andReturnError(new StubError).
end();
var driver = executor.createDriver();
return driver.executeScript('throw Error(arguments[0]);', 'bam').
then(fail, assertIsStubError);
});
it('failsIfArgumentIsARejectedPromise', function() {
let executor = new FakeExecutor();
var arg = Promise.reject(new StubError);
arg.catch(function() {}); // Suppress default handler.
var driver = executor.createDriver();
return driver.executeScript(function() {}, arg).
then(fail, assertIsStubError);
});
});
describe('executeAsyncScript', function() {
it('failsIfArgumentIsARejectedPromise', function() {
var arg = Promise.reject(new StubError);
arg.catch(function() {}); // Suppress default handler.
var driver = new FakeExecutor().createDriver();
return driver.executeAsyncScript(function() {}, arg).
then(fail, assertIsStubError);
});
});
describe('findElement', function() {
it('elementNotFound', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENT,
{using: 'css selector', value: '*[id="foo"]'}).
andReturnError(new StubError).
end();
var driver = executor.createDriver();
return driver.findElement(By.id('foo'))
.then(assert.fail, assertIsStubError);
});
it('elementNotFoundInACallback', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENT,
{using: 'css selector', value: '*[id="foo"]'}).
andReturnError(new StubError).
end();
var driver = executor.createDriver();
return Promise.resolve()
.then(_ => driver.findElement(By.id('foo')))
.then(assert.fail, assertIsStubError);
});
it('elementFound', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENT,
{using: 'css selector', value: '*[id="foo"]'}).
andReturnSuccess(WebElement.buildId('bar')).
expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('bar')}).
andReturnSuccess().
end();
var driver = executor.createDriver();
var element = driver.findElement(By.id('foo'));
element.click();
return waitForIdle();
});
it('canUseElementInCallback', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENT,
{using: 'css selector', value: '*[id="foo"]'}).
andReturnSuccess(WebElement.buildId('bar')).
expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('bar')}).
andReturnSuccess().
end();
var driver = executor.createDriver();
driver.findElement(By.id('foo')).then(function(element) {
element.click();
});
return waitForIdle();
});
it('byJs', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT, {
'script': 'return document.body',
'args': []
}).
andReturnSuccess(WebElement.buildId('bar')).
expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('bar')}).
end();
var driver = executor.createDriver();
var element = driver.findElement(By.js('return document.body'));
element.click(); // just to make sure
return waitForIdle();
});
it('byJs_returnsNonWebElementValue', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT, {'script': 'return 123', 'args': []}).
andReturnSuccess(123).
end();
var driver = executor.createDriver();
return driver.findElement(By.js('return 123'))
.then(assert.fail, function(e) {
assertIsInstance(TypeError, e);
assert.equal(
'Custom locator did not return a WebElement', e.message);
});
});
it('byJs_canPassArguments', function() {
var script = 'return document.getElementsByTagName(arguments[0]);';
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT, {
'script': script,
'args': ['div']
}).
andReturnSuccess(WebElement.buildId('one')).
end();
var driver = executor.createDriver();
driver.findElement(By.js(script, 'div'));
return waitForIdle();
});
it('customLocator', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENTS, {'using': 'css selector', 'value': 'a'}).
andReturnSuccess([
WebElement.buildId('foo'),
WebElement.buildId('bar')]).
expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('foo')}).
andReturnSuccess().
end();
var driver = executor.createDriver();
var element = driver.findElement(function(d) {
assert.equal(driver, d);
return d.findElements(By.tagName('a'));
});
return element.click();
});
it('customLocatorThrowsIfresultIsNotAWebElement', function() {
var driver = new FakeExecutor().createDriver();
return driver.findElement(_ => 1)
.then(assert.fail, function(e) {
assertIsInstance(TypeError, e);
assert.equal(
'Custom locator did not return a WebElement', e.message);
});
});
});
describe('findElements', function() {
it('returnsMultipleElements', function() {
var ids = ['foo', 'bar', 'baz'];
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENTS, {'using':'css selector', 'value':'a'}).
andReturnSuccess(ids.map(WebElement.buildId)).
end();
var driver = executor.createDriver();
return driver.findElements(By.tagName('a'))
.then(function(elements) {
return promise.all(elements.map(function(e) {
assert.ok(e instanceof WebElement);
return e.getId();
}));
})
.then((actual) => assert.deepEqual(ids, actual));
});
it('byJs', function() {
var ids = ['foo', 'bar', 'baz'];
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT, {
'script': 'return document.getElementsByTagName("div");',
'args': []
}).
andReturnSuccess(ids.map(WebElement.buildId)).
end();
var driver = executor.createDriver();
return driver.
findElements(By.js('return document.getElementsByTagName("div");')).
then(function(elements) {
return promise.all(elements.map(function(e) {
assert.ok(e instanceof WebElement);
return e.getId();
}));
}).
then((actual) => assert.deepEqual(ids, actual));
});
it('byJs_filtersOutNonWebElementResponses', function() {
var ids = ['foo', 'bar', 'baz'];
var json = [
WebElement.buildId(ids[0]),
123,
'a',
false,
WebElement.buildId(ids[1]),
{'not a web element': 1},
WebElement.buildId(ids[2])
];
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT, {
'script': 'return document.getElementsByTagName("div");',
'args': []
}).
andReturnSuccess(json).
end();
var driver = executor.createDriver();
driver.findElements(By.js('return document.getElementsByTagName("div");')).
then(function(elements) {
return promise.all(elements.map(function(e) {
assert.ok(e instanceof WebElement);
return e.getId();
}));
}).
then((actual) => assert.deepEqual(ids, actual));
return waitForIdle();
});
it('byJs_convertsSingleWebElementResponseToArray', function() {
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT, {
'script': 'return document.getElementsByTagName("div");',
'args': []
}).
andReturnSuccess(WebElement.buildId('foo')).
end();
var driver = executor.createDriver();
return driver.
findElements(By.js('return document.getElementsByTagName("div");')).
then(function(elements) {
return promise.all(elements.map(function(e) {
assert.ok(e instanceof WebElement);
return e.getId();
}));
}).
then((actual) => assert.deepEqual(['foo'], actual));
});
it('byJs_canPassScriptArguments', function() {
var script = 'return document.getElementsByTagName(arguments[0]);';
let executor = new FakeExecutor().
expect(CName.EXECUTE_SCRIPT, {
'script': script,
'args': ['div']
}).
andReturnSuccess([
WebElement.buildId('one'),
WebElement.buildId('two')
]).
end();
var driver = executor.createDriver();
return driver.findElements(By.js(script, 'div'))
then(function(elements) {
return promise.all(elements.map(function(e) {
assert.ok(e instanceof WebElement);
return e.getId();
}));
}).
then((actual) => assert.deepEqual(['one', 'two'], actual));
});
});
describe('sendKeys', function() {
it('convertsVarArgsIntoStrings_simpleArgs', function() {
let executor = new FakeExecutor().
expect(CName.SEND_KEYS_TO_ELEMENT,
{'id': WebElement.buildId('one'),
'value':'12abc3'.split('')}).
andReturnSuccess().
end();
var driver = executor.createDriver();
var element = new WebElement(driver, 'one');
element.sendKeys(1, 2, 'abc', 3);
return waitForIdle();
});
it('convertsVarArgsIntoStrings_promisedArgs', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENT,
{'using':'css selector', 'value':'*[id="foo"]'}).
andReturnSuccess(WebElement.buildId('one')).
expect(CName.SEND_KEYS_TO_ELEMENT,
{'id':WebElement.buildId('one'),
'value':'abc123def'.split('')}).
andReturnSuccess().
end();
var driver = executor.createDriver();
var element = driver.findElement(By.id('foo'));
return element.sendKeys(
Promise.resolve('abc'),
123,
Promise.resolve('def'));
});
it('sendKeysWithAFileDetector', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENT,
{'using':'css selector', 'value':'*[id="foo"]'}).
andReturnSuccess(WebElement.buildId('one')).
expect(CName.SEND_KEYS_TO_ELEMENT,
{'id': WebElement.buildId('one'),
'value':'modified/path'.split('')}).
andReturnSuccess().
end();
let driver = executor.createDriver();
let handleFile = function(d, path) {
assert.strictEqual(driver, d);
assert.equal(path, 'original/path');
return Promise.resolve('modified/path');
};
driver.setFileDetector({handleFile});
return driver.findElement(By.id('foo')).sendKeys('original/', 'path');
});
});
describe("switchTo()", function() {
describe("window", function() {
it('should return a resolved promise when the window is found', function() {
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW).
withParameters({
'name': 'foo',
'handle': 'foo'
}).
andReturnSuccess().
end();
executor.createDriver().switchTo().window('foo');
return waitForIdle();
});
it('should propagate exceptions', function() {
let e = new error.NoSuchWindowError('window not found');
let executor = new FakeExecutor().
expect(CName.SWITCH_TO_WINDOW).
withParameters({
'name': 'foo',
'handle': 'foo'
}).
andReturnError(e).
end();
return executor.createDriver()
.switchTo().window('foo')
.then(assert.fail, v => assert.strictEqual(v, e));
});
});
});
describe('elementEquality', function() {
it('isReflexive', function() {
var a = new WebElement(new FakeExecutor().createDriver(), 'foo');
return WebElement.equals(a, a).then(assert.ok);
});
it('failsIfAnInputElementCouldNotBeFound', function() {
let id = Promise.reject(new StubError);
var driver = new FakeExecutor().createDriver();
var a = new WebElement(driver, 'foo');
var b = new WebElementPromise(driver, id);
return WebElement.equals(a, b).then(fail, assertIsStubError);
});
});
describe('waiting', function() {
describe('supports custom wait functions', function() {
it('waitSucceeds', function() {
let executor = new FakeExecutor().
expect(CName.FIND_ELEMENTS,
{using: 'css selector', value: '*[id="foo"]'}).
andRe