node-bluebird/test/mocha/2.2.6.js

258 lines
10 KiB
JavaScript

"use strict";
var assert = require("assert");
var sinon = require("sinon");
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
var testRejected = require("./helpers/testThreeCases").testRejected;
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
var other = { other: "other" }; // a value we don't want to be strict equal to
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
var sentinel2 = { sentinel2: "sentinel2" };
var sentinel3 = { sentinel3: "sentinel3" };
function callbackAggregator(times, ultimateCallback) {
var soFar = 0;
return function () {
if (++soFar === times) {
ultimateCallback();
}
};
}
describe("2.2.6: `then` may be called multiple times on the same promise.", function () {
describe("2.2.6.1: If/when `promise` is fulfilled, all respective `onFulfilled` callbacks must execute in the " +
"order of their originating calls to `then`.", function () {
describe("multiple boring fulfillment handlers", function () {
testFulfilled(sentinel, function (promise, done) {
var handler1 = sinon.stub().returns(other);
var handler2 = sinon.stub().returns(other);
var handler3 = sinon.stub().returns(other);
var spy = sinon.spy();
promise.then(handler1, spy);
promise.then(handler2, spy);
promise.then(handler3, spy);
promise.then(function (value) {
assert.strictEqual(value, sentinel);
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
sinon.assert.notCalled(spy);
done();
});
});
});
describe("multiple fulfillment handlers, one of which throws", function () {
testFulfilled(sentinel, function (promise, done) {
var handler1 = sinon.stub().returns(other);
var handler2 = sinon.stub().throws(other);
var handler3 = sinon.stub().returns(other);
var spy = sinon.spy();
promise.then(handler1, spy);
promise.then(handler2, spy).caught(function(){});
promise.then(handler3, spy);
promise.then(function (value) {
assert.strictEqual(value, sentinel);
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
sinon.assert.notCalled(spy);
done();
});
});
});
describe("results in multiple branching chains with their own fulfillment values", function () {
testFulfilled(dummy, function (promise, done) {
var semiDone = callbackAggregator(3, done);
promise.then(function () {
return sentinel;
}).then(function (value) {
assert.strictEqual(value, sentinel);
semiDone();
});
promise.then(function () {
throw sentinel2;
}).then(null, function (reason) {
assert.strictEqual(reason, sentinel2);
semiDone();
});
promise.then(function () {
return sentinel3;
}).then(function (value) {
assert.strictEqual(value, sentinel3);
semiDone();
});
});
});
describe("`onFulfilled` handlers are called in the original order", function () {
testFulfilled(dummy, function (promise, done) {
var handler1 = sinon.spy(function handler1() {});
var handler2 = sinon.spy(function handler2() {});
var handler3 = sinon.spy(function handler3() {});
promise.then(handler1);
promise.then(handler2);
promise.then(handler3);
promise.then(function () {
sinon.assert.callOrder(handler1, handler2, handler3);
done();
});
});
describe("even when one handler is added inside another handler", function () {
testFulfilled(dummy, function (promise, done) {
var handler1 = sinon.spy(function handler1() {});
var handler2 = sinon.spy(function handler2() {});
var handler3 = sinon.spy(function handler3() {});
promise.then(function () {
handler1();
promise.then(handler3);
});
promise.then(handler2);
promise.then(function () {
// Give implementations a bit of extra time to flush their internal queue, if necessary.
setTimeout(function () {
sinon.assert.callOrder(handler1, handler2, handler3);
done();
}, 15);
});
});
});
});
});
describe("2.2.6.2: If/when `promise` is rejected, all respective `onRejected` callbacks must execute in the " +
"order of their originating calls to `then`.", function () {
describe("multiple boring rejection handlers", function () {
testRejected(sentinel, function (promise, done) {
var handler1 = sinon.stub().returns(other);
var handler2 = sinon.stub().returns(other);
var handler3 = sinon.stub().returns(other);
var spy = sinon.spy();
promise.then(spy, handler1);
promise.then(spy, handler2);
promise.then(spy, handler3);
promise.then(null, function (reason) {
assert.strictEqual(reason, sentinel);
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
sinon.assert.notCalled(spy);
done();
});
});
});
describe("multiple rejection handlers, one of which throws", function () {
testRejected(sentinel, function (promise, done) {
var handler1 = sinon.stub().returns(other);
var handler2 = sinon.stub().throws(other);
var handler3 = sinon.stub().returns(other);
var spy = sinon.spy();
promise.then(spy, handler1);
promise.then(spy, handler2).caught(function(){});
promise.then(spy, handler3);
promise.then(null, function (reason) {
assert.strictEqual(reason, sentinel);
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
sinon.assert.notCalled(spy);
done();
});
});
});
describe("results in multiple branching chains with their own fulfillment values", function () {
testRejected(sentinel, function (promise, done) {
var semiDone = callbackAggregator(3, done);
promise.then(null, function () {
return sentinel;
}).then(function (value) {
assert.strictEqual(value, sentinel);
semiDone();
});
promise.then(null, function () {
throw sentinel2;
}).then(null, function (reason) {
assert.strictEqual(reason, sentinel2);
semiDone();
});
promise.then(null, function () {
return sentinel3;
}).then(function (value) {
assert.strictEqual(value, sentinel3);
semiDone();
});
});
});
describe("`onRejected` handlers are called in the original order", function () {
testRejected(dummy, function (promise, done) {
var handler1 = sinon.spy(function handler1() {});
var handler2 = sinon.spy(function handler2() {});
var handler3 = sinon.spy(function handler3() {});
promise.then(null, handler1);
promise.then(null, handler2);
promise.then(null, handler3);
promise.then(null, function () {
sinon.assert.callOrder(handler1, handler2, handler3);
done();
});
});
describe("even when one handler is added inside another handler", function () {
testRejected(dummy, function (promise, done) {
var handler1 = sinon.spy(function handler1() {});
var handler2 = sinon.spy(function handler2() {});
var handler3 = sinon.spy(function handler3() {});
promise.then(null, function () {
handler1();
promise.then(null, handler3);
});
promise.then(null, handler2);
promise.then(null, function () {
// Give implementations a bit of extra time to flush their internal queue, if necessary.
setTimeout(function () {
sinon.assert.callOrder(handler1, handler2, handler3);
done();
}, 15);
});
});
});
});
});
});