2312 lines
73 KiB
JavaScript
2312 lines
73 KiB
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, () => 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, () => {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'),
|
||
|
'text': '12abc3',
|
||
|
'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'),
|
||
|
'text': 'abc123def',
|
||
|
'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'),
|
||
|
'text': 'modified/path',
|
||
|
'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"]'}).
|
||
|
andReturnSuccess([]).
|
||
|
times(2).
|
||
|
expect(CName.FIND_ELEMENTS,
|
||
|
{using: 'css selector', value: '*[id="foo"]'}).
|
||
|
andReturnSuccess([WebElement.buildId('bar')]).
|
||
|
end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
driver.wait(function() {
|
||
|
return driver.findElements(By.id('foo')).then(els => els.length > 0);
|
||
|
}, 200);
|
||
|
return waitForIdle();
|
||
|
});
|
||
|
|
||
|
it('waitTimesout_timeoutCaught', function() {
|
||
|
let executor = new FakeExecutor().
|
||
|
expect(CName.FIND_ELEMENTS,
|
||
|
{using: 'css selector', value: '*[id="foo"]'}).
|
||
|
andReturnSuccess([]).
|
||
|
anyTimes().
|
||
|
end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
return driver.wait(function() {
|
||
|
return driver.findElements(By.id('foo')).then(els => els.length > 0);
|
||
|
}, 25).then(fail, function(e) {
|
||
|
assert.equal('Wait timed out after ',
|
||
|
e.message.substring(0, 'Wait timed out after '.length));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
enablePromiseManager(() => {
|
||
|
it('waitTimesout_timeoutNotCaught', function() {
|
||
|
let executor = new FakeExecutor().
|
||
|
expect(CName.FIND_ELEMENTS,
|
||
|
{using: 'css selector', value: '*[id="foo"]'}).
|
||
|
andReturnSuccess([]).
|
||
|
anyTimes().
|
||
|
end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
driver.wait(function() {
|
||
|
return driver.findElements(By.id('foo')).then(els => els.length > 0);
|
||
|
}, 25);
|
||
|
return waitForAbort().then(function(e) {
|
||
|
assert.equal('Wait timed out after ',
|
||
|
e.message.substring(0, 'Wait timed out after '.length));
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('supports condition objects', function() {
|
||
|
it('wait succeeds', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.FIND_ELEMENTS,
|
||
|
{using: 'css selector', value: '*[id="foo"]'})
|
||
|
.andReturnSuccess([])
|
||
|
.times(2)
|
||
|
.expect(CName.FIND_ELEMENTS,
|
||
|
{using: 'css selector', value: '*[id="foo"]'})
|
||
|
.andReturnSuccess([WebElement.buildId('bar')])
|
||
|
.end();
|
||
|
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.wait(until.elementLocated(By.id('foo')), 200);
|
||
|
});
|
||
|
|
||
|
it('wait times out', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.FIND_ELEMENTS,
|
||
|
{using: 'css selector', value: '*[id="foo"]'})
|
||
|
.andReturnSuccess([])
|
||
|
.anyTimes()
|
||
|
.end();
|
||
|
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.wait(until.elementLocated(By.id('foo')), 5)
|
||
|
.then(fail, err => assert.ok(err instanceof error.TimeoutError));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('supports promise objects', function() {
|
||
|
it('wait succeeds', function() {
|
||
|
let promise = new Promise(resolve => {
|
||
|
setTimeout(() => resolve(1), 10);
|
||
|
});
|
||
|
|
||
|
let driver = new FakeExecutor().createDriver();
|
||
|
return driver.wait(promise, 200).then(v => assert.equal(v, 1));
|
||
|
});
|
||
|
|
||
|
it('wait times out', function() {
|
||
|
let promise = new Promise(resolve => {/* never resolves */});
|
||
|
|
||
|
let driver = new FakeExecutor().createDriver();
|
||
|
return driver.wait(promise, 5)
|
||
|
.then(fail, err => assert.ok(err instanceof error.TimeoutError));
|
||
|
});
|
||
|
|
||
|
it('wait fails if promise is rejected', function() {
|
||
|
let err = Error('boom');
|
||
|
let driver = new FakeExecutor().createDriver();
|
||
|
return driver.wait(Promise.reject(err), 5)
|
||
|
.then(fail, e => assert.strictEqual(e, err));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('fails if not supported condition type provided', function() {
|
||
|
let driver = new FakeExecutor().createDriver();
|
||
|
assert.throws(() => driver.wait({}, 5), TypeError);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('alert handling', function() {
|
||
|
it('alertResolvesWhenPromisedTextResolves', function() {
|
||
|
let driver = new FakeExecutor().createDriver();
|
||
|
let deferredText = defer();
|
||
|
|
||
|
let alert = new AlertPromise(driver, deferredText.promise);
|
||
|
|
||
|
deferredText.resolve(new Alert(driver, 'foo'));
|
||
|
return alert.getText().then(text => assert.equal(text, 'foo'));
|
||
|
});
|
||
|
|
||
|
it('cannotSwitchToAlertThatIsNotPresent', function() {
|
||
|
let e = new error.NoSuchAlertError;
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.GET_ALERT_TEXT)
|
||
|
.andReturnError(e)
|
||
|
.end();
|
||
|
|
||
|
return executor.createDriver()
|
||
|
.switchTo().alert()
|
||
|
.then(assert.fail, v => assert.strictEqual(v, e));
|
||
|
});
|
||
|
|
||
|
enablePromiseManager(() => {
|
||
|
it('alertsBelongToSameFlowAsParentDriver', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.GET_ALERT_TEXT).andReturnSuccess('hello')
|
||
|
.end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
var otherFlow = new promise.ControlFlow();
|
||
|
otherFlow.execute(function() {
|
||
|
driver.switchTo().alert().then(function() {
|
||
|
assert.strictEqual(
|
||
|
driver.controlFlow(), promise.controlFlow(),
|
||
|
'Alert should belong to the same flow as its parent driver');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
assert.notEqual(otherFlow, driver.controlFlow);
|
||
|
return Promise.all([
|
||
|
waitForIdle(otherFlow),
|
||
|
waitForIdle(driver.controlFlow())
|
||
|
]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('commandsFailIfAlertNotPresent', function() {
|
||
|
let e = new error.NoSuchAlertError;
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.GET_ALERT_TEXT)
|
||
|
.andReturnError(e)
|
||
|
.end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
var alert = driver.switchTo().alert();
|
||
|
|
||
|
var expectError = (v) => assert.strictEqual(v, e);
|
||
|
|
||
|
return alert.getText()
|
||
|
.then(fail, expectedError)
|
||
|
.then(() => alert.accept())
|
||
|
.then(fail, expectedError)
|
||
|
.then(() => alert.dismiss())
|
||
|
.then(fail, expectError)
|
||
|
.then(() => alert.sendKeys('hi'))
|
||
|
.then(fail, expectError);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
enablePromiseManager(() => {
|
||
|
it('testWebElementsBelongToSameFlowAsParentDriver', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.FIND_ELEMENT,
|
||
|
{using: 'css selector', value: '*[id="foo"]'})
|
||
|
.andReturnSuccess(WebElement.buildId('abc123'))
|
||
|
.end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
var otherFlow = new promise.ControlFlow();
|
||
|
otherFlow.execute(function() {
|
||
|
driver.findElement({id: 'foo'}).then(function() {
|
||
|
assert.equal(driver.controlFlow(), promise.controlFlow());
|
||
|
});
|
||
|
});
|
||
|
|
||
|
assert.notEqual(otherFlow, driver.controlFlow);
|
||
|
return Promise.all([
|
||
|
waitForIdle(otherFlow),
|
||
|
waitForIdle(driver.controlFlow())
|
||
|
]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('testFetchingLogs', function() {
|
||
|
let executor = new FakeExecutor().
|
||
|
expect(CName.GET_LOG, {'type': 'browser'}).
|
||
|
andReturnSuccess([
|
||
|
{'level': 'INFO', 'message': 'hello', 'timestamp': 1234},
|
||
|
{'level': 'DEBUG', 'message': 'abc123', 'timestamp': 5678}
|
||
|
]).
|
||
|
end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
return driver.manage().logs().get('browser').then(function(entries) {
|
||
|
assert.equal(2, entries.length);
|
||
|
|
||
|
assert.ok(entries[0] instanceof logging.Entry);
|
||
|
assert.equal(logging.Level.INFO.value, entries[0].level.value);
|
||
|
assert.equal('hello', entries[0].message);
|
||
|
assert.equal(1234, entries[0].timestamp);
|
||
|
|
||
|
assert.ok(entries[1] instanceof logging.Entry);
|
||
|
assert.equal(logging.Level.DEBUG.value, entries[1].level.value);
|
||
|
assert.equal('abc123', entries[1].message);
|
||
|
assert.equal(5678, entries[1].timestamp);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('testCommandsFailIfInitialSessionCreationFailed', function() {
|
||
|
var session = Promise.reject(new StubError);
|
||
|
|
||
|
var driver = new FakeExecutor().createDriver(session);
|
||
|
var navigateResult = driver.get('some-url').then(fail, assertIsStubError);
|
||
|
var quitResult = driver.quit().then(fail, assertIsStubError);
|
||
|
|
||
|
return waitForIdle().then(function() {
|
||
|
return promise.all(navigateResult, quitResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('testWebElementCommandsFailIfInitialDriverCreationFailed', function() {
|
||
|
var session = Promise.reject(new StubError);
|
||
|
var driver = new FakeExecutor().createDriver(session);
|
||
|
return driver.findElement(By.id('foo')).click().
|
||
|
then(fail, assertIsStubError);
|
||
|
});
|
||
|
|
||
|
it('testWebElementCommansFailIfElementCouldNotBeFound', function() {
|
||
|
let e = new error.NoSuchElementError('Unable to find element');
|
||
|
let executor = new FakeExecutor().
|
||
|
expect(CName.FIND_ELEMENT,
|
||
|
{using: 'css selector', value: '*[id="foo"]'}).
|
||
|
andReturnError(e).
|
||
|
end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
return driver.findElement(By.id('foo')).click()
|
||
|
.then(fail, v => assert.strictEqual(v, e));
|
||
|
});
|
||
|
|
||
|
it('testCannotFindChildElementsIfParentCouldNotBeFound', function() {
|
||
|
let e = new error.NoSuchElementError('Unable to find element');
|
||
|
let executor = new FakeExecutor().
|
||
|
expect(CName.FIND_ELEMENT,
|
||
|
{using: 'css selector', value: '*[id="foo"]'}).
|
||
|
andReturnError(e).
|
||
|
end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
return driver.findElement(By.id('foo'))
|
||
|
.findElement(By.id('bar'))
|
||
|
.findElement(By.id('baz'))
|
||
|
.then(fail, v => assert.strictEqual(v, e));
|
||
|
});
|
||
|
|
||
|
describe('actions()', function() {
|
||
|
it('failsIfInitialDriverCreationFailed', function() {
|
||
|
let session = Promise.reject(new StubError('no session for you'));
|
||
|
let driver = new FakeExecutor().createDriver(session);
|
||
|
driver.getSession().catch(function() {});
|
||
|
return driver.
|
||
|
actions().
|
||
|
mouseDown().
|
||
|
mouseUp().
|
||
|
perform().
|
||
|
catch(assertIsStubError);
|
||
|
});
|
||
|
|
||
|
describe('mouseMove', function() {
|
||
|
it('noElement', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.MOVE_TO, {'xoffset': 0, 'yoffset': 125})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
|
||
|
return executor.createDriver().
|
||
|
actions().
|
||
|
mouseMove({x: 0, y: 125}).
|
||
|
perform();
|
||
|
});
|
||
|
|
||
|
it('element', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.FIND_ELEMENT,
|
||
|
{using: 'css selector', value: '*[id="foo"]'})
|
||
|
.andReturnSuccess(WebElement.buildId('abc123'))
|
||
|
.expect(CName.MOVE_TO,
|
||
|
{'element': 'abc123', 'xoffset': 0, 'yoffset': 125})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
var element = driver.findElement(By.id('foo'));
|
||
|
return driver.actions()
|
||
|
.mouseMove(element, {x: 0, y: 125})
|
||
|
.perform();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('supportsMouseDown', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.MOUSE_DOWN, {'button': Button.LEFT})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
|
||
|
return executor.createDriver().
|
||
|
actions().
|
||
|
mouseDown().
|
||
|
perform();
|
||
|
});
|
||
|
|
||
|
it('testActionSequence', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.FIND_ELEMENT,
|
||
|
{using: 'css selector', value: '*[id="a"]'})
|
||
|
.andReturnSuccess(WebElement.buildId('id1'))
|
||
|
.expect(CName.FIND_ELEMENT,
|
||
|
{using: 'css selector', value: '*[id="b"]'})
|
||
|
.andReturnSuccess(WebElement.buildId('id2'))
|
||
|
.expect(CName.SEND_KEYS_TO_ACTIVE_ELEMENT,
|
||
|
{'value': [Key.SHIFT]})
|
||
|
.andReturnSuccess()
|
||
|
.expect(CName.MOVE_TO, {'element': 'id1'})
|
||
|
.andReturnSuccess()
|
||
|
.expect(CName.CLICK, {'button': Button.LEFT})
|
||
|
.andReturnSuccess()
|
||
|
.expect(CName.MOVE_TO, {'element': 'id2'})
|
||
|
.andReturnSuccess()
|
||
|
.expect(CName.CLICK, {'button': Button.LEFT})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
var element1 = driver.findElement(By.id('a'));
|
||
|
var element2 = driver.findElement(By.id('b'));
|
||
|
|
||
|
return driver.actions()
|
||
|
.keyDown(Key.SHIFT)
|
||
|
.click(element1)
|
||
|
.click(element2)
|
||
|
.perform();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('touchActions()', function() {
|
||
|
it('failsIfInitialDriverCreationFailed', function() {
|
||
|
let session = Promise.reject(new StubError);
|
||
|
let driver = new FakeExecutor().createDriver(session);
|
||
|
driver.getSession().catch(function() {});
|
||
|
return driver.
|
||
|
touchActions().
|
||
|
scroll({x: 3, y: 4}).
|
||
|
perform().
|
||
|
catch(assertIsStubError);
|
||
|
});
|
||
|
|
||
|
it('testTouchActionSequence', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.TOUCH_DOWN, {x: 1, y: 2}).andReturnSuccess()
|
||
|
.expect(CName.TOUCH_MOVE, {x: 3, y: 4}).andReturnSuccess()
|
||
|
.expect(CName.TOUCH_UP, {x: 5, y: 6}).andReturnSuccess()
|
||
|
.end();
|
||
|
|
||
|
var driver = executor.createDriver();
|
||
|
return driver.touchActions()
|
||
|
.tapAndHold({x: 1, y: 2})
|
||
|
.move({x: 3, y: 4})
|
||
|
.release({x: 5, y: 6})
|
||
|
.perform();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('manage()', function() {
|
||
|
describe('setTimeouts()', function() {
|
||
|
describe('throws if no timeouts are specified', function() {
|
||
|
let driver;
|
||
|
before(() => driver = new FakeExecutor().createDriver());
|
||
|
|
||
|
it('; no arguments', function() {
|
||
|
assert.throws(() => driver.manage().setTimeouts(), TypeError);
|
||
|
});
|
||
|
|
||
|
it('; ignores unrecognized timeout keys', function() {
|
||
|
assert.throws(
|
||
|
() => driver.manage().setTimeouts({foo: 123}), TypeError);
|
||
|
});
|
||
|
|
||
|
it('; ignores positional arguments', function() {
|
||
|
assert.throws(
|
||
|
() => driver.manage().setTimeouts(1234, 56), TypeError);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('throws timeout is not a number, null, or undefined', () => {
|
||
|
let driver;
|
||
|
before(() => driver = new FakeExecutor().createDriver());
|
||
|
|
||
|
function checkError(e) {
|
||
|
return e instanceof TypeError
|
||
|
&& /expected "(script|pageLoad|implicit)" to be a number/.test(
|
||
|
e.message);
|
||
|
}
|
||
|
|
||
|
it('script', function() {
|
||
|
assert.throws(
|
||
|
() => driver.manage().setTimeouts({script: 'abc'}),
|
||
|
checkError);
|
||
|
});
|
||
|
|
||
|
it('pageLoad', function() {
|
||
|
assert.throws(
|
||
|
() => driver.manage().setTimeouts({pageLoad: 'abc'}),
|
||
|
checkError);
|
||
|
});
|
||
|
|
||
|
it('implicit', function() {
|
||
|
assert.throws(
|
||
|
() => driver.manage().setTimeouts({implicit: 'abc'}),
|
||
|
checkError);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('can set multiple timeouts', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.SET_TIMEOUT, {script:1, pageLoad: 2, implicit: 3})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.manage()
|
||
|
.setTimeouts({script: 1, pageLoad: 2, implicit: 3});
|
||
|
});
|
||
|
|
||
|
it('falls back to legacy wire format if W3C version fails', () => {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.SET_TIMEOUT, {implicit: 3})
|
||
|
.andReturnError(Error('oops'))
|
||
|
.expect(CName.SET_TIMEOUT, {type: 'implicit', ms: 3})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.manage().setTimeouts({implicit: 3});
|
||
|
});
|
||
|
|
||
|
describe('deprecated API calls setTimeouts()', function() {
|
||
|
it('implicitlyWait()', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.SET_TIMEOUT, {implicit: 3})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.manage().timeouts().implicitlyWait(3);
|
||
|
});
|
||
|
|
||
|
it('setScriptTimeout()', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.SET_TIMEOUT, {script: 3})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.manage().timeouts().setScriptTimeout(3);
|
||
|
});
|
||
|
|
||
|
it('pageLoadTimeout()', function() {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.SET_TIMEOUT, {pageLoad: 3})
|
||
|
.andReturnSuccess()
|
||
|
.end();
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.manage().timeouts().pageLoadTimeout(3);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('generator support', function() {
|
||
|
var driver;
|
||
|
|
||
|
beforeEach(function() {
|
||
|
driver = new WebDriver(
|
||
|
new Session('test-session', {}),
|
||
|
new ExplodingExecutor());
|
||
|
});
|
||
|
|
||
|
it('canUseGeneratorsWithWebDriverCall', function() {
|
||
|
return driver.call(function* () {
|
||
|
var x = yield Promise.resolve(1);
|
||
|
var y = yield Promise.resolve(2);
|
||
|
return x + y;
|
||
|
}).then(function(value) {
|
||
|
assert.deepEqual(3, value);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('canDefineScopeOnGeneratorCall', function() {
|
||
|
return driver.call(function* () {
|
||
|
var x = yield Promise.resolve(1);
|
||
|
return this.name + x;
|
||
|
}, {name: 'Bob'}).then(function(value) {
|
||
|
assert.deepEqual('Bob1', value);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('canSpecifyArgsOnGeneratorCall', function() {
|
||
|
return driver.call(function* (a, b) {
|
||
|
var x = yield Promise.resolve(1);
|
||
|
var y = yield Promise.resolve(2);
|
||
|
return [x + y, a, b];
|
||
|
}, null, 'abc', 123).then(function(value) {
|
||
|
assert.deepEqual([3, 'abc', 123], value);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('canUseGeneratorWithWebDriverWait', function() {
|
||
|
var values = [];
|
||
|
return driver.wait(function* () {
|
||
|
yield values.push(1);
|
||
|
values.push(yield promise.delayed(10).then(function() {
|
||
|
return 2;
|
||
|
}));
|
||
|
yield values.push(3);
|
||
|
return values.length === 6;
|
||
|
}, 250).then(function() {
|
||
|
assert.deepEqual([1, 2, 3, 1, 2, 3], values);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* @constructor
|
||
|
* @implements {CommandExecutor}
|
||
|
*/
|
||
|
function ExplodingExecutor() {}
|
||
|
|
||
|
|
||
|
/** @override */
|
||
|
ExplodingExecutor.prototype.execute = function(command, cb) {
|
||
|
cb(Error('Unsupported operation'));
|
||
|
};
|
||
|
});
|
||
|
|
||
|
describe('wire format', function() {
|
||
|
const FAKE_DRIVER = new FakeExecutor().createDriver();
|
||
|
|
||
|
describe('can serialize', function() {
|
||
|
function runSerializeTest(input, want) {
|
||
|
let executor = new FakeExecutor().
|
||
|
expect(CName.NEW_SESSION).
|
||
|
withParameters({'desiredCapabilities': want}).
|
||
|
andReturnSuccess({'browserName': 'firefox'}).
|
||
|
end();
|
||
|
return WebDriver.createSession(executor, input)
|
||
|
.getSession();
|
||
|
}
|
||
|
|
||
|
it('function as a string', function() {
|
||
|
function foo() { return 'foo'; }
|
||
|
return runSerializeTest(foo, '' + foo);
|
||
|
});
|
||
|
|
||
|
it('object with toJSON()', function() {
|
||
|
return runSerializeTest(
|
||
|
new Date(605728511546),
|
||
|
'1989-03-12T17:55:11.546Z');
|
||
|
});
|
||
|
|
||
|
it('Session', function() {
|
||
|
return runSerializeTest(new Session('foo', {}), 'foo');
|
||
|
});
|
||
|
|
||
|
it('Capabilities', function() {
|
||
|
var prefs = new logging.Preferences();
|
||
|
prefs.setLevel(logging.Type.BROWSER, logging.Level.DEBUG);
|
||
|
|
||
|
var caps = Capabilities.chrome();
|
||
|
caps.setLoggingPrefs(prefs);
|
||
|
|
||
|
return runSerializeTest(
|
||
|
caps,
|
||
|
{
|
||
|
'browserName': 'chrome',
|
||
|
'loggingPrefs': {'browser': 'DEBUG'}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('WebElement', function() {
|
||
|
return runSerializeTest(
|
||
|
new WebElement(FAKE_DRIVER, 'fefifofum'),
|
||
|
WebElement.buildId('fefifofum'));
|
||
|
});
|
||
|
|
||
|
it('WebElementPromise', function() {
|
||
|
return runSerializeTest(
|
||
|
new WebElementPromise(
|
||
|
FAKE_DRIVER,
|
||
|
Promise.resolve(new WebElement(FAKE_DRIVER, 'fefifofum'))),
|
||
|
WebElement.buildId('fefifofum'));
|
||
|
});
|
||
|
|
||
|
describe('an array', function() {
|
||
|
it('with Serializable', function() {
|
||
|
return runSerializeTest([new Session('foo', {})], ['foo']);
|
||
|
});
|
||
|
|
||
|
it('with WebElement', function() {
|
||
|
return runSerializeTest(
|
||
|
[new WebElement(FAKE_DRIVER, 'fefifofum')],
|
||
|
[WebElement.buildId('fefifofum')]);
|
||
|
});
|
||
|
|
||
|
it('with WebElementPromise', function() {
|
||
|
return runSerializeTest(
|
||
|
[new WebElementPromise(
|
||
|
FAKE_DRIVER,
|
||
|
Promise.resolve(new WebElement(FAKE_DRIVER, 'fefifofum')))],
|
||
|
[WebElement.buildId('fefifofum')]);
|
||
|
});
|
||
|
|
||
|
it('complex array', function() {
|
||
|
var expected = [
|
||
|
'abc', 123, true, WebElement.buildId('fefifofum'),
|
||
|
[123, {'foo': 'bar'}]
|
||
|
];
|
||
|
|
||
|
var element = new WebElement(FAKE_DRIVER, 'fefifofum');
|
||
|
var input = ['abc', 123, true, element, [123, {'foo': 'bar'}]];
|
||
|
return runSerializeTest(input, expected);
|
||
|
});
|
||
|
|
||
|
it('nested promises', function() {
|
||
|
return runSerializeTest(
|
||
|
['abc', Promise.resolve([123, Promise.resolve(true)])],
|
||
|
['abc', [123, true]]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('an object', function() {
|
||
|
it('literal', function() {
|
||
|
var expected = {sessionId: 'foo'};
|
||
|
return runSerializeTest({sessionId: 'foo'}, expected);
|
||
|
});
|
||
|
|
||
|
it('with sub-objects', function() {
|
||
|
var expected = {sessionId: {value: 'foo'}};
|
||
|
return runSerializeTest(
|
||
|
{sessionId: {value: 'foo'}}, expected);
|
||
|
});
|
||
|
|
||
|
it('with values that have toJSON', function() {
|
||
|
return runSerializeTest(
|
||
|
{a: {b: new Date(605728511546)}},
|
||
|
{a: {b: '1989-03-12T17:55:11.546Z'}});
|
||
|
});
|
||
|
|
||
|
it('with a Session', function() {
|
||
|
return runSerializeTest(
|
||
|
{a: new Session('foo', {})},
|
||
|
{a: 'foo'});
|
||
|
});
|
||
|
|
||
|
it('nested', function() {
|
||
|
var elementJson = WebElement.buildId('fefifofum');
|
||
|
var expected = {
|
||
|
'script': 'return 1',
|
||
|
'args': ['abc', 123, true, elementJson, [123, {'foo': 'bar'}]],
|
||
|
'sessionId': 'foo'
|
||
|
};
|
||
|
|
||
|
var element = new WebElement(FAKE_DRIVER, 'fefifofum');
|
||
|
var parameters = {
|
||
|
'script': 'return 1',
|
||
|
'args':['abc', 123, true, element, [123, {'foo': 'bar'}]],
|
||
|
'sessionId': new Session('foo', {})
|
||
|
};
|
||
|
|
||
|
return runSerializeTest(parameters, expected);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('can deserialize', function() {
|
||
|
function runDeserializeTest(original, want) {
|
||
|
let executor = new FakeExecutor()
|
||
|
.expect(CName.GET_CURRENT_URL)
|
||
|
.andReturnSuccess(original)
|
||
|
.end();
|
||
|
let driver = executor.createDriver();
|
||
|
return driver.getCurrentUrl().then(function(got) {
|
||
|
assert.deepEqual(got, want);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
it('primitives', function() {
|
||
|
return Promise.all([
|
||
|
runDeserializeTest(1, 1),
|
||
|
runDeserializeTest('', ''),
|
||
|
runDeserializeTest(true, true),
|
||
|
runDeserializeTest(undefined, undefined),
|
||
|
runDeserializeTest(null, null)
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('simple object', function() {
|
||
|
return runDeserializeTest(
|
||
|
{sessionId: 'foo'},
|
||
|
{sessionId: 'foo'});
|
||
|
});
|
||
|
|
||
|
it('nested object', function() {
|
||
|
return runDeserializeTest(
|
||
|
{'foo': {'bar': 123}},
|
||
|
{'foo': {'bar': 123}});
|
||
|
});
|
||
|
|
||
|
it('array', function() {
|
||
|
return runDeserializeTest(
|
||
|
[{'foo': {'bar': 123}}],
|
||
|
[{'foo': {'bar': 123}}]);
|
||
|
});
|
||
|
|
||
|
it('passes through function properties', function() {
|
||
|
function bar() {}
|
||
|
return runDeserializeTest(
|
||
|
[{foo: {'bar': 123}, func: bar}],
|
||
|
[{foo: {'bar': 123}, func: bar}]);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|