selenium-webdriver
Version:
The official WebDriver JavaScript bindings from the Selenium project
1,864 lines (1,495 loc) • 62.1 kB
JavaScript
// Copyright 2014 Software Freedom Conservancy. All Rights Reserved.
//
// Licensed 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.
goog.require('goog.array');
goog.require('goog.functions');
goog.require('goog.string');
goog.require('goog.testing.FunctionMock');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
goog.require('webdriver.promise.ControlFlow');
goog.require('webdriver.stacktrace.Snapshot');
goog.require('webdriver.test.testutil');
goog.require('webdriver.testing.promise.FlowTester');
// Aliases for readability.
var STUB_ERROR = webdriver.test.testutil.STUB_ERROR,
throwStubError = webdriver.test.testutil.throwStubError,
assertIsStubError = webdriver.test.testutil.assertIsStubError,
assertingMessages = webdriver.test.testutil.assertingMessages,
callbackHelper = webdriver.test.testutil.callbackHelper,
callbackPair = webdriver.test.testutil.callbackPair;
var clock, flow, flowHistory, flowTester;
function shouldRunTests() {
return !goog.userAgent.IE || goog.userAgent.isVersionOrHigher(10);
}
function setUp() {
clock = webdriver.test.testutil.createMockClock();
flowTester = new webdriver.testing.promise.FlowTester(clock, goog.global);
flow = webdriver.promise.controlFlow();
webdriver.test.testutil.messages = [];
flowHistory = [];
}
function tearDown() {
flowTester.dispose();
clock.dispose();
}
function schedule(msg, opt_return) {
return scheduleAction(msg, function() {
return opt_return;
});
}
/**
* @param {string} value The value to push.
* @param {webdriver.promise.Promise=} opt_taskPromise Promise to return from
* the task.
* @return {!webdriver.promise.Promise} The result.
*/
function schedulePush(value, opt_taskPromise) {
return scheduleAction(value, function() {
webdriver.test.testutil.messages.push(value);
return opt_taskPromise;
});
}
/**
* @param {string} msg Debug message.
* @param {!Function} actionFn The function.
* @return {!webdriver.promise.Promise} The function result.
*/
function scheduleAction(msg, actionFn) {
return webdriver.promise.controlFlow().execute(function() {
flowHistory.push(msg);
return actionFn();
}, msg);
}
/**
* @param {!Function} condition The condition function.
* @param {number} timeout The timeout.
* @param {string=} opt_message Optional message.
* @return {!webdriver.promise.Promise} The wait result.
*/
function scheduleWait(condition, timeout, opt_message) {
var msg = opt_message || '';
// It's not possible to hook into when the wait itself is scheduled, so
// we record each iteration of the wait loop.
var count = 0;
return webdriver.promise.controlFlow().wait(function() {
flowHistory.push((count++) + ': ' + msg);
return condition();
}, timeout, msg);
}
/** @see {@link webdriver.testing.promise.FlowTester#turnEventLoop}. */
function turnEventLoop() {
flowTester.turnEventLoop();
}
function runAndExpectSuccess(opt_callback) {
flowTester.run();
flowTester.verifySuccess();
if (opt_callback) {
opt_callback();
}
}
function runAndExpectFailure(opt_errback) {
flowTester.run();
flowTester.verifyFailure();
if (opt_errback) {
opt_errback(flowTester.getFailure());
}
}
function assertFlowHistory(var_args) {
var expected = goog.array.slice(arguments, 0);
assertArrayEquals(expected, flowHistory);
}
/**
* @param {string=} opt_description A description of the task for debugging.
* @return {!webdriver.promise.Task_} The new task.
*/
function createTask(opt_description) {
return new webdriver.promise.Task_(
webdriver.promise.controlFlow(),
goog.nullFunction,
opt_description || '',
new webdriver.stacktrace.Snapshot());
}
/**
* @return {!webdriver.promise.Frame_}
*/
function createFrame() {
return new webdriver.promise.Frame_(webdriver.promise.controlFlow());
}
function testAddChild_toEmptyFrame() {
var frame = createFrame();
var task1 = createTask(),
task2 = createTask(),
task3 = createTask();
frame.addChild(task1);
frame.addChild(task2);
frame.addChild(task3);
assertArrayEquals([task1, task2, task3], frame.children_);
}
function testAddChild_withSubframes() {
var root = createFrame();
var task1 = createTask('task1');
root.addChild(task1);
assertArrayEquals([task1], root.children_);
var frame1 = createFrame();
root.addChild(frame1);
assertArrayEquals([task1, frame1], root.children_);
var task2 = createTask('task2'), task3 = createTask('task3');
root.addChild(task2);
root.addChild(task3);
assertArrayEquals([task1, frame1], root.children_);
assertArrayEquals([task2, task3], frame1.children_);
frame1.lockFrame();
var task4 = createTask('task4'), task5 = createTask('task5');
root.addChild(task4);
root.addChild(task5);
assertArrayEquals([task1, frame1, task4, task5], root.children_);
assertArrayEquals([task2, task3], frame1.children_);
var frame2 = createFrame(),
frame3 = createFrame(),
task6 = createTask('task6'),
task7 = createTask('task7'),
task8 = createTask('task8');
root.addChild(frame2);
root.addChild(frame3);
root.addChild(task6);
frame3.lockFrame();
root.addChild(task7);
frame2.lockFrame();
root.addChild(task8);
assertArrayEquals([task1, frame1, task4, task5, frame2, task8],
root.children_);
assertArrayEquals([task2, task3], frame1.children_);
assertArrayEquals([frame3, task7], frame2.children_);
assertArrayEquals([task6], frame3.children_);
}
function testAddChild_insertingFramesIntoAnActiveFrame() {
var root = createFrame(),
frame2 = createFrame(),
frame3 = createFrame(),
task1 = createTask('task1');
root.addChild(task1);
root.isActive_ = true;
root.addChild(frame2);
frame2.lockFrame();
root.addChild(frame3);
frame3.lockFrame();
assertArrayEquals([frame2, frame3, task1], root.children_);
}
function testRemoveChild() {
var frame1 = createFrame(),
frame2 = createFrame();
frame1.addChild(frame2);
assertArrayEquals([frame2], frame1.children_);
frame1.removeChild(frame2);
assertArrayEquals([], frame1.children_);
}
function testResolveFrame() {
var frame1 = createFrame(),
frame2 = createFrame(),
frame3 = createFrame();
frame2.addChild(frame3);
frame1.addChild(frame2);
assertArrayEquals([frame3], frame2.children_);
assertArrayEquals([frame2], frame1.children_);
frame1.fulfill = callbackHelper();
frame2.fulfill = callbackHelper();
frame3.fulfill = callbackHelper();
var obj = {
activeFrame_: frame2,
commenceShutdown_: callbackHelper(),
trimHistory_: callbackHelper(),
history_: []
};
webdriver.promise.ControlFlow.prototype.resolveFrame_.call(obj, frame3);
assertEquals(1, obj.trimHistory_.getCallCount());
frame3.fulfill.assertCalled('frame 3 not resolved');
frame2.fulfill.assertNotCalled('frame 2 should not be resolved yet');
frame1.fulfill.assertNotCalled('frame 1 should not be resolved yet');
assertNull(frame3.getParent());
assertArrayEquals([], frame2.children_);
assertArrayEquals([frame2], frame1.children_);
assertEquals(frame2, obj.activeFrame_);
webdriver.promise.ControlFlow.prototype.resolveFrame_.call(obj, frame2);
assertEquals(2, obj.trimHistory_.getCallCount());
frame2.fulfill.assertCalled('frame 2 not resolved');
frame1.fulfill.assertNotCalled('frame 1 should not be resolved yet');
assertNull(frame2.getParent());
assertArrayEquals([], frame1.children_);
assertEquals(frame1, obj.activeFrame_);
obj.commenceShutdown_.assertNotCalled();
webdriver.promise.ControlFlow.prototype.resolveFrame_.call(obj, frame1);
assertEquals(3, obj.trimHistory_.getCallCount());
frame1.fulfill.assertCalled('frame 1 not resolved');
obj.commenceShutdown_.assertCalled();
assertNull(frame1.getParent());
assertNull(obj.activeFrame_);
}
function testGetNextTask() {
var root = flow.activeFrame_ = createFrame();
var frame1 = createFrame(),
frame2 = createFrame(),
frame3 = createFrame(),
task1 = createTask('task1'),
task2 = createTask('task2'),
task3 = createTask('task3'),
task4 = createTask('task4'),
task5 = createTask('task5'),
task6 = createTask('task6'),
task7 = createTask('task7'),
task8 = createTask('task8');
flow.commenceShutdown_ = callbackHelper();
root.fulfill = callbackHelper();
frame1.fulfill = callbackHelper();
frame2.fulfill = callbackHelper();
frame3.fulfill = callbackHelper();
root.addChild(task1);
root.addChild(frame1);
root.addChild(task2);
root.addChild(task3);
assertArrayEquals([task1, frame1], root.children_);
assertArrayEquals([task2, task3], frame1.children_);
frame1.lockFrame();
root.addChild(task4);
root.addChild(task5);
assertArrayEquals([task1, frame1, task4, task5], root.children_);
assertArrayEquals([task2, task3], frame1.children_);
root.addChild(frame2);
root.addChild(frame3);
root.addChild(task6);
frame3.lockFrame();
root.addChild(task7);
frame2.lockFrame();
root.addChild(task8);
assertArrayEquals([task1, frame1, task4, task5, frame2, task8],
root.children_);
assertArrayEquals([task2, task3], frame1.children_);
assertArrayEquals([frame3, task7], frame2.children_);
assertArrayEquals([task6], frame3.children_);
assertEquals(root, task1.getParent());
assertEquals(task1, flow.getNextTask_());
assertNull(task1.getParent());
assertEquals(root, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame1.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertNotCalled();
assertEquals(task2, flow.getNextTask_());
assertNull(task2.getParent());
assertEquals(frame1, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame1.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertNotCalled();
assertEquals(task3, flow.getNextTask_());
assertNull(task3.getParent());
assertEquals(frame1, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame1.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertNotCalled();
assertNull(flow.getNextTask_());
assertNull(frame1.getParent());
assertEquals(root, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame1.fulfill.assertCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertNotCalled();
assertEquals(task4, flow.getNextTask_());
assertNull(task4.getParent());
assertEquals(root, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertNotCalled();
assertEquals(task5, flow.getNextTask_());
assertNull(task5.getParent());
assertEquals(root, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertNotCalled();
assertEquals(task6, flow.getNextTask_());
assertNull(task6.getParent());
assertEquals(frame3, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertNotCalled();
assertNull(flow.getNextTask_());
assertNull(frame3.getParent());
assertEquals(frame2, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
frame3.fulfill.assertCalled('frame3 should have been resolved');
assertEquals(task7, flow.getNextTask_());
assertNull(task7.getParent());
assertEquals(frame2, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame2.fulfill.assertNotCalled();
assertNull(flow.getNextTask_());
assertNull(frame2.getParent());
assertEquals(root, flow.activeFrame_);
root.fulfill.assertNotCalled();
frame2.fulfill.assertCalled('frame2 should have been resolved');
assertEquals(task8, flow.getNextTask_());
assertNull(task8.getParent());
assertEquals(root, flow.activeFrame_);
root.fulfill.assertNotCalled();
flow.commenceShutdown_.assertNotCalled();
assertNull(flow.getNextTask_());
assertNull(flow.activeFrame_);
root.fulfill.assertCalled('Root should have been resolved');
flow.commenceShutdown_.assertCalled();
}
function testAbortFrame_noActiveFrame() {
flow.abortFrame_(STUB_ERROR);
assertIsStubError(flowTester.getFailure());
assertNull(flow.activeFrame_);
}
function testAbortFrame_activeIsOnlyFrame() {
// Make the ControlFlow think the flow is not-idle.
flow.emit(webdriver.promise.ControlFlow.EventType.SCHEDULE_TASK);
flow.activeFrame_ = createFrame();
flow.abortFrame_(STUB_ERROR);
assertNull(flow.activeFrame_);
flowTester.assertStillRunning();
clock.tick();
assertIsStubError(flowTester.getFailure());
}
function testAbortFrame_unhandledAbortionsBubbleUp() {
var root = flow.activeFrame_ = createFrame(),
frame1 = createFrame(),
frame2 = createFrame(),
frame3 = createFrame(),
task = createTask();
var rootHelper = installResolveHelper(root),
frame1Helper = installResolveHelper(frame1),
frame2Helper = installResolveHelper(frame2),
frame3Helper = installResolveHelper(frame3);
flow.abortNow_ = callbackHelper(assertIsStubError);
root.addChild(frame1);
root.addChild(frame2);
root.addChild(frame3);
root.addChild(task);
assertArrayEquals([task], frame3.children_);
assertArrayEquals([frame3], frame2.children_);
assertArrayEquals([frame2], frame1.children_);
assertArrayEquals([frame1], root.children_);
assertEquals(task, flow.getNextTask_());
assertEquals(frame3, flow.activeFrame_);
flow.abortNow_.assertNotCalled();
rootHelper.assertNeither();
frame1Helper.assertNeither();
frame2Helper.assertNeither();
frame3Helper.assertNeither();
flow.abortFrame_(STUB_ERROR);
assertEquals(frame2, flow.activeFrame_);
flow.abortNow_.assertNotCalled();
rootHelper.assertNeither();
frame1Helper.assertNeither();
frame2Helper.assertNeither();
frame3Helper.assertErrback();
clock.tick();
assertEquals(frame1, flow.activeFrame_);
flow.abortNow_.assertNotCalled();
rootHelper.assertNeither();
frame1Helper.assertNeither();
frame2Helper.assertErrback();
clock.tick();
assertEquals(root, flow.activeFrame_);
flow.abortNow_.assertNotCalled();
rootHelper.assertNeither();
frame1Helper.assertErrback();
clock.tick();
assertNull(flow.activeFrame_);
flow.abortNow_.assertNotCalled();
rootHelper.assertErrback();
clock.tick();
assertNull(flow.activeFrame_);
flow.abortNow_.assertCalled();
function installResolveHelper(promise) {
var reject = promise.reject;
var pair = callbackPair(promise.fulfill, function(e) {
assertIsStubError(e);
reject(e);
});
promise.fulfill = pair.callback;
promise.reject = pair.errback;
return pair;
}
}
function testRunInNewFrame_nothingScheduledInFunction() {
var root = flow.activeFrame_ = createFrame(),
task1 = createTask(),
task2 = createTask();
root.addChild(task1);
root.addChild(task2);
assertArrayEquals([task1, task2], root.children_);
assertEquals(task1, flow.getNextTask_());
assertEquals(root, flow.activeFrame_);
assertArrayEquals([task2], root.children_);
var pair = callbackPair(assertUndefined);
flow.runInNewFrame_(goog.nullFunction, pair.callback, pair.errback);
pair.assertCallback();
assertEquals(root, flow.activeFrame_);
assertArrayEquals([task2], root.children_);
}
function testRunInNewFrame_functionThrows() {
var root = flow.activeFrame_ = createFrame(),
task1 = createTask(),
task2 = createTask();
root.addChild(task1);
root.addChild(task2);
assertArrayEquals([task1, task2], root.children_);
assertEquals(task1, flow.getNextTask_());
assertEquals(root, flow.activeFrame_);
assertArrayEquals([task2], root.children_);
var pair = callbackPair(null, assertIsStubError);
flow.runInNewFrame_(throwStubError, pair.callback, pair.errback);
pair.assertErrback();
assertEquals(root, flow.activeFrame_);
assertArrayEquals([task2], root.children_);
}
function testRunInNewFrame_functionThrowsAfterSchedulingTasks() {
var root = flow.activeFrame_ = createFrame(),
task1 = createTask('task1'),
task2 = createTask('task2');
root.addChild(task1);
root.addChild(task2);
assertArrayEquals([task1, task2], root.children_);
assertEquals(task1, flow.getNextTask_());
assertEquals(root, flow.activeFrame_);
assertArrayEquals([task2], root.children_);
var pair = callbackPair(null, assertIsStubError);
flow.runInNewFrame_(function() {
flow.execute(goog.nullFunction);
throw STUB_ERROR;
}, pair.callback, pair.errback);
pair.assertErrback();
assertEquals(root, flow.activeFrame_);
assertArrayEquals([task2], root.children_);
}
function testRunInNewFrame_whenThereIsNoCurrentActiveFrame_noopFunc() {
var pair = callbackPair(assertUndefined);
flow.runInNewFrame_(goog.nullFunction, pair.callback, pair.errback);
pair.assertCallback();
assertNull(flow.activeFrame_);
assertEquals('[]', flow.getSchedule());
}
function testRunInNewFrame_whenThereIsNoCurrentActiveFrame_funcThrows() {
var pair = callbackPair(null, assertIsStubError);
flow.runInNewFrame_(throwStubError, pair.callback, pair.errback);
pair.assertErrback();
assertNull(flow.activeFrame_);
assertEquals('[]', flow.getSchedule());
}
function
testRunInNewFrame_whenThereIsNoCurrentActiveFrame_throwsAfterSchedule() {
var pair = callbackPair(null, assertIsStubError);
flow.runInNewFrame_(function() {
flow.execute('task3', goog.nullFunction);
throwStubError();
}, pair.callback, pair.errback);
pair.assertErrback();
assertNull(flow.activeFrame_);
assertEquals('[]', flow.getSchedule());
}
function testRunInNewFrame_returnsPrimitiveFunctionResultImmediately() {
var pair = callbackPair(goog.partial(assertEquals, 23));
flow.runInNewFrame_(function() {
return 23;
}, pair.callback, pair.errback);
pair.assertCallback();
}
function testRunInNewFrame_updatesSchedulingFrameForContextOfFunction() {
var root = flow.activeFrame_ = createFrame();
var pair = callbackPair();
flow.runInNewFrame_(function() {
assertNotNull(flow.activeFrame_);
assertNotNull(flow.schedulingFrame_);
assertNotEquals(root, flow.schedulingFrame_);
assertArrayEquals([flow.schedulingFrame_], root.children_);
assertEquals(root, flow.schedulingFrame_.getParent());
}, pair.callback, pair.errback);
pair.assertCallback();
assertEquals('Did not restore active frame', root, flow.activeFrame_);
}
function testRunInNewFrame_doesNotReturnUntilScheduledFrameResolved() {
var root = flow.activeFrame_ = createFrame(),
task1 = createTask('task1'),
task2 = createTask('task2');
root.addChild(task1);
root.addChild(task2);
assertArrayEquals([task1, task2], root.children_);
assertEquals(task1, flow.getNextTask_());
assertEquals(root, flow.activeFrame_);
assertArrayEquals([task2], root.children_);
var pair = callbackPair();
flow.runInNewFrame_(function() {
schedule('task3');
}, pair.callback, pair.errback);
pair.assertNeither('active frame not resolved yet');
assertEquals(root, flow.activeFrame_);
var task = flow.getNextTask_();
assertEquals('task3', task.getDescription());
assertEquals(root.children_[0], flow.activeFrame_);
pair.assertNeither('active frame still not resolved yet');
assertNull(flow.getNextTask_());
pair.assertCallback();
assertEquals(root, flow.activeFrame_);
assertEquals(task2, flow.getNextTask_());
}
function testRunInNewFrame_doesNotReturnUntilScheduledFrameResolved_nested() {
var root = flow.activeFrame_ = createFrame();
schedule('task1');
schedule('task2');
assertEquals('task1', flow.getNextTask_().getDescription());
var pair1 = callbackPair(), pair2 = callbackPair();
flow.runInNewFrame_(function() {
schedule('task3');
flow.runInNewFrame_(function() {
schedule('task4');
}, pair2.callback, pair2.errback);
}, pair1.callback, pair1.errback);
pair1.assertNeither();
pair2.assertNeither();
assertEquals('task3', flow.getNextTask_().getDescription());
assertEquals('task4', flow.getNextTask_().getDescription());
assertNull(flow.getNextTask_());
pair1.assertNeither();
pair2.assertCallback();
assertNull(flow.getNextTask_());
pair1.assertCallback();
assertEquals(root, flow.activeFrame_);
assertEquals('task2', flow.getNextTask_().getDescription());
}
function testScheduling_aSimpleFunction() {
schedule('go');
runAndExpectSuccess();
assertFlowHistory('go');
}
function testScheduling_aSimpleSequence() {
schedule('a');
schedule('b');
schedule('c');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c');
}
function testScheduling_invokesCallbacksWhenTaskIsDone() {
var callback;
var d = new webdriver.promise.Deferred();
schedule('a', d.promise).then(callback = callbackHelper(function(value) {
assertEquals(123, value);
}));
callback.assertNotCalled('Callback should not have been called yet');
turnEventLoop();
callback.assertNotCalled('Task has not completed yet!');
d.fulfill(123);
callback.assertCalled('Callback should have been called!');
runAndExpectSuccess();
assertFlowHistory('a');
}
function testScheduling_blocksUntilPromiseReturnedByTaskIsResolved() {
var d = new webdriver.promise.Deferred();
schedule('a', d.promise);
schedule('b');
assertFlowHistory();
turnEventLoop(); assertFlowHistory('a');
turnEventLoop(); assertFlowHistory('a'); // Task 'a' is still running.
turnEventLoop(); assertFlowHistory('a'); // Task 'a' is still running.
d.fulfill(123);
runAndExpectSuccess();
assertFlowHistory('a', 'b');
}
function testScheduling_waitsForReturnedPromisesToResolve() {
var d1 = new webdriver.promise.Deferred();
var d2 = new webdriver.promise.Deferred();
var callback;
schedule('a', d1.promise).then(callback = callbackHelper(function(value) {
assertEquals('fluffy bunny', value);
}));
callback.assertNotCalled('d1 not resolved yet');
d1.fulfill(d2);
callback.assertNotCalled('Should not be called yet; blocked on d2');
d2.fulfill('fluffy bunny');
runAndExpectSuccess();
callback.assertCalled('d2 has been resolved');
assertFlowHistory('a');
}
function testScheduling_executesTasksInAFutureTurnAfterTheyAreScheduled() {
var count = 0;
function incr() { count++; }
scheduleAction('', incr);
assertEquals(0, count);
turnEventLoop();
assertEquals(1, count);
runAndExpectSuccess();
}
function testScheduling_executesOneTaskPerTurnOfTheEventLoop() {
var count = 0;
function incr() { count++; }
scheduleAction('', incr);
scheduleAction('', incr);
assertEquals(0, count);
turnEventLoop();
assertEquals(1, count);
turnEventLoop();
assertEquals(2, count);
runAndExpectSuccess();
}
function testScheduling_firstScheduledTaskIsWithinACallback() {
webdriver.promise.fulfilled().then(function() {
schedule('a');
schedule('b');
schedule('c');
});
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c');
}
function testFraming_callbacksRunInANewFrame() {
schedule('a').then(function() {
schedule('c');
});
schedule('b');
runAndExpectSuccess();
assertFlowHistory('a', 'c', 'b');
}
function testFraming_lotsOfNesting() {
schedule('a').then(function() {
schedule('c').then(function() {
schedule('e').then(function() {
schedule('g');
});
schedule('f');
});
schedule('d');
});
schedule('b');
runAndExpectSuccess();
assertFlowHistory('a', 'c', 'e', 'g', 'f', 'd', 'b');
}
function testFraming_eachCallbackWaitsForAllScheduledTasksToComplete() {
schedule('a').
then(function() {
schedule('b');
schedule('c');
}).
then(function() {
schedule('d');
});
schedule('e');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e');
}
function testFraming_eachCallbackWaitsForReturnTasksToComplete() {
schedule('a').
then(function() {
schedule('b');
return schedule('c');
}).
then(function() {
schedule('d');
});
schedule('e');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e');
}
function testFraming_promiseCallbacks() {
webdriver.promise.fulfilled().then(function() {
schedule('b');
});
schedule('a');
runAndExpectSuccess();
assertFlowHistory('b', 'a');
}
function testFraming_allCallbacksInAFrameAreScheduledWhenPromiseIsResolved() {
var a = schedule('a');
a.then(function() { schedule('b'); });
schedule('c');
a.then(function() { schedule('d'); });
schedule('e');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'd', 'c', 'e');
}
function testFraming_tasksScheduledInInActiveFrameDoNotGetPrecedence() {
var d = new webdriver.promise.Deferred();
schedule('a');
schedule('b');
d.then(function() { schedule('c'); });
d.fulfill();
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c');
}
function testFraming_tasksScheduledInAFrameGetPrecedence_1() {
var a = schedule('a');
schedule('b').then(function() {
a.then(function() {
schedule('c');
schedule('d');
});
var e = schedule('e');
a.then(function() {
// When this function runs, |e| will not be resolved yet, so |f| and
// |h| will be resolved first. After |e| is resolved, |g| will be
// scheduled in a new frame, resulting in: [j][f, h, i][g], so |g| is
// expected to execute first.
schedule('f');
e.then(function() {
schedule('g');
});
schedule('h');
});
schedule('i');
});
schedule('j');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e', 'g', 'f', 'h', 'i', 'j');
}
function testErrorHandling_thrownErrorsArePassedToTaskErrback() {
var callbacks = callbackPair(null, assertIsStubError);
scheduleAction('function that throws', throwStubError).
then(callbacks.callback, callbacks.errback);
runAndExpectSuccess(callbacks.assertErrback);
}
function testErrorHandling_thrownErrorsPropagateThroughPromiseChain() {
var callbacks = callbackPair(null, assertIsStubError);
scheduleAction('function that throws', throwStubError).
then(callbacks.callback).
then(null, callbacks.errback);
runAndExpectSuccess(callbacks.assertErrback);
}
function testErrorHandling_catchesErrorsFromFailedTasksInAFrame() {
var errback;
schedule('a').
then(function() {
schedule('b');
scheduleAction('function that throws', throwStubError);
}).
then(null, errback = callbackHelper(assertIsStubError));
runAndExpectSuccess();
errback.assertCalled();
}
function testErrorHandling_abortsIfOnlyTaskThrowsAnError() {
scheduleAction('function that throws', throwStubError);
runAndExpectFailure(assertIsStubError);
}
function testErrorHandling_abortsIfOnlyTaskReturnsAnUnhandledRejection() {
var rejected = webdriver.promise.rejected(STUB_ERROR);
scheduleAction('function that throws', function() { return rejected; });
runAndExpectFailure(assertIsStubError);
}
function testErrorHandling_abortsIfThereIsAnUnhandledRejection() {
webdriver.promise.rejected(STUB_ERROR);
schedule('this should not run');
runAndExpectFailure(assertIsStubError);
assertFlowHistory();
}
function testErrorHandling_abortsSequenceIfATaskFails() {
schedule('a');
schedule('b');
scheduleAction('c', throwStubError);
schedule('d'); // Should never execute.
runAndExpectFailure(assertIsStubError);
assertFlowHistory('a', 'b', 'c');
}
function testErrorHandling_abortsFromUnhandledFramedTaskFailures_1() {
schedule('outer task').then(function() {
scheduleAction('inner task', throwStubError);
});
schedule('this should not run');
runAndExpectFailure(assertIsStubError);
assertFlowHistory('outer task', 'inner task');
}
function testErrorHandling_abortsFromUnhandledFramedTaskFailures_2() {
schedule('a').then(function() {
schedule('b').then(function() {
scheduleAction('c', throwStubError);
// This should not execute.
schedule('d');
});
});
runAndExpectFailure(assertIsStubError);
assertFlowHistory('a', 'b', 'c');
}
function testErrorHandling_abortsWhenErrorBubblesUpFromFullyResolvingAnObject() {
var obj = {'foo': webdriver.promise.rejected(STUB_ERROR)};
scheduleAction('', function() {
return webdriver.promise.fullyResolved(obj).
then(function() {
// Should never get here; STUB_ERROR should abort the flow above.
return webdriver.promise.rejected('rejected 2');
});
});
runAndExpectFailure(assertIsStubError);
}
function testErrorHandling_abortsWhenErrorBubblesUpFromFullyResolvingAnObject_withCallback() {
var obj = {'foo': webdriver.promise.rejected(STUB_ERROR)};
var callback;
scheduleAction('', function() {
return webdriver.promise.fullyResolved(obj).
then(function() {
// Should never get here; STUB_ERROR should abort the flow above.
return webdriver.promise.rejected('rejected 2');
});
}).then(callback = callbackHelper());
callback.assertNotCalled();
runAndExpectFailure(assertIsStubError);
}
function testErrorHandling_canCatchErrorsFromNestedTasks() {
var errback;
schedule('a').
then(function() {
return scheduleAction('b', throwStubError);
}).
thenCatch(errback = callbackHelper(assertIsStubError));
runAndExpectSuccess();
errback.assertCalled();
}
function testErrorHandling_nestedCommandFailuresCanBeCaughtAndSuppressed() {
var errback;
schedule('a').then(function() {
return schedule('b').then(function() {
return schedule('c').then(function() {
throw STUB_ERROR;
});
});
}).thenCatch(errback = callbackHelper(assertIsStubError));
schedule('d');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd');
errback.assertCalled();
}
function testErrorHandling_aTaskWithAnUnhandledPromiseRejection() {
schedule('a');
scheduleAction('sub-tasks', function() {
webdriver.promise.rejected(STUB_ERROR);
});
schedule('should never run');
runAndExpectFailure(assertIsStubError);
assertFlowHistory('a', 'sub-tasks');
}
function testErrorHandling_aTaskThatReutrnsARejectedPromise() {
schedule('a');
scheduleAction('sub-tasks', function() {
return webdriver.promise.rejected(STUB_ERROR);
});
schedule('should never run');
runAndExpectFailure(assertIsStubError);
assertFlowHistory('a', 'sub-tasks')
}
function testErrorHandling_discardsSubtasksIfTaskThrows() {
var pair = callbackPair(null, assertIsStubError);
scheduleAction('a', function() {
schedule('b');
schedule('c');
throwStubError();
}).then(pair.callback, pair.errback);
schedule('d');
runAndExpectSuccess();
pair.assertErrback();
assertFlowHistory('a', 'd');
}
function testErrorHandling_discardsRemainingSubtasksIfASubtaskFails() {
var pair = callbackPair(null, assertIsStubError);
scheduleAction('a', function() {
schedule('b');
scheduleAction('c', throwStubError);
schedule('d');
}).then(pair.callback, pair.errback);
schedule('e');
runAndExpectSuccess();
pair.assertErrback();
assertFlowHistory('a', 'b', 'c', 'e');
}
function testTryFinally_happyPath() {
/* Model:
try {
doFoo();
doBar();
} finally {
doBaz();
}
*/
schedulePush('foo').
then(goog.partial(schedulePush, 'bar')).
thenFinally(goog.partial(schedulePush, 'baz'));
runAndExpectSuccess(assertingMessages('foo', 'bar', 'baz'));
assertFlowHistory('foo', 'bar', 'baz');
}
function testTryFinally_firstTryFails() {
/* Model:
try {
doFoo();
doBar();
} finally {
doBaz();
}
*/
scheduleAction('doFoo and throw', function() {
webdriver.test.testutil.messages.push('foo');
throw STUB_ERROR;
}).then(goog.partial(schedulePush, 'bar')).
thenFinally(goog.partial(schedulePush, 'baz'));
runAndExpectFailure(function(e) {
assertIsStubError(e);
webdriver.test.testutil.assertMessages('foo', 'baz');
});
}
function testTryFinally_secondTryFails() {
/* Model:
try {
doFoo();
doBar();
} finally {
doBaz();
}
*/
schedulePush('foo').
then(function() {
return scheduleAction('doBar and throw', function() {
webdriver.test.testutil.messages.push('bar');
throw STUB_ERROR;
});
}).
thenFinally(function() {
return schedulePush('baz');
});
runAndExpectFailure(function(e) {
assertIsStubError(e);
webdriver.test.testutil.assertMessages('foo', 'bar' , 'baz');
});
}
function testDelayedNesting_1() {
var a = schedule('a');
schedule('b').then(function() {
a.then(function() { schedule('c'); });
schedule('d');
});
schedule('e');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e');
}
function testDelayedNesting_2() {
var a = schedule('a');
schedule('b').then(function() {
a.then(function() { schedule('c'); });
schedule('d');
a.then(function() { schedule('e'); });
});
schedule('f');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e', 'f');
}
function testDelayedNesting_3() {
var a = schedule('a');
schedule('b').then(function() {
a.then(function() { schedule('c'); });
a.then(function() { schedule('d'); });
});
schedule('e');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e');
}
function testDelayedNesting_4() {
var a = schedule('a');
schedule('b').then(function() {
a.then(function() { schedule('c'); }).then(function() {
schedule('d');
});
a.then(function() { schedule('e'); });
});
schedule('f');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e', 'f');
}
function testDelayedNesting_5() {
var a = schedule('a');
schedule('b').then(function() {
var c;
a.then(function() { c = schedule('c'); }).then(function() {
schedule('d');
a.then(function() { schedule('e'); });
c.then(function() { schedule('f'); });
schedule('g');
});
a.then(function() { schedule('h'); });
});
schedule('i');
runAndExpectSuccess();
assertFlowHistory('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i');
}
function testCancelsTerminationEventIfNewCommandIsScheduled() {
schedule('a');
turnEventLoop();
assertFlowHistory('a');
flowTester.assertStillRunning();
turnEventLoop();
schedule('b');
runAndExpectSuccess();
assertFlowHistory('a', 'b');
}
function testWaiting_onAConditionThatIsAlwaysTrue() {
scheduleWait(function() { return true;}, 0, 'waiting on true');
runAndExpectSuccess();
assertFlowHistory('0: waiting on true');
}
function testWaiting_aSimpleCountingCondition() {
var count = 0;
scheduleWait(function() {
return ++count == 3;
}, 200, 'counting to 3');
turnEventLoop(); // Start the flow; triggers first condition poll.
assertEquals(1, count);
clock.tick(100); // Poll 2 more times.
clock.tick(100);
assertEquals(3, count);
runAndExpectSuccess();
}
function testWaiting_aConditionThatReturnsAPromise() {
var d = new webdriver.promise.Deferred();
scheduleWait(function() {
return d.promise;
}, 0, 'waiting for promise');
turnEventLoop();
flowTester.assertStillRunning();
// Should be able to turn the event loop a few times since we're blocked
// on our wait condition.
turnEventLoop();
turnEventLoop();
d.fulfill(123);
runAndExpectSuccess();
}
function testWaiting_aConditionThatReturnsAPromise_2() {
var count = 0;
scheduleWait(function() {
return webdriver.promise.fulfilled(++count == 3);
}, 200, 'waiting for promise');
turnEventLoop(); // Start the flow; triggers first condition poll.
clock.tick(100); // Poll 2 more times.
clock.tick(100);
assertEquals(3, count);
runAndExpectSuccess();
}
function testWaiting_aConditionThatReturnsATaskResult() {
var count = 0;
scheduleWait(function() {
return scheduleAction('increment count', function() {
return ++count == 3;
});
}, 200, 'counting to 3');
schedule('post wait');
turnEventLoop();
assertEquals(0, count);
assertFlowHistory('0: counting to 3');
turnEventLoop(); // Runs scheduled task.
turnEventLoop();
assertFlowHistory(
'0: counting to 3', 'increment count');
assertEquals(1, count);
clock.tick(100); // Advance clock for next polling pass.
assertEquals(1, count);
turnEventLoop();
assertEquals(2, count);
turnEventLoop();
assertFlowHistory(
'0: counting to 3', 'increment count',
'1: counting to 3', 'increment count');
clock.tick(100); // Advance clock for next polling pass.
assertEquals(2, count);
turnEventLoop();
assertEquals(3, count);
turnEventLoop();
assertFlowHistory(
'0: counting to 3', 'increment count',
'1: counting to 3', 'increment count',
'2: counting to 3', 'increment count');
runAndExpectSuccess();
assertEquals(3, count);
assertFlowHistory(
'0: counting to 3', 'increment count',
'1: counting to 3', 'increment count',
'2: counting to 3', 'increment count',
'post wait');
}
function testWaiting_conditionContainsASubtask() {
var count = 0;
scheduleWait(function() {
schedule('sub task');
return ++count == 3;
}, 200, 'counting to 3');
schedule('post wait');
runAndExpectSuccess();
assertEquals(3, count);
assertFlowHistory(
'0: counting to 3', 'sub task',
'1: counting to 3', 'sub task',
'2: counting to 3', 'sub task',
'post wait');
}
function testWaiting_cancelsWaitIfScheduledTaskFails() {
var pair = callbackPair(null, assertIsStubError);
scheduleWait(function() {
scheduleAction('boom', throwStubError);
schedule('this should not run');
return true;
}, 200, 'waiting to go boom').then(pair.callback, pair.errback);
schedule('post wait');
runAndExpectSuccess();
assertFlowHistory(
'0: waiting to go boom', 'boom',
'post wait');
}
function testWaiting_failsIfConditionThrows() {
var callbacks = callbackPair(null, assertIsStubError);
scheduleWait(throwStubError, 0, 'goes boom').
then(callbacks.callback, callbacks.errback);
schedule('post wait');
runAndExpectSuccess();
assertFlowHistory('0: goes boom', 'post wait');
callbacks.assertErrback();
}
function testWaiting_failsIfConditionReturnsARejectedPromise() {
var callbacks = callbackPair(null, assertIsStubError);
scheduleWait(function() {
return webdriver.promise.rejected(STUB_ERROR);
}, 0, 'goes boom').then(callbacks.callback, callbacks.errback);
schedule('post wait');
runAndExpectSuccess();
assertFlowHistory('0: goes boom', 'post wait');
callbacks.assertErrback();
}
function testWaiting_failsIfConditionHasUnhandledRejection() {
var callbacks = callbackPair(null, assertIsStubError);
scheduleWait(function() {
webdriver.promise.controlFlow().execute(throwStubError);
}, 0, 'goes boom').then(callbacks.callback, callbacks.errback);
schedule('post wait');
runAndExpectSuccess();
assertFlowHistory('0: goes boom', 'post wait');
callbacks.assertErrback();
}
function testWaiting_failsIfConditionHasAFailedSubtask() {
var callbacks = callbackPair(null, assertIsStubError);
var count = 0;
scheduleWait(function() {
scheduleAction('maybe throw', function() {
if (++count == 2) {
throw STUB_ERROR;
}
});
}, 200, 'waiting').then(callbacks.callback, callbacks.errback);
schedule('post wait');
turnEventLoop();
assertEquals(0, count);
turnEventLoop(); // Runs scheduled task.
assertEquals(1, count);
clock.tick(100); // Advance clock for next polling pass.
assertEquals(1, count);
runAndExpectSuccess();
assertEquals(2, count);
assertFlowHistory(
'0: waiting', 'maybe throw',
'1: waiting', 'maybe throw',
'post wait');
}
function testWaiting_pollingLoopWaitsForAllScheduledTasksInCondition() {
var count = 0;
scheduleWait(function() {
scheduleAction('increment count', function() { ++count; });
return count >= 3;
}, 300, 'counting to 3');
schedule('post wait');
turnEventLoop();
assertEquals(0, count);
turnEventLoop(); // Runs scheduled task.
turnEventLoop();
assertEquals(1, count);
clock.tick(100); // Advance clock for next polling pass.
assertEquals(1, count);
turnEventLoop();
assertEquals(2, count);
clock.tick(100); // Advance clock for next polling pass.
assertEquals(2, count);
runAndExpectSuccess();
assertEquals(4, count);
assertFlowHistory(
'0: counting to 3', 'increment count',
'1: counting to 3', 'increment count',
'2: counting to 3', 'increment count',
'3: counting to 3', 'increment count',
'post wait');
}
function testWaiting_blocksNextTaskOnWait() {
var count = 0;
scheduleWait(function() {
return ++count == 3;
}, 200, 'counting to 3');
schedule('post wait');
turnEventLoop(); // Start the flow; triggers first condition poll.
assertFlowHistory('0: counting to 3');
assertEquals(1, count);
clock.tick(100); // Poll 2 more times.
assertFlowHistory(
'0: counting to 3',
'1: counting to 3');
clock.tick(100);
assertFlowHistory(
'0: counting to 3',
'1: counting to 3',
'2: counting to 3');
assertEquals(3, count);
runAndExpectSuccess();
assertFlowHistory(
'0: counting to 3',
'1: counting to 3',
'2: counting to 3',
'post wait');
}
function testWaiting_timesOut_zeroTimeout() {
scheduleWait(function() { return false; }, 0, 'always false');
runAndExpectFailure(goog.nullFunction);
}
function testWaiting_timesOut_nonZeroTimeout() {
var count = 0;
scheduleWait(function() {
return ++count == 3;
}, 100, 'counting to 3');
turnEventLoop(); // Start the flow; triggers first condition poll.
clock.tick(100); // Poll 2 more times.
assertEquals(2, count);
runAndExpectFailure(function() {
assertFlowHistory('0: counting to 3', '1: counting to 3');
assertEquals(2, count);
});
}
function testWaiting_shouldFailIfConditionReturnsARejectedPromise() {
var count = 0;
scheduleWait(function() {
return webdriver.promise.rejected(STUB_ERROR);
}, 100, 'counting to 3');
runAndExpectFailure(assertIsStubError);
}
function testWaiting_callbacks() {
var pair = callbackPair();
scheduleWait(function() { return true;}, 0, 'waiting on true').
then(pair.callback, pair.errback);
pair.assertNeither('Wait not expected to be done yet');
turnEventLoop();
pair.assertCallback('Wait callback not called!');
runAndExpectSuccess();
}
function testWaiting_errbacks() {
scheduleWait(function() { return false; }, 0, 'always false');
runAndExpectFailure();
}
function testWaiting_scheduleWithIntermittentWaits() {
schedule('a');
scheduleWait(function() { return true; }, 0, 'wait 1');
schedule('b');
scheduleWait(function() { return true; }, 0, 'wait 2');
schedule('c');
scheduleWait(function() { return true; }, 0, 'wait 3');
runAndExpectSuccess();
assertFlowHistory('a', '0: wait 1', 'b', '0: wait 2', 'c', '0: wait 3');
}
function testWaiting_scheduleWithIntermittentAndNestedWaits() {
schedule('a');
scheduleWait(function() { return true; }, 0, 'wait 1').
then(function() {
schedule('d');
scheduleWait(function() { return true; }, 0, 'wait 2');
schedule('e');
});
schedule('b');
scheduleWait(function() { return true; }, 0, 'wait 3');
schedule('c');
scheduleWait(function() { return true; }, 0, 'wait 4');
runAndExpectSuccess();
assertFlowHistory(
'a', '0: wait 1', 'd', '0: wait 2', 'e', 'b', '0: wait 3', 'c',
'0: wait 4');
}
function testSubtasks() {
schedule('a');
scheduleAction('sub-tasks', function() {
schedule('c');
schedule('d');
});
schedule('b');
runAndExpectSuccess();
assertFlowHistory('a', 'sub-tasks', 'c', 'd', 'b');
}
function testSubtasks_nesting() {
schedule('a');
scheduleAction('sub-tasks', function() {
schedule('b');
scheduleAction('sub-sub-tasks', function() {
schedule('c');
schedule('d');
});
schedule('e');
});
schedule('f');
runAndExpectSuccess();
assertFlowHistory(
'a', 'sub-tasks', 'b', 'sub-sub-tasks', 'c', 'd', 'e', 'f');
}
function testSubtasks_taskReturnsSubTaskResult_1() {
schedule('a');
scheduleAction('sub-tasks', function() {
return schedule('c');
});
schedule('b');
runAndExpectSuccess();
assertFlowHistory('a', 'sub-tasks', 'c', 'b');
}
function testSubtasks_taskReturnsSubTaskResult_2() {
var callback;
schedule('a');
schedule('sub-tasks', webdriver.promise.fulfilled(123)).
then(callback = callbackHelper(function(value) {
assertEquals(123, value);
}));
schedule('b');
runAndExpectSuccess();
assertFlowHistory('a', 'sub-tasks','b');
callback.assertCalled();
}
function testSubtasks_subTaskFails_1() {
schedule('a');
scheduleAction('sub-tasks', function() {
scheduleAction('sub-task that fails', throwStubError);
});
schedule('should never execute');
runAndExpectFailure(assertIsStubError);
assertFlowHistory('a', 'sub-tasks', 'sub-task that fails');
}
function testSubtasks_subTaskFails_2() {
schedule('a');
scheduleAction('sub-tasks', function() {
return webdriver.promise.rejected(STUB_ERROR);
});
schedule('should never execute');
runAndExpectFailure(assertIsStubError);
assertFlowHistory('a', 'sub-tasks');
}
function testSubtasks_subTaskFails_3() {
var callbacks = callbackPair(null, assertIsStubError);
schedule('a');
scheduleAction('sub-tasks', function() {
return webdriver.promise.rejected(STUB_ERROR);
}).then(callbacks.callback, callbacks.errback);
schedule('b');
runAndExpectSuccess();
assertFlowHistory('a', 'sub-tasks', 'b');
callbacks.assertErrback();
}
function testEventLoopWaitsOnPendingPromiseRejections_oneRejection() {
var d = new webdriver.promise.Deferred;
scheduleAction('one', function() {
return d.promise;
});
scheduleAction('two', goog.nullFunction);
turn();
assertFlowHistory('one');
turn(-1);
d.reject(STUB_ERROR);
clock.tick(1);
assertFlowHistory('one');
runAndExpectFailure(assertIsStubError);
assertFlowHistory('one');
function turn(opt_minusN) {
var n = webdriver.promise.ControlFlow.EVENT_LOOP_FREQUENCY;
if (opt_minusN) n -= Math.abs(opt_minusN);
clock.tick(n);
}
}
function testEventLoopWaitsOnPendingPromiseRejections_multipleRejections() {
var once = Error('once');
var twice = Error('twice');
var onError = new goog.testing.FunctionMock('onError',
goog.testing.Mock.LOOSE);
onError(once);
onError(twice);
onError.$replay();
flow.on(
webdriver.promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION, onError);
scheduleAction('one', goog.nullFunction);
scheduleAction('two', goog.nullFunction);
turn();
assertFlowHistory('one');
turn(-1);
webdriver.promise.rejected(once);
webdriver.promise.rejected(twice);
clock.tick(1);
assertFlowHistory('one');
turn();
onError.$verify();
function turn(opt_minusN) {
var n = webdriver.promise.ControlFlow.EVENT_LOOP_FREQUENCY;
if (opt_minusN) n -= Math.abs(opt_minusN);
clock.tick(n);
}
}
function testCancelsPromiseReturnedByCallbackIfFrameFails_promiseCallback() {
var chainPair = callbackPair(null, assertIsStubError);
var deferredPair = callbackPair(null, assertIsStubError);
var d = new webdriver.promise.Deferred();
d.then(deferredPair.callback, deferredPair.errback);
webdriver.promise.fulfilled().
then(function() {
scheduleAction('boom', throwStubError);
schedule('this should not run');
return d.promise;
}).
then(chainPair.callback, chainPair.errback);
runAndExpectSuccess();
assertFlowHistory('boom');
chainPair.assertErrback('chain errback not invoked');
deferredPair.assertErrback('deferred errback not invoked');
}
function testCancelsPromiseReturnedByCallbackIfFrameFails_taskCallback() {
var chainPair = callbackPair(null, assertIsStubError);
var deferredPair = callbackPair(null, assertIsStubError);
var d = new webdriver.promise.Deferred();
d.then(deferredPair.callback, deferredPair.errback);
schedule('a').
then(function() {
scheduleAction('boom', throwStubError);
schedule('this should not run');
return d.promise;
}).
then(chainPair.callback, chainPair.errback);
runAndExpectSuccess();
assertFlowHistory('a', 'boom');
chainPair.assertErrback('chain errback not invoked');
deferredPair.assertErrback('deferred errback not invoked');
}
function testMaintainsOrderInCallbacksWhenATaskReturnsAPromise() {
schedule('__start__', webdriver.promise.fulfilled()).
then(function() {
webdriver.test.testutil.messages.push('a');
schedulePush('b');
webdriver.test.testutil.messages.push('c');
}).
then(function() {
webdriver.test.testutil.messages.push('d');
});
schedulePush('e');
runAndExpectSuccess();
assertFlowHistory('__start__', 'b', 'e');
webdriver.test.testutil.assertMessages('a', 'c', 'b', 'd', 'e');
}
function assertFrame(description, frame) {
var regexp = new RegExp('^' + description + '(\\n at .*)*$');
assertTrue(
'Frame did not match expected regex:' +
'\n expec