123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140 |
- <!DOCTYPE html>
- <html>
- <!--
- Copyright 2009 The Closure Library Authors. All Rights Reserved.
- Author: arv@google.com (Erik Arvidsson)
- -->
- <head>
- <title>Closure Unit Tests - goog.async.Deferred</title>
- <script src="../../../../../closure/goog/base.js"></script>
- <script>
- goog.require('goog.Promise');
- goog.require('goog.Thenable');
- goog.require('goog.array');
- goog.require('goog.async.Deferred');
- goog.require('goog.string');
- goog.require('goog.testing.MockClock');
- goog.require('goog.testing.PropertyReplacer');
- goog.require('goog.testing.jsunit');
- goog.require('goog.testing.recordFunction');
- </script>
- </head>
- <body>
- <script>
- var Deferred = goog.async.Deferred;
- var AlreadyCalledError = Deferred.AlreadyCalledError;
- var CanceledError = Deferred.CanceledError;
- // Unhandled errors may be sent to the browser on a timeout.
- var mockClock = new goog.testing.MockClock();
- var stubs = new goog.testing.PropertyReplacer();
- function setUp() {
- mockClock.install();
- }
- function tearDown() {
- // Advance the mockClock to fire any unhandled exception timeouts.
- mockClock.tick();
- mockClock.uninstall();
- stubs.reset();
- }
- function assertEqualsCallback(msg, expected) {
- return function(res) {
- assertEquals(msg, expected, res);
- // Since the assertion is an exception that will be caught inside the
- // Deferred object, we must advance the clock to see if it has failed.
- mockClock.tick();
- return res;
- };
- }
- function increment(res) {
- return res + 1;
- }
- function throwStuff(res) {
- throw res;
- }
- function catchStuff(res) {
- return res;
- }
- function returnError(res) {
- return Error(res);
- }
- function neverHappen(res) {
- fail('This should not happen');
- }
- function testNormal() {
- var d = new Deferred();
- d.addCallback(assertEqualsCallback('pre-deferred callback', 1));
- d.callback(1);
- d.addCallback(increment);
- d.addCallback(assertEqualsCallback('post-deferred callback', 2));
- d.addCallback(throwStuff);
- d.addCallback(neverHappen);
- d.addErrback(catchStuff);
- d.addCallback(assertEqualsCallback('throw -> err, catch -> success', 2));
- d.addCallback(returnError);
- d.addCallback(neverHappen);
- d.addErrback(catchStuff);
- d.addCallback(assertEqualsCallback('return -> err, catch -> succcess', 2));
- }
- function testCancel() {
- var count = 0;
- function canceled(d) {
- count++;
- }
- function canceledError(res) {
- assertTrue(res instanceof CanceledError);
- }
- var d = new Deferred(canceled);
- d.addCallback(neverHappen);
- d.addErrback(canceledError);
- d.cancel();
- assertEquals(1, count);
- }
- function testSucceedFail() {
- var count = 0;
- var d = Deferred.succeed(1).addCallback(assertEqualsCallback('succeed', 1));
- // default error
- d = Deferred.fail().addCallback(neverHappen);
- d = d.addErrback(function(res) {
- count++;
- return res;
- });
- // default wrapped error
- d = Deferred.fail('web taco').addCallback(neverHappen).addErrback(catchStuff);
- d = d.addCallback(assertEqualsCallback('wrapped fail', 'web taco'));
- // default unwrapped error
- d = Deferred.fail(Error('ugh')).addCallback(neverHappen).addErrback(
- catchStuff);
- d = d.addCallback(assertEqualsCallback('unwrapped fail', 'ugh'));
- assertEquals(1, count);
- }
- function testDeferredDependencies() {
- function deferredIncrement(res) {
- var rval = Deferred.succeed(res);
- rval.addCallback(increment);
- return rval;
- }
- var d = Deferred.succeed(1).addCallback(deferredIncrement);
- d = d.addCallback(assertEqualsCallback('dependent deferred succeed', 2));
- function deferredFailure(res) {
- return Deferred.fail(res);
- }
- d = Deferred.succeed('ugh').addCallback(deferredFailure).addErrback(
- catchStuff);
- d = d.addCallback(assertEqualsCallback('dependent deferred fail', 'ugh'));
- }
- // Test double-calling, double-failing, etc.
- function testDoubleCalling() {
- var ex = assertThrows(function() {
- Deferred.succeed(1).callback(2);
- neverHappen();
- });
- assertTrue('double call', ex instanceof AlreadyCalledError);
- }
- function testDoubleCalling2() {
- var ex = assertThrows(function() {
- Deferred.fail(1).errback(2);
- neverHappen();
- });
- assertTrue('double-fail', ex instanceof AlreadyCalledError);
- }
- function testDoubleCalling3() {
- var ex = assertThrows(function() {
- var d = Deferred.succeed(1);
- d.cancel();
- d = d.callback(2);
- assertTrue('swallowed one callback, no canceler', true);
- d.callback(3);
- neverHappen();
- });
- assertTrue('swallow cancel', ex instanceof AlreadyCalledError);
- }
- function testDoubleCalling4() {
- var count = 0;
- function canceled(d) {
- count++;
- }
- var ex = assertThrows(function() {
- var d = new Deferred(canceled);
- d.cancel();
- d = d.callback(1);
- });
- assertTrue('non-swallowed cancel', ex instanceof AlreadyCalledError);
- assertEquals(1, count);
- }
- // Test incorrect Deferred usage
- function testIncorrectUsage() {
- var d = new Deferred();
- var ex = assertThrows(function() {
- d.callback(new Deferred());
- neverHappen();
- });
- assertTrue('deferred not allowed for callback', ex instanceof Error);
- }
- function testIncorrectUsage2() {
- var d = new Deferred();
- var ex = assertThrows(function() {
- d.errback(new Deferred());
- neverHappen();
- });
- assertTrue('deferred not allowed for errback', ex instanceof Error);
- }
- function testIncorrectUsage3() {
- var d = new Deferred();
- (new Deferred()).addCallback(function() {return d;}).callback(1);
- var ex = assertThrows(function() {
- d.addCallback(function() {});
- neverHappen();
- });
- assertTrue('chained deferred not allowed to be re-used', ex instanceof Error);
- }
- function testCallbackScope1() {
- var c1 = {}, c2 = {};
- var callbackScope = null;
- var errbackScope = null;
- var d = new Deferred();
- d.addCallback(function() {
- callbackScope = this;
- throw Error('Foo');
- }, c1);
- d.addErrback(function() {
- errbackScope = this;
- }, c2);
- d.callback();
- assertEquals('Incorrect callback scope', c1, callbackScope);
- assertEquals('Incorrect errback scope', c2, errbackScope);
- }
- function testCallbackScope2() {
- var callbackScope = null;
- var errbackScope = null;
- var d = new Deferred();
- d.addCallback(function() {
- callbackScope = this;
- throw Error('Foo');
- });
- d.addErrback(function() {
- errbackScope = this;
- });
- d.callback();
- assertEquals('Incorrect callback scope', window, callbackScope);
- assertEquals('Incorrect errback scope', window, errbackScope);
- }
- function testCallbackScope3() {
- var c = {};
- var callbackScope = null;
- var errbackScope = null;
- var d = new Deferred(null, c);
- d.addCallback(function() {
- callbackScope = this;
- throw Error('Foo');
- });
- d.addErrback(function() {
- errbackScope = this;
- });
- d.callback();
- assertEquals('Incorrect callback scope', c, callbackScope);
- assertEquals('Incorrect errback scope', c, errbackScope);
- }
- function testChainedDeferred1() {
- var calls = [];
- var d2 = new Deferred();
- d2.addCallback(function() {calls.push('B1');});
- d2.addCallback(function() {calls.push('B2');});
- var d1 = new Deferred();
- d1.addCallback(function() {calls.push('A1');});
- d1.addCallback(function() {calls.push('A2');});
- d1.chainDeferred(d2);
- d1.addCallback(function() {calls.push('A3');});
- d1.callback();
- assertEquals('A1,A2,B1,B2,A3', calls.join(','));
- }
- function testChainedDeferred2() {
- var calls = [];
- var d2 = new Deferred();
- d2.addCallback(function() {calls.push('B1');});
- d2.addErrback(function(err) {calls.push('B2'); throw Error('x');});
- var d1 = new Deferred();
- d1.addCallback(function(err) {throw Error('foo');});
- d1.chainDeferred(d2);
- d1.addCallback(function() {calls.push('A1');});
- d1.addErrback(function() {calls.push('A2');});
- d1.callback();
- assertEquals('B2,A2', calls.join(','));
- var ex = assertThrows(function() {
- mockClock.tick();
- neverHappen();
- });
- assertTrue('Should catch unhandled throw from d2.', ex.message == 'x');
- }
- function testUndefinedResultAndCallbackSequence() {
- var results = [];
- var d = new Deferred();
- d.addCallback(function(res) {return 'foo';});
- d.addCallback(function(res) {results.push(res); return 'bar';});
- d.addCallback(function(res) {results.push(res);});
- d.addCallback(function(res) {results.push(res);});
- d.callback();
- assertEquals('foo,bar,bar', results.join(','));
- }
- function testUndefinedResultAndErrbackSequence() {
- var results = [];
- var d = new Deferred();
- d.addCallback(function(res) {throw Error('uh oh');});
- d.addErrback(function(res) {results.push('A');});
- d.addCallback(function(res) {results.push('B');});
- d.addErrback(function(res) {results.push('C');});
- d.callback();
- assertEquals('A,C', results.join(','));
- }
- function testHasFired() {
- var d1 = new Deferred();
- var d2 = new Deferred();
- assertFalse(d1.hasFired());
- assertFalse(d2.hasFired());
- d1.callback();
- d2.errback();
- assertTrue(d1.hasFired());
- assertTrue(d2.hasFired());
- }
- function testUnhandledErrors() {
- var d = new Deferred();
- d.addCallback(throwStuff);
- var ex = assertThrows(function() {
- d.callback(123);
- mockClock.tick();
- neverHappen();
- });
- assertEquals('Unhandled throws should hit the browser.', 123, ex);
- assertNotThrows(
- 'Errbacks added after a failure should resume.',
- function() {
- d.addErrback(catchStuff);
- mockClock.tick();
- });
- d.addCallback(assertEqualsCallback('Should recover after throw.', 1));
- mockClock.tick();
- }
- function testStrictUnhandledErrors() {
- stubs.replace(Deferred, 'STRICT_ERRORS', true);
- var err = Error('never handled');
- // The registered errback exists, but doesn't modify the error value.
- var d = Deferred.succeed();
- d.addCallback(function(res) { throw err; });
- d.addErrback(function(unhandledErr) {});
- var caught = assertThrows(
- 'The error should be rethrown at the next clock tick.',
- function() { mockClock.tick(); });
- assertEquals(err, caught);
- }
- function testStrictHandledErrors() {
- stubs.replace(Deferred, 'STRICT_ERRORS', true);
- // The registered errback returns a non-error value.
- var d = Deferred.succeed();
- d.addCallback(function(res) { throw Error('eventually handled'); });
- d.addErrback(function(unhandledErr) { return true; });
- assertNotThrows(
- 'The error was handled and should not be rethrown',
- function() { mockClock.tick(); });
- d.addCallback(function(res) { assertTrue(res); });
- }
- function testStrictBlockedErrors() {
- stubs.replace(Deferred, 'STRICT_ERRORS', true);
- var d1 = Deferred.fail(Error('blocked failure'));
- var d2 = new Deferred();
- d1.addBoth(function() { return d2; });
- assertNotThrows(
- 'd1 should be blocked until d2 fires.',
- function() { mockClock.tick(); });
- d2.callback('unblocked');
- d1.addCallback(assertEqualsCallback(
- 'd1 should receive the fired result from d2.', 'unblocked'));
- }
- function testStrictCanceledErrors() {
- stubs.replace(Deferred, 'STRICT_ERRORS', true);
- var d = Deferred.canceled();
- assertNotThrows(
- 'CanceledErrors should not be rethrown to the global scope.',
- function() { mockClock.tick(); });
- }
- function testSynchronousErrorCanceling() {
- var d = new Deferred();
- d.addCallback(throwStuff);
- assertNotThrows(
- 'Adding an errback to the end of a failing Deferred should cancel the ' +
- 'unhandled error timeout.',
- function() {
- d.callback(1);
- d.addErrback(catchStuff);
- mockClock.tick();
- });
- d.addCallback(assertEqualsCallback('Callback should fire', 1));
- }
- function testThrowNonError() {
- var results = [];
- var d = new Deferred();
- d.addCallback(function(res) {
- throw res;
- });
- d.addErrback(function(res) {
- results.push(res);
- return 6;
- });
- d.addCallback(function(res) {
- results.push(res);
- });
- d.callback(7);
- assertArrayEquals(
- 'Errback should have been called with 7, followed by callback with 6.',
- [7, 6], results);
- }
- function testThrownErrorWithNoErrbacks() {
- var d = new Deferred();
- d.addCallback(function() {
- throw Error('foo');
- });
- d.addCallback(goog.nullFunction);
- function assertCallback() {
- d.callback(1);
- mockClock.tick(); // Should cause error because throwing is delayed.
- }
- assertThrows('A thrown error should be rethrown if there is no ' +
- 'errback to catch it.', assertCallback);
- }
- function testThrownErrorCallbacksDoNotCancel() {
- var d = new Deferred();
- d.addCallback(function() {
- throw Error('foo');
- });
- function assertCallback() {
- d.callback(1);
- // Add another callback after the fact. Note this is not an errback!
- d.addCallback(neverHappen);
- mockClock.tick(); // Should cause error because throwing is delayed.
- }
- assertThrows('A thrown error should be rethrown if there is no ' +
- 'errback to catch it.', assertCallback);
- }
- function testAwaitDeferred() {
- var results = [];
- function fn(x) {
- return function() {
- results.push(x);
- };
- }
- var d2 = new Deferred();
- d2.addCallback(fn('b'));
- // d1 -> a -> (wait for d2) -> c
- var d1 = new Deferred();
- d1.addCallback(fn('a'));
- d1.awaitDeferred(d2);
- d1.addCallback(fn('c'));
- // calls 'a' then yields for d2.
- d1.callback(null);
- // will get called after d2.
- d1.addCallback(fn('d'));
- assertEquals('a', results.join(''));
- // d3 -> w -> (wait for d2) -> x
- var d3 = new Deferred();
- d3.addCallback(fn('w'));
- d3.awaitDeferred(d2);
- d3.addCallback(fn('x'));
- // calls 'w', then yields for d2.
- d3.callback();
- // will get called after d2.
- d3.addCallback(fn('y'));
- assertEquals('aw', results.join(''));
- // d1 calls 'd', d3 calls 'y'
- d2.callback(null);
- assertEquals('awbcdxy', results.join(''));
- // d3 and d2 already called, so 'z' called immediately.
- d3.addCallback(fn('z'));
- assertEquals('awbcdxyz', results.join(''));
- }
- function testAwaitDeferred_withPromise() {
- var results = [];
- function fn(x) {
- return function() {
- results.push(x);
- };
- }
- var resolver = new goog.Promise.withResolver();
- resolver.promise.then(fn('b'));
- // d1 -> a -> (wait for promise) -> c
- var d1 = new Deferred();
- d1.addCallback(fn('a'));
- d1.awaitDeferred(resolver.promise);
- d1.addCallback(fn('c'));
- // calls 'a' then yields for promise.
- d1.callback(1);
- // will get called after promise.
- d1.addCallback(fn('d'));
- assertEquals('a', results.join(''));
- // d3 -> w -> (wait for promise) -> x
- var d3 = new Deferred();
- d3.addCallback(fn('w'));
- d3.awaitDeferred(resolver.promise);
- d3.addCallback(fn('x'));
- // calls 'w', then yields for promise.
- d3.callback(2);
- // will get called after promise.
- d3.addCallback(fn('y'));
- assertEquals('aw', results.join(''));
- // d1 calls 'd', d3 calls 'y'
- resolver.resolve();
- mockClock.tick();
- assertEquals('awbcdxy', results.join(''));
- // d3 and promise already called, so 'z' called immediately.
- d3.addCallback(fn('z'));
- assertEquals('awbcdxyz', results.join(''));
- }
- function testAwaitDeferredWithErrors() {
- var results = [];
- function fn(x) {
- return function(e) {
- results.push(x);
- };
- }
- var d2 = new Deferred();
- d2.addErrback(fn('a'));
- var d1 = new Deferred();
- d1.awaitDeferred(d2);
- d1.addCallback(fn('x'));
- d1.addErrback(fn('b'));
- d1.callback(null);
- assertEquals('', results.join(''));
- d2.addCallback(fn('z'));
- d2.addErrback(fn('c'));
- d2.errback(null);
- // First errback added to d2 prints 'a'.
- // Next 'd' was chained, so execute its err backs, printing 'b'.
- // Finally 'c' was added last by d2's errback.
- assertEquals('abc', results.join(''));
- }
- function testNonErrorErrback() {
- var results = [];
- function fn(x) {
- return function(e) {
- results.push(x);
- };
- }
- var d = new Deferred();
- d.addCallback(fn('a'));
- d.addErrback(fn('b'));
- d.addCallback(fn('c'));
- d.addErrback(fn('d'));
- d.errback('foo');
- assertEquals('bd', results.join(''));
- }
- function testUnequalReturnValueForErrback() {
- var results = [];
- function fn(x) {
- return function(e) {
- results.push(x);
- };
- }
- var d = new Deferred();
- d.addCallback(fn('a'));
- d.addErrback(function() {
- results.push('b');
- return 'bar';
- });
- d.addCallback(fn('c'));
- d.addErrback(fn('d'));
- d.errback('foo');
- assertEquals('bc', results.join(''));
- }
- function testBranch() {
- function fn(x) {
- return function(arr) {
- return arr.concat(x);
- };
- }
- var d = new Deferred();
- d.addCallback(fn(1));
- d.addCallback(fn(2));
- var d2 = d.branch();
- d.addCallback(fn(3));
- d2.addCallback(fn(4));
- d.callback([]);
- assertTrue('both deferreds should have fired', d.hasFired());
- assertTrue('both deferreds should have fired', d2.hasFired());
- d.addCallback(function(arr) { assertArrayEquals([1, 2, 3], arr); });
- d2.addCallback(function(arr) { assertArrayEquals([1, 2, 4], arr); });
- }
- function testDiamondBranch() {
- function fn(x) {
- return function(arr) {
- return arr.concat(x);
- };
- }
- var d = new Deferred();
- d.addCallback(fn(1));
- var d2 = d.branch();
- d2.addCallback(fn(2));
- // Chain the branch back to the original. There is no good reason to do this
- // cever.
- d.addCallback(function(ret) {return d2;});
- d.callback([]);
- // But no reason it shouldn't work!
- d.addCallback(function(arr) { assertArrayEquals([1, 2], arr); });
- }
- function testRepeatedBranch() {
- var d = new Deferred().addCallback(increment);
- d.branch().
- addCallback(assertEqualsCallback('branch should be after increment', 2)).
- addCallback(function(res) {return d.branch();}).
- addCallback(assertEqualsCallback('second branch should be the same', 2));
- d.callback(1);
- }
- function testCancelThroughBranch() {
- var wasCanceled = false;
- var d = new Deferred(function() { wasCanceled = true; });
- var branch1 = d.branch(true);
- var branch2 = d.branch(true);
- branch1.cancel();
- assertFalse(wasCanceled);
- branch2.cancel();
- assertTrue(wasCanceled);
- }
- function testCancelThroughSeveralBranches() {
- var wasCanceled = false;
- var d = new Deferred(function() { wasCanceled = true; });
- var branch = d.branch(true).branch(true).branch(true);
- branch.cancel();
- assertTrue(wasCanceled);
- }
- function testBranchCancelThenCallback() {
- var wasCanceled = false;
- var d = new Deferred(function() { wasCanceled = true; });
- var wasCalled = false;
- d.addCallback(function() { wasCalled = true; });
- var branch1 = d.branch();
- var branch2 = d.branch();
- var branch1WasCalled = false;
- var branch2WasCalled = false;
- branch1.addCallback(function() { branch1WasCalled = true; });
- branch2.addCallback(function() { branch2WasCalled = true; });
- var branch1HadErrback = false;
- var branch2HadErrback = false;
- branch1.addErrback(function() { branch1HadErrback = true; });
- branch2.addErrback(function() { branch2HadErrback = true; });
- branch1.cancel();
- assertFalse(wasCanceled);
- assertTrue(branch1HadErrback);
- assertFalse(branch2HadErrback);
- d.callback();
- assertTrue(wasCalled);
- assertFalse(branch1WasCalled);
- assertTrue(branch2WasCalled);
- }
- function testDeepCancelOnBranch() {
- var wasCanceled = false;
- var d = new Deferred(function() { wasCanceled = true; });
- var branch1 = d.branch(true);
- var branch2 = d.branch(true).branch(true).branch(true);
- var branch1HadErrback = false;
- var branch2HadErrback = false;
- branch1.addErrback(function() { branch1HadErrback = true; });
- branch2.addErrback(function() { branch2HadErrback = true; });
- branch2.cancel(true /* opt_deepCancel */);
- assertTrue(wasCanceled);
- assertTrue(branch1HadErrback);
- assertTrue(branch2HadErrback);
- }
- function testCancelOnRoot() {
- var wasCanceled = false;
- var d = new Deferred(function() { wasCanceled = true; });
- var branch = d.branch(true).branch(true).branch(true);
- d.cancel();
- assertTrue(wasCanceled);
- }
- function testCancelOnLeafBranch() {
- var wasCanceled = false;
- var branchWasCanceled = false;
- var d = new Deferred(function() { wasCanceled = true; });
- var branch = d.branch(true).branch(true).branch(true);
- branch.addErrback(function() { branchWasCanceled = true; });
- branch.cancel();
- assertTrue(wasCanceled);
- assertTrue(branchWasCanceled);
- }
- function testCancelOnIntermediateBranch() {
- var rootWasCanceled = false;
- var d = new Deferred(function() { rootWasCanceled = true; });
- var branch = d.branch(true).branch(true).branch(true);
- var deepBranch1 = branch.branch(true);
- var deepBranch2 = branch.branch(true);
- branch.cancel();
- assertTrue(rootWasCanceled);
- assertTrue(deepBranch1.hasFired());
- assertTrue(deepBranch2.hasFired());
- }
- function testCancelWithSomeCompletedBranches() {
- var d = new Deferred();
- var branch1 = d.branch(true);
- var branch1HadCallback = false;
- var branch1HadErrback = false;
- branch1.
- addCallback(function() { branch1HadCallback = true; }).
- addErrback(function() { branch1HadErrback = true; });
- d.callback(true);
- assertTrue(branch1HadCallback);
- assertFalse(branch1HadErrback);
- var rootHadCallback = false;
- var rootHadErrback = false;
- // Block the root on a new Deferred indefinitely.
- d.
- addCallback(function() { rootHadCallback = true; }).
- addCallback(function() { return new Deferred(); }).
- addErrback(function() { rootHadErrback = true; });
- var branch2 = d.branch(true);
- assertTrue(rootHadCallback);
- assertFalse(rootHadErrback);
- branch2.cancel();
- assertFalse(branch1HadErrback);
- assertTrue('Canceling the last active branch should cancel the parent.',
- rootHadErrback);
- }
- function testStaticCanceled() {
- var callbackCalled = false;
- var errbackResult = null;
- var d = goog.async.Deferred.canceled();
- d.addCallback(function() { callbackCalled = true;} );
- d.addErrback(function(err) { errbackResult = err;} );
- assertTrue('Errback should have been called with a canceled error',
- errbackResult instanceof goog.async.Deferred.CanceledError);
- assertFalse('Callback should not have been called', callbackCalled);
- }
- function testWhenWithValues() {
- var called = false;
- Deferred.when(4, function(obj) {
- called = true;
- assertEquals(4, obj);
- });
- assertTrue('Fn should have been called', called);
- }
- function testWhenWithDeferred() {
- var called = false;
- var d = new Deferred();
- Deferred.when(d, function(obj) {
- called = true;
- assertEquals(6, obj);
- });
- assertFalse('Fn should not have been called yet', called);
- d.callback(6);
- assertTrue('Fn should have been called', called);
- }
- function testWhenDoesntAlterOriginalChain() {
- var calls = 0;
- var d1 = new Deferred();
- var d2 = Deferred.when(d1, function(obj) {
- calls++;
- return obj * 2;
- });
- d1.addCallback(function(obj) {
- assertEquals('Original chain should get original value', 5, obj);
- calls++;
- });
- d2.addCallback(function(obj) {
- assertEquals('Branched chain should get modified value', 10, obj);
- calls++;
- });
- d1.callback(5);
- assertEquals('There should have been 3 callbacks', 3, calls);
- }
- function testAssertNoErrors() {
- var d = new Deferred();
- d.addCallback(function() {
- throw new Error('Foo');
- });
- d.callback(1);
- var ex = assertThrows(function() {
- Deferred.assertNoErrors();
- neverHappen();
- });
- assertEquals('Expected to get thrown error', 'Foo', ex.message);
- assertNotThrows(
- 'Calling Deferred.assertNoErrors() a second time with only one ' +
- 'scheduled error should pass.',
- function() {
- Deferred.assertNoErrors();
- });
- }
- function testThen() {
- var result;
- var result2;
- var d = new Deferred();
- assertEquals(d.then, d['then']);
- d.then(function(r) {
- return result = r;
- }).then(function (r2) {
- result2 = r2;
- });
- d.callback('done');
- assertUndefined(result);
- mockClock.tick();
- assertEquals('done', result);
- assertEquals('done', result2);
- }
- function testThen_reject() {
- var result, error, error2;
- var d = new Deferred();
- assertEquals(d.then, d['then']);
- d.then(function(r) {
- result = r;
- }, function(e) {
- error = e;
- });
- d.errback(new Error('boom'));
- assertUndefined(result);
- mockClock.tick();
- assertUndefined(result);
- assertEquals('boom', error.message);
- }
- function testPromiseAll() {
- var d = new Deferred();
- var p = new goog.Promise(function(resolve) {
- resolve('promise');
- });
- goog.Promise.all([d, p]).then(function(values) {
- assertEquals(2, values.length);
- assertEquals('deferred', values[0]);
- assertEquals('promise', values[1]);
- });
- d.callback('deferred');
- mockClock.tick();
- }
- function testGoogPromiseBlocksDeferred() {
- var result;
- var d = new Deferred();
- var p = new goog.Promise(function(resolve) {
- resolve('promise');
- });
- d.callback();
- d.addCallback(function() {
- return p;
- });
- d.addCallback(function(r) {
- result = r;
- });
- assertUndefined(result);
- mockClock.tick();
- assertEquals('promise', result);
- }
- function testNativePromiseBlocksDeferred() {
- // Early-out for browsers that don't support native Promises.
- if (typeof Promise !== 'function') {
- return;
- }
- // Disable mock clock for this test. Native promises don't abide by it, so
- // it just complicates things in this case.
- mockClock.uninstall();
- var blockedOnPromise = true;
- var resolver;
- var d = Deferred.succeed();
- d.addCallback(function() {
- return new Promise(function(resolve) {
- resolver = resolve;
- });
- });
- d.addCallback(function(r) {
- blockedOnPromise = false;
- assertEquals('Native promise value', 'result', r);
- });
- // Verify that the callback chain executes up to, but not beyond, the callback
- // that returns a Promise.
- assertTrue(!!resolver);
- assertTrue('Deferred chain not blocked on Promise resolution',
- blockedOnPromise);
- // Resolve the promise, which should unblock the rest of the callback chain.
- resolver('result');
- return d;
- }
- function testFromPromise() {
- var result;
- var p = new goog.Promise(function(resolve) {
- resolve('promise');
- });
- var d = Deferred.fromPromise(p);
- d.addCallback(function(value) {
- result = value;
- });
- assertUndefined(result);
- mockClock.tick();
- assertEquals('promise', result);
- }
- function testPromiseBlocksDeferredAndRejects() {
- var result;
- var d = new Deferred();
- var p = new goog.Promise(function(resolve, reject) {
- reject(new Error('error'));
- });
- d.callback();
- d.addCallback(function(r) {
- return p;
- });
- d.addErrback(function(r) {
- result = r;
- });
- assertUndefined(result);
- mockClock.tick();
- assertEquals('error', result.message);
- }
- function testPromiseFromCanceledDeferred() {
- var result;
- var d = new Deferred();
- d.cancel();
- var p = d.then(neverHappen, function(reason) {
- result = reason;
- });
- mockClock.tick();
- assertTrue(result instanceof goog.Promise.CancellationError);
- }
- function testThenableInterface() {
- var d = new Deferred();
- assertTrue(goog.Thenable.isImplementedBy(d));
- }
- function testAddBothPropagatesToErrback() {
- var log = [];
- var deferred = new goog.async.Deferred();
- deferred.addBoth(goog.nullFunction);
- deferred.addErrback(function () {
- log.push('errback');
- });
- deferred.errback(new Error('my error'));
- mockClock.tick(1);
- assertArrayEquals(['errback'], log);
- }
- function testAddBothDoesNotPropagateUncaughtExceptions() {
- var deferred = new goog.async.Deferred();
- deferred.addBoth(goog.nullFunction);
- deferred.errback(new Error('my error'));
- mockClock.tick(1);
- }
- function testAddFinally() {
- var deferred = new goog.async.Deferred();
- var callback = goog.testing.recordFunction();
- var thisArg = {};
- deferred.addFinally(callback, thisArg);
- deferred.errback(new Error('my error'));
- try {
- mockClock.tick(1);
- } catch (e) {
- assertEquals('my error', e.message);
- }
- assertEquals(thisArg, callback.getCalls()[0].getThis());
- }
- </script>
- </body>
- </html>
|