mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-01-23 15:18:00 +08:00
c23ba31e17
Thread dropdown Small fixes
2611 lines
75 KiB
JavaScript
2611 lines
75 KiB
JavaScript
"use strict";
|
|
/*jshint newcap: false*/
|
|
/*global Q: true, describe: false, it: false, expect: false, beforeEach: false,
|
|
afterEach: false, require: false, jasmine: false, waitsFor: false,
|
|
runs: false */
|
|
|
|
if (typeof Q === "undefined" && typeof require !== "undefined") {
|
|
// For Node compatibility.
|
|
global.Q = require("../q");
|
|
require("./lib/jasmine-promise");
|
|
}
|
|
|
|
var REASON = "this is not an error, but it might show up in the console";
|
|
|
|
// In browsers that support strict mode, it'll be `undefined`; otherwise, the global.
|
|
var calledAsFunctionThis = (function () { return this; }());
|
|
|
|
afterEach(function () {
|
|
Q.onerror = null;
|
|
});
|
|
|
|
describe("computing sum of integers using promises", function() {
|
|
it("should compute correct result without blowing stack", function () {
|
|
var array = [];
|
|
var iters = 1000;
|
|
for (var i = 1; i <= iters; i++) {
|
|
array.push(i);
|
|
}
|
|
|
|
var pZero = Q.fulfill(0);
|
|
var result = array.reduce(function (promise, nextVal) {
|
|
return promise.then(function (currentVal) {
|
|
return Q.fulfill(currentVal + nextVal);
|
|
});
|
|
}, pZero);
|
|
|
|
return result.then(function (value) {
|
|
expect(value).toEqual(iters * (iters + 1) / 2);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Q function", function () {
|
|
it("should result in a fulfilled promise when given a value", function () {
|
|
expect(Q(5).isFulfilled()).toBe(true);
|
|
});
|
|
|
|
it("should be the identity when given promise", function () {
|
|
var f = Q.fulfill(5);
|
|
var r = Q.reject(new Error("aaargh"));
|
|
var p = Q.promise(function () { });
|
|
|
|
expect(Q(f)).toBe(f);
|
|
expect(Q(r)).toBe(r);
|
|
expect(Q(p)).toBe(p);
|
|
});
|
|
});
|
|
|
|
describe("defer and when", function () {
|
|
|
|
it("resolve before when", function () {
|
|
var turn = 0;
|
|
var deferred = Q.defer();
|
|
deferred.resolve(10);
|
|
var promise = Q.when(deferred.promise, function (value) {
|
|
expect(turn).toEqual(1);
|
|
expect(value).toEqual(10);
|
|
});
|
|
turn++;
|
|
return promise;
|
|
});
|
|
|
|
it("reject before when", function () {
|
|
var turn = 0;
|
|
var deferred = Q.defer();
|
|
deferred.reject(-1);
|
|
var promise = Q.when(deferred.promise, function () {
|
|
expect(true).toBe(false);
|
|
}, function (value) {
|
|
expect(turn).toEqual(1);
|
|
expect(value).toEqual(-1);
|
|
});
|
|
turn++;
|
|
return promise;
|
|
});
|
|
|
|
it("when before resolve", function () {
|
|
var turn = 0;
|
|
var deferred = Q.defer();
|
|
var promise = deferred.promise.then(function (value) {
|
|
expect(turn).toEqual(2);
|
|
expect(value).toEqual(10);
|
|
turn++;
|
|
});
|
|
Q.nextTick(function () {
|
|
expect(turn).toEqual(1);
|
|
deferred.resolve(10);
|
|
turn++;
|
|
});
|
|
turn++;
|
|
return promise;
|
|
});
|
|
|
|
it("when before reject", function () {
|
|
var turn = 0;
|
|
var deferred = Q.defer();
|
|
var promise = deferred.promise.then(function () {
|
|
expect(true).toBe(false);
|
|
}, function (value) {
|
|
expect(turn).toEqual(2);
|
|
expect(value).toEqual(-1);
|
|
turn++;
|
|
});
|
|
Q.nextTick(function () {
|
|
expect(turn).toEqual(1);
|
|
deferred.reject(-1);
|
|
turn++;
|
|
});
|
|
turn++;
|
|
return promise;
|
|
});
|
|
|
|
it("resolves multiple observers", function (done) {
|
|
var nextTurn = false;
|
|
|
|
var resolution = "Taram pam param!";
|
|
var deferred = Q.defer();
|
|
var count = 10;
|
|
var i = 0;
|
|
|
|
function resolve(value) {
|
|
i++;
|
|
expect(value).toBe(resolution);
|
|
expect(nextTurn).toBe(true);
|
|
if (i === count) {
|
|
done();
|
|
}
|
|
}
|
|
|
|
while (++i <= count) {
|
|
Q.when(deferred.promise, resolve);
|
|
}
|
|
|
|
deferred.resolve(resolution);
|
|
i = 0;
|
|
nextTurn = true;
|
|
});
|
|
|
|
it("observers called even after throw", function () {
|
|
var threw = false;
|
|
var deferred = Q.defer();
|
|
Q.when(deferred.promise, function () {
|
|
threw = true;
|
|
throw new Error(REASON);
|
|
});
|
|
var promise = Q.when(deferred.promise, function (value) {
|
|
expect(value).toEqual(10);
|
|
}, function () {
|
|
expect("not").toEqual("here");
|
|
});
|
|
deferred.resolve(10);
|
|
return promise;
|
|
});
|
|
|
|
it("returns `undefined` from the deferred's methods", function () {
|
|
expect(Q.defer().resolve()).toBe(undefined);
|
|
expect(Q.defer().reject()).toBe(undefined);
|
|
});
|
|
|
|
});
|
|
|
|
describe("always next tick", function () {
|
|
|
|
it("generated by `resolve`", function () {
|
|
var turn = 0;
|
|
var promise = Q.when(Q(), function () {
|
|
expect(turn).toEqual(1);
|
|
});
|
|
turn++;
|
|
return promise;
|
|
});
|
|
|
|
it("generated by `reject`", function () {
|
|
var turn = 0;
|
|
var promise = Q.when(Q.reject(), function () {
|
|
expect(true).toBe(false);
|
|
}, function () {
|
|
expect(turn).toEqual(1);
|
|
});
|
|
turn++;
|
|
return promise;
|
|
});
|
|
|
|
it("allows overriding global nextTick", function () {
|
|
var spy = jasmine.createSpy();
|
|
spyOn(Q, 'nextTick').andCallFake(function immediateTick(task){
|
|
task();
|
|
});
|
|
|
|
Q.when(Q(), spy);
|
|
|
|
expect(spy).toHaveBeenCalled();
|
|
expect(Q.nextTick).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("progress", function () {
|
|
|
|
it("calls a single progress listener", function () {
|
|
var progressed = false;
|
|
var deferred = Q.defer();
|
|
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
expect(progressed).toBe(true);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function () {
|
|
progressed = true;
|
|
}
|
|
);
|
|
|
|
deferred.notify();
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("calls multiple progress listeners", function () {
|
|
var progressed1 = false;
|
|
var progressed2 = false;
|
|
var deferred = Q.defer();
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
expect(progressed1).toBe(true);
|
|
expect(progressed2).toBe(true);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function () {
|
|
progressed1 = true;
|
|
}
|
|
);
|
|
Q.when(deferred.promise, null, null, function () {
|
|
progressed2 = true;
|
|
});
|
|
|
|
deferred.notify();
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("calls all progress listeners even if one throws", function () {
|
|
var progressed1 = false;
|
|
var progressed2 = false;
|
|
var progressed3 = false;
|
|
var deferred = Q.defer();
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
expect(progressed1).toBe(true);
|
|
expect(progressed2).toBe(true);
|
|
expect(progressed3).toBe(true);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function () {
|
|
progressed1 = true;
|
|
}
|
|
);
|
|
|
|
Q.onerror = function () { };
|
|
|
|
Q.when(deferred.promise, null, null, function () {
|
|
progressed2 = true;
|
|
throw new Error("just a test, ok if it shows up in the console");
|
|
});
|
|
Q.when(deferred.promise, null, null, function () {
|
|
progressed3 = true;
|
|
});
|
|
|
|
deferred.notify();
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("calls the progress listener even if later rejected", function () {
|
|
var progressed = false;
|
|
var deferred = Q.defer();
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function () {
|
|
expect(progressed).toEqual(true);
|
|
},
|
|
function () {
|
|
progressed = true;
|
|
}
|
|
);
|
|
|
|
deferred.notify();
|
|
deferred.reject();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("calls the progress listener with the notify values", function () {
|
|
var progressValues = [];
|
|
var desiredProgressValues = [{}, {}, "foo", 5];
|
|
var deferred = Q.defer();
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
for (var i = 0; i < desiredProgressValues.length; ++i) {
|
|
var desired = desiredProgressValues[i];
|
|
var actual = progressValues[i];
|
|
expect(actual).toBe(desired);
|
|
}
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (value) {
|
|
progressValues.push(value);
|
|
}
|
|
);
|
|
|
|
for (var i = 0; i < desiredProgressValues.length; ++i) {
|
|
deferred.notify(desiredProgressValues[i]);
|
|
}
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("does not call the progress listener if notify is called after fulfillment", function () {
|
|
var deferred = Q.defer();
|
|
var called = false;
|
|
|
|
Q.when(deferred.promise, null, null, function () {
|
|
called = true;
|
|
});
|
|
|
|
deferred.resolve();
|
|
deferred.notify();
|
|
|
|
return Q.delay(10).then(function () {
|
|
expect(called).toBe(false);
|
|
});
|
|
});
|
|
|
|
it("does not call the progress listener if notify is called after rejection", function () {
|
|
var deferred = Q.defer();
|
|
var called = false;
|
|
|
|
Q.when(deferred.promise, null, null, function () {
|
|
called = true;
|
|
});
|
|
|
|
deferred.reject();
|
|
deferred.notify();
|
|
|
|
return Q.delay(10).then(function () {
|
|
expect(called).toBe(false);
|
|
});
|
|
});
|
|
|
|
it("should not save and re-emit progress notifications", function () {
|
|
var deferred = Q.defer();
|
|
var progressValues = [];
|
|
|
|
deferred.notify(1);
|
|
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
expect(progressValues).toEqual([2]);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (progressValue) {
|
|
progressValues.push(progressValue);
|
|
}
|
|
);
|
|
|
|
deferred.notify(2);
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should allow attaching progress listeners w/ .progress", function () {
|
|
var progressed = false;
|
|
var deferred = Q.defer();
|
|
|
|
deferred.promise.progress(function () {
|
|
progressed = true;
|
|
});
|
|
|
|
deferred.notify();
|
|
deferred.resolve();
|
|
|
|
return deferred.promise;
|
|
});
|
|
|
|
it("should allow attaching progress listeners w/ Q.progress", function () {
|
|
var progressed = false;
|
|
var deferred = Q.defer();
|
|
|
|
Q.progress(deferred.promise, function () {
|
|
progressed = true;
|
|
});
|
|
|
|
deferred.notify();
|
|
deferred.resolve();
|
|
|
|
return deferred.promise;
|
|
});
|
|
|
|
it("should call the progress listener with undefined context", function () {
|
|
var progressed = false;
|
|
var progressContext = {};
|
|
var deferred = Q.defer();
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
expect(progressed).toBe(true);
|
|
expect(progressContext).toBe(calledAsFunctionThis);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function () {
|
|
progressed = true;
|
|
progressContext = this;
|
|
}
|
|
);
|
|
|
|
deferred.notify();
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should forward only the first notify argument to listeners", function () {
|
|
var progressValueArrays = [];
|
|
var deferred = Q.defer();
|
|
|
|
var promise = Q.when(
|
|
deferred.promise,
|
|
function () {
|
|
expect(progressValueArrays).toEqual([[1], [2], [4]]);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function () {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
progressValueArrays.push(args);
|
|
}
|
|
);
|
|
|
|
deferred.notify(1);
|
|
deferred.notify(2, 3);
|
|
deferred.notify(4, 5, 6);
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should work with .then as well", function () {
|
|
var progressed = false;
|
|
var deferred = Q.defer();
|
|
|
|
var promise = deferred.promise.then(
|
|
function () {
|
|
expect(progressed).toBe(true);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function () {
|
|
progressed = true;
|
|
}
|
|
);
|
|
|
|
deferred.notify();
|
|
deferred.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should re-throw all errors thrown by listeners to Q.onerror", function () {
|
|
var theError = new Error("boo!");
|
|
|
|
var def = Q.defer();
|
|
def.promise.progress(function () {
|
|
throw theError;
|
|
});
|
|
|
|
var deferred = Q.defer();
|
|
Q.onerror = function (error) {
|
|
expect(error).toBe(theError);
|
|
deferred.resolve();
|
|
};
|
|
Q.delay(100).then(deferred.reject);
|
|
|
|
def.notify();
|
|
|
|
return deferred.promise;
|
|
});
|
|
});
|
|
|
|
describe("promises for objects", function () {
|
|
|
|
describe("get", function () {
|
|
|
|
it("fulfills a promise", function () {
|
|
var deferred = Q.defer();
|
|
deferred.resolve({a: 1});
|
|
return deferred.promise.get("a")
|
|
.then(function (a) {
|
|
expect(a).toBe(1);
|
|
});
|
|
});
|
|
|
|
it("propagates a rejection", function () {
|
|
var exception = new Error("boo!");
|
|
return Q.fcall(function () {
|
|
throw exception;
|
|
})
|
|
.get("a")
|
|
.then(function () {
|
|
expect("be").toBe("not to be");
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("set", function () {
|
|
|
|
it("fulfills a promise", function () {
|
|
var object = {};
|
|
return Q(object)
|
|
.set("a", 1)
|
|
.then(function (result) {
|
|
expect(result).toBe(undefined);
|
|
expect(object.a).toBe(1);
|
|
});
|
|
});
|
|
|
|
it("propagates a rejection", function () {
|
|
var exception = new Error("Gah!");
|
|
return Q.reject(exception)
|
|
.set("a", 1)
|
|
.then(function () {
|
|
expect("frozen over").toBe("quite warm");
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("del", function () {
|
|
|
|
it("fulfills a promise", function () {
|
|
var object = {a: 10};
|
|
return Q.fcall(function () {
|
|
return object;
|
|
})
|
|
.del("a")
|
|
.then(function (result) {
|
|
expect("a" in object).toBe(false);
|
|
expect(result).toBe(void 0);
|
|
}, function () {
|
|
expect("up").toBe("down");
|
|
});
|
|
});
|
|
|
|
it("propagates a rejection", function () {
|
|
var exception = new Error("hah-hah");
|
|
return Q.fcall(function () {
|
|
throw exception;
|
|
})
|
|
.del("a")
|
|
.then(function () {
|
|
expect(true).toBe(false);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("post", function () {
|
|
|
|
it("fulfills a promise", function () {
|
|
var subject = {
|
|
a: function a(value) {
|
|
this._a = value;
|
|
return 1 + value;
|
|
}
|
|
};
|
|
return Q.when(Q.post(subject, "a", [1]), function (two) {
|
|
expect(subject._a).toBe(1);
|
|
expect(two).toBe(2);
|
|
});
|
|
});
|
|
|
|
it("works as apply when given no name", function () {
|
|
return Q(function (a, b, c) {
|
|
return a + b + c;
|
|
})
|
|
.post(undefined, [1, 2, 3])
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("send", function () {
|
|
|
|
it("fulfills a promise", function () {
|
|
var foo;
|
|
var subject = {
|
|
foo: function (_bar) {
|
|
return _bar;
|
|
},
|
|
bar: function (_foo, _bar) {
|
|
foo = _foo;
|
|
return this.foo(_bar);
|
|
}
|
|
};
|
|
return Q.send(subject, "bar", 1, 2)
|
|
.then(function (two) {
|
|
expect(foo).toEqual(1);
|
|
expect(two).toEqual(2);
|
|
});
|
|
});
|
|
|
|
it("is rejected for undefined method", function () {
|
|
var subject = {};
|
|
return Q(subject)
|
|
.send("foo")
|
|
.then(function () {
|
|
expect("here").toEqual("not here");
|
|
}, function () {
|
|
});
|
|
});
|
|
|
|
it("is rejected for undefined object", function () {
|
|
return Q()
|
|
.send("foo")
|
|
.then(function () {
|
|
expect("here").toEqual("not here");
|
|
}, function () {
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("keys", function () {
|
|
|
|
function Klass (a, b) {
|
|
this.a = a;
|
|
this.b = b;
|
|
}
|
|
Klass.prototype.notOwn = 1;
|
|
|
|
it("fulfills a promise", function () {
|
|
return Q.keys(new Klass(10, 20))
|
|
.then(function (keys) {
|
|
expect(keys.sort()).toEqual(["a", "b"]);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("promises for functions", function () {
|
|
|
|
describe("fapply", function () {
|
|
it("fulfills a promise using arguments", function () {
|
|
return Q(function (a, b, c) {
|
|
return a + b + c;
|
|
})
|
|
.fapply([1, 2, 3])
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("fcall", function () {
|
|
it("fulfills a promise using arguments", function () {
|
|
return Q(function (a, b, c) {
|
|
return a + b + c;
|
|
})
|
|
.fcall(1, 2, 3)
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("fbind", function () {
|
|
|
|
it("accepts a promise for a function", function () {
|
|
return Q.fbind(Q(function (high, low) {
|
|
return high - low;
|
|
}))
|
|
(2, 1)
|
|
.then(function (difference) {
|
|
expect(difference).toEqual(1);
|
|
});
|
|
});
|
|
|
|
it("chains partial application on a promise for a function", function () {
|
|
return Q(function (a, b) {
|
|
return a * b;
|
|
})
|
|
.fbind(2)(3)
|
|
.then(function (product) {
|
|
expect(product).toEqual(6);
|
|
});
|
|
});
|
|
|
|
it("returns a fulfilled promise", function () {
|
|
var result = {};
|
|
var bound = Q.fbind(function () {
|
|
return result;
|
|
});
|
|
return bound()
|
|
.then(function (_result) {
|
|
expect(_result).toBe(result);
|
|
});
|
|
});
|
|
|
|
it("returns a rejected promise from a thrown error", function () {
|
|
var exception = new Error("Boo!");
|
|
var bound = Q.fbind(function () {
|
|
throw exception;
|
|
});
|
|
return bound()
|
|
.then(function () {
|
|
expect("flying pigs").toBe("swillin' pigs");
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
it("passes arguments through", function () {
|
|
var x = {}, y = {};
|
|
var bound = Q.fbind(function (a, b) {
|
|
expect(a).toBe(x);
|
|
expect(b).toBe(y);
|
|
});
|
|
return bound(x, y);
|
|
});
|
|
|
|
it("passes and also partially applies arguments", function () {
|
|
var x = {}, y = {};
|
|
var bound = Q.fbind(function (a, b) {
|
|
expect(a).toBe(x);
|
|
expect(b).toBe(y);
|
|
}, x);
|
|
return bound(y);
|
|
});
|
|
|
|
it("doesn't bind `this`", function () {
|
|
var theThis = { me: "this" };
|
|
var bound = Q.fbind(function () {
|
|
expect(this).toBe(theThis);
|
|
});
|
|
|
|
return bound.call(theThis);
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("inspect", function () {
|
|
|
|
it("for a fulfilled promise", function () {
|
|
expect(Q(10).inspect()).toEqual({
|
|
state: "fulfilled",
|
|
value: 10
|
|
});
|
|
});
|
|
|
|
it("for a rejected promise", function () {
|
|
var error = new Error("In your face.");
|
|
var rejected = Q.reject(error);
|
|
expect(rejected.inspect()).toEqual({
|
|
state: "rejected",
|
|
reason: error
|
|
});
|
|
});
|
|
|
|
it("for a pending, unresolved promise", function () {
|
|
var pending = Q.defer().promise;
|
|
expect(pending.inspect()).toEqual({ state: "pending" });
|
|
});
|
|
|
|
it("for a promise resolved to a rejected promise", function () {
|
|
var deferred = Q.defer();
|
|
var error = new Error("Rejected!");
|
|
var rejected = Q.reject(error);
|
|
deferred.resolve(rejected);
|
|
|
|
expect(deferred.promise.inspect()).toEqual({
|
|
state: "rejected",
|
|
reason: error
|
|
});
|
|
});
|
|
|
|
it("for a promise resolved to a fulfilled promise", function () {
|
|
var deferred = Q.defer();
|
|
var fulfilled = Q(10);
|
|
deferred.resolve(fulfilled);
|
|
|
|
expect(deferred.promise.inspect()).toEqual({
|
|
state: "fulfilled",
|
|
value: 10
|
|
});
|
|
});
|
|
|
|
it("for a promise resolved to a pending promise", function () {
|
|
var a = Q.defer();
|
|
var b = Q.defer();
|
|
a.resolve(b.promise);
|
|
|
|
expect(a.promise.inspect()).toEqual({ state: "pending" });
|
|
});
|
|
|
|
});
|
|
|
|
describe("promise states", function () {
|
|
|
|
it("of fulfilled value", function () {
|
|
expect(Q.isFulfilled(void 0)).toBe(true);
|
|
expect(Q.isRejected(false)).toBe(false);
|
|
expect(Q.isPending(true)).toBe(false);
|
|
});
|
|
|
|
it("of fulfillment", function () {
|
|
var promise = Q(10);
|
|
expect(Q.isFulfilled(promise)).toBe(true);
|
|
expect(promise.isFulfilled()).toBe(true);
|
|
expect(Q.isRejected(promise)).toBe(false);
|
|
expect(promise.isRejected()).toBe(false);
|
|
expect(Q.isPending(promise)).toBe(false);
|
|
expect(promise.isPending()).toBe(false);
|
|
});
|
|
|
|
it("of rejection", function () {
|
|
var error = new Error("Oh, snap.");
|
|
var promise = Q.reject(error);
|
|
expect(promise.isFulfilled()).toBe(false);
|
|
expect(promise.isRejected()).toBe(true);
|
|
expect(promise.isPending()).toBe(false);
|
|
});
|
|
|
|
it("of rejection with a falsy value", function () {
|
|
var promise = Q.reject(undefined);
|
|
expect(promise.isFulfilled()).toBe(false);
|
|
expect(promise.isRejected()).toBe(true);
|
|
expect(promise.isPending()).toBe(false);
|
|
});
|
|
|
|
it("of deferred", function () {
|
|
var deferred = Q.defer();
|
|
var promise = deferred.promise;
|
|
expect(promise.isFulfilled()).toBe(false);
|
|
expect(promise.isRejected()).toBe(false);
|
|
expect(promise.isPending()).toBe(true);
|
|
});
|
|
|
|
it("of deferred rejection", function () {
|
|
var deferred = Q.defer();
|
|
var rejection = Q.reject(new Error("Rejected!"));
|
|
deferred.resolve(rejection);
|
|
var promise = deferred.promise;
|
|
expect(promise.isFulfilled()).toBe(false);
|
|
expect(promise.isRejected()).toBe(true);
|
|
expect(promise.isPending()).toBe(false);
|
|
});
|
|
|
|
it("of deferred fulfillment", function () {
|
|
var deferred = Q.defer();
|
|
deferred.resolve(10);
|
|
var promise = deferred.promise;
|
|
expect(promise.isFulfilled()).toBe(true);
|
|
expect(promise.isRejected()).toBe(false);
|
|
expect(promise.isPending()).toBe(false);
|
|
});
|
|
|
|
it("of deferred deferred", function () {
|
|
var a = Q.defer();
|
|
var b = Q.defer();
|
|
a.resolve(b.promise);
|
|
var promise = a.promise;
|
|
expect(promise.isFulfilled()).toBe(false);
|
|
expect(promise.isRejected()).toBe(false);
|
|
expect(promise.isPending()).toBe(true);
|
|
});
|
|
|
|
it("of isFulfilled side effects", function () {
|
|
var deferred = Q.defer();
|
|
var finished = false;
|
|
|
|
waitsFor(function () {
|
|
return finished;
|
|
});
|
|
|
|
var parentPromise = deferred.promise;
|
|
|
|
var childPromise = parentPromise.then(function () {
|
|
expect(parentPromise.isFulfilled()).toBe(true);
|
|
expect(childPromise.isFulfilled()).toBe(false);
|
|
|
|
return parentPromise.then(function (value) {
|
|
finished = true;
|
|
return value + 1;
|
|
});
|
|
});
|
|
|
|
deferred.resolve(1);
|
|
|
|
runs(function () {
|
|
expect(childPromise.isPending()).toBe(false);
|
|
expect(childPromise.isRejected()).toBe(false);
|
|
expect(childPromise.isFulfilled()).toBe(true);
|
|
expect(childPromise.inspect().value).toBe(2);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("propagation", function () {
|
|
|
|
it("propagate through then with no callback", function () {
|
|
return Q(10)
|
|
.then()
|
|
.then(function (ten) {
|
|
expect(ten).toBe(10);
|
|
});
|
|
});
|
|
|
|
it("propagate through then with modifying callback", function () {
|
|
return Q(10)
|
|
.then(function (ten) {
|
|
return ten + 10;
|
|
})
|
|
.then(function (twen) {
|
|
expect(twen).toBe(20);
|
|
});
|
|
});
|
|
|
|
it("errback recovers from exception", function () {
|
|
var error = new Error("Bah!");
|
|
return Q.reject(error)
|
|
.then(null, function (_error) {
|
|
expect(_error).toBe(error);
|
|
return 10;
|
|
})
|
|
.then(function (value) {
|
|
expect(value).toBe(10);
|
|
});
|
|
});
|
|
|
|
it("rejection propagates through then with no errback", function () {
|
|
var error = new Error("Foolish mortals!");
|
|
return Q.reject(error)
|
|
.then()
|
|
.then(null, function (_error) {
|
|
expect(_error).toBe(error);
|
|
});
|
|
});
|
|
|
|
it("rejection intercepted and rethrown", function () {
|
|
var error = new Error("Foolish mortals!");
|
|
var nextError = new Error("Silly humans!");
|
|
return Q.reject(error)
|
|
.fail(function () {
|
|
throw nextError;
|
|
})
|
|
.then(null, function (_error) {
|
|
expect(_error).toBe(nextError);
|
|
});
|
|
});
|
|
|
|
it("resolution is forwarded through deferred promise", function () {
|
|
var a = Q.defer();
|
|
var b = Q.defer();
|
|
a.resolve(b.promise);
|
|
b.resolve(10);
|
|
return a.promise.then(function (eh) {
|
|
expect(eh).toEqual(10);
|
|
});
|
|
});
|
|
|
|
it("should propagate progress by default", function () {
|
|
var d = Q.defer();
|
|
|
|
var progressValues = [];
|
|
var promise = d.promise
|
|
.then()
|
|
.then(
|
|
function () {
|
|
expect(progressValues).toEqual([1]);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (progressValue) {
|
|
progressValues.push(progressValue);
|
|
}
|
|
);
|
|
|
|
d.notify(1);
|
|
d.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should allow translation of progress in the progressback", function () {
|
|
var d = Q.defer();
|
|
|
|
var progressValues = [];
|
|
var promise = d.promise
|
|
.progress(function (p) {
|
|
return p + 5;
|
|
})
|
|
.then(
|
|
function () {
|
|
expect(progressValues).toEqual([10]);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (progressValue) {
|
|
progressValues.push(progressValue);
|
|
}
|
|
);
|
|
|
|
d.notify(5);
|
|
d.resolve();
|
|
|
|
return promise;
|
|
});
|
|
|
|
|
|
it("should stop progress propagation if an error is thrown", function () {
|
|
var def = Q.defer();
|
|
var p2 = def.promise.progress(function () {
|
|
throw new Error("boo!");
|
|
});
|
|
|
|
Q.onerror = function () { /* just swallow it for this test */ };
|
|
|
|
var progressValues = [];
|
|
var result = p2.then(
|
|
function () {
|
|
expect(progressValues).toEqual([]);
|
|
},
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (progressValue) {
|
|
progressValues.push(progressValue);
|
|
}
|
|
);
|
|
|
|
def.notify();
|
|
def.resolve();
|
|
return result;
|
|
});
|
|
});
|
|
|
|
describe("all", function () {
|
|
it("fulfills when passed an empty array", function () {
|
|
return Q.all([]);
|
|
});
|
|
|
|
it("rejects after any constituent promise is rejected", function () {
|
|
var toResolve = Q.defer(); // never resolve
|
|
var toReject = Q.defer();
|
|
var promises = [toResolve.promise, toReject.promise];
|
|
var promise = Q.all(promises);
|
|
|
|
toReject.reject(new Error("Rejected"));
|
|
|
|
return Q.delay(250)
|
|
.then(function () {
|
|
expect(promise.isRejected()).toBe(true);
|
|
})
|
|
.timeout(1000);
|
|
});
|
|
|
|
it("resolves foreign thenables", function () {
|
|
var normal = Q(1);
|
|
var foreign = { then: function (f) { f(2); } };
|
|
|
|
return Q.all([normal, foreign])
|
|
.then(function (result) {
|
|
expect(result).toEqual([1, 2]);
|
|
});
|
|
});
|
|
|
|
it("fulfills when passed an sparse array", function () {
|
|
var toResolve = Q.defer();
|
|
var promises = [];
|
|
promises[0] = Q(0);
|
|
promises[2] = toResolve.promise;
|
|
var promise = Q.all(promises);
|
|
|
|
toResolve.resolve(2);
|
|
|
|
return promise.then(function (result) {
|
|
expect(result).toEqual([0, void 0, 2]);
|
|
});
|
|
});
|
|
|
|
it("modifies the input array", function () {
|
|
var input = [Q(0), Q(1)];
|
|
|
|
return Q.all(input).then(function (result) {
|
|
expect(result).toBe(input);
|
|
expect(input).toEqual([0, 1]);
|
|
});
|
|
});
|
|
|
|
it("sends { index, value } progress updates", function () {
|
|
var deferred1 = Q.defer();
|
|
var deferred2 = Q.defer();
|
|
|
|
var progressValues = [];
|
|
|
|
Q.delay(50).then(function () {
|
|
deferred1.notify("a");
|
|
});
|
|
Q.delay(100).then(function () {
|
|
deferred2.notify("b");
|
|
deferred2.resolve();
|
|
});
|
|
Q.delay(150).then(function () {
|
|
deferred1.notify("c");
|
|
deferred1.resolve();
|
|
});
|
|
|
|
return Q.all([deferred1.promise, deferred2.promise]).then(
|
|
function () {
|
|
expect(progressValues).toEqual([
|
|
{ index: 0, value: "a" },
|
|
{ index: 1, value: "b" },
|
|
{ index: 0, value: "c" }
|
|
]);
|
|
},
|
|
undefined,
|
|
function (progressValue) {
|
|
progressValues.push(progressValue);
|
|
}
|
|
)
|
|
});
|
|
|
|
});
|
|
|
|
describe("allSettled", function () {
|
|
it("works on an empty array", function () {
|
|
return Q.allSettled([])
|
|
.then(function (snapshots) {
|
|
expect(snapshots).toEqual([]);
|
|
});
|
|
});
|
|
|
|
it("deals with a mix of non-promises and promises", function () {
|
|
return Q.allSettled([1, Q(2), Q.reject(3)])
|
|
.then(function (snapshots) {
|
|
expect(snapshots).toEqual([
|
|
{ state: "fulfilled", value: 1 },
|
|
{ state: "fulfilled", value: 2 },
|
|
{ state: "rejected", reason: 3 }
|
|
]);
|
|
});
|
|
});
|
|
|
|
it("is settled after every constituent promise is settled", function () {
|
|
var toFulfill = Q.defer();
|
|
var toReject = Q.defer();
|
|
var promises = [toFulfill.promise, toReject.promise];
|
|
var fulfilled;
|
|
var rejected;
|
|
|
|
Q.fcall(function () {
|
|
toReject.reject();
|
|
rejected = true;
|
|
})
|
|
.delay(15)
|
|
.then(function () {
|
|
toFulfill.resolve();
|
|
fulfilled = true;
|
|
});
|
|
|
|
return Q.allSettled(promises)
|
|
.then(function () {
|
|
expect(fulfilled).toBe(true);
|
|
expect(rejected).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("does not modify the input array", function () {
|
|
var input = [1, Q(2), Q.reject(3)];
|
|
|
|
return Q.allSettled(input)
|
|
.then(function (snapshots) {
|
|
expect(snapshots).not.toBe(input);
|
|
expect(snapshots).toEqual([
|
|
{ state: "fulfilled", value: 1 },
|
|
{ state: "fulfilled", value: 2 },
|
|
{ state: "rejected", reason: 3 }
|
|
]);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("spread", function () {
|
|
|
|
it("spreads values across arguments", function () {
|
|
return Q.spread([1, 2, 3], function (a, b) {
|
|
expect(b).toBe(2);
|
|
});
|
|
});
|
|
|
|
it("spreads promises for arrays across arguments", function () {
|
|
return Q([Q(10)])
|
|
.spread(function (value) {
|
|
expect(value).toEqual(10);
|
|
});
|
|
});
|
|
|
|
it("spreads arrays of promises across arguments", function () {
|
|
var deferredA = Q.defer();
|
|
var deferredB = Q.defer();
|
|
|
|
var promise = Q.spread([deferredA.promise, deferredB.promise],
|
|
function (a, b) {
|
|
expect(a).toEqual(10);
|
|
expect(b).toEqual(20);
|
|
});
|
|
|
|
Q.delay(5).then(function () {
|
|
deferredA.resolve(10);
|
|
});
|
|
Q.delay(10).then(function () {
|
|
deferredB.resolve(20);
|
|
});
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("calls the errback when given a rejected promise", function () {
|
|
var err = new Error();
|
|
return Q.spread([Q(10), Q.reject(err)],
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (actual) {
|
|
expect(actual).toBe(err);
|
|
}
|
|
);
|
|
});
|
|
|
|
});
|
|
|
|
describe("fin", function () {
|
|
|
|
var exception1 = new Error("boo!");
|
|
var exception2 = new TypeError("evil!");
|
|
|
|
describe("when the promise is fulfilled", function () {
|
|
|
|
it("should call the callback", function () {
|
|
var called = false;
|
|
|
|
return Q("foo")
|
|
.fin(function () {
|
|
called = true;
|
|
})
|
|
.then(function () {
|
|
expect(called).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("should fulfill with the original value", function () {
|
|
return Q("foo")
|
|
.fin(function () {
|
|
return "bar";
|
|
})
|
|
.then(function (result) {
|
|
expect(result).toBe("foo");
|
|
});
|
|
});
|
|
|
|
describe("when the callback returns a promise", function () {
|
|
|
|
describe("that is fulfilled", function () {
|
|
it("should fulfill with the original reason after that promise resolves", function () {
|
|
var promise = Q.delay(250);
|
|
|
|
return Q("foo")
|
|
.fin(function () {
|
|
return promise;
|
|
})
|
|
.then(function (result) {
|
|
expect(Q.isPending(promise)).toBe(false);
|
|
expect(result).toBe("foo");
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("that is rejected", function () {
|
|
it("should reject with this new rejection reason", function () {
|
|
return Q("foo")
|
|
.fin(function () {
|
|
return Q.reject(exception1);
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception1);
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("when the callback throws an exception", function () {
|
|
it("should reject with this new exception", function () {
|
|
return Q("foo")
|
|
.fin(function () {
|
|
throw exception1;
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception1);
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("when the promise is rejected", function () {
|
|
|
|
it("should call the callback", function () {
|
|
var called = false;
|
|
|
|
return Q.reject(exception1)
|
|
.fin(function () {
|
|
called = true;
|
|
})
|
|
.then(function () {
|
|
expect(called).toBe(true);
|
|
}, function () {
|
|
expect(called).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("should reject with the original reason", function () {
|
|
return Q.reject(exception1)
|
|
.fin(function () {
|
|
return "bar";
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception1);
|
|
});
|
|
});
|
|
|
|
describe("when the callback returns a promise", function () {
|
|
|
|
describe("that is fulfilled", function () {
|
|
it("should reject with the original reason after that promise resolves", function () {
|
|
var promise = Q.delay(250);
|
|
|
|
return Q.reject(exception1)
|
|
.fin(function () {
|
|
return promise;
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception1);
|
|
expect(Q.isPending(promise)).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("that is rejected", function () {
|
|
it("should reject with the new reason", function () {
|
|
return Q.reject(exception1)
|
|
.fin(function () {
|
|
return Q.reject(exception2);
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception2);
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("when the callback throws an exception", function () {
|
|
it("should reject with this new exception", function () {
|
|
return Q.reject(exception1)
|
|
.fin(function () {
|
|
throw exception2;
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception2);
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
// Almost like "fin"
|
|
describe("tap", function () {
|
|
var exception1 = new Error("boo!");
|
|
|
|
describe("when the promise is fulfilled", function () {
|
|
it("should call the callback", function () {
|
|
var called = false;
|
|
return Q("foo")
|
|
.tap(function () {
|
|
called = true;
|
|
})
|
|
.then(function () {
|
|
expect(called).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("should fulfill with the original value", function () {
|
|
return Q("foo")
|
|
.tap(function () {
|
|
return "bar";
|
|
})
|
|
.then(function (result) {
|
|
expect(result).toBe("foo");
|
|
});
|
|
});
|
|
|
|
describe("when the callback returns a promise", function () {
|
|
describe("that is fulfilled", function () {
|
|
it("should fulfill with the original reason after that promise resolves", function () {
|
|
var promise = Q.delay(250);
|
|
|
|
return Q("foo")
|
|
.tap(function () {
|
|
return promise;
|
|
})
|
|
.then(function (result) {
|
|
expect(Q.isPending(promise)).toBe(false);
|
|
expect(result).toBe("foo");
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("that is rejected", function () {
|
|
it("should reject with this new rejection reason", function () {
|
|
return Q("foo")
|
|
.tap(function () {
|
|
return Q.reject(exception1);
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception1);
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("when the callback throws an exception", function () {
|
|
it("should reject with this new exception", function () {
|
|
return Q("foo")
|
|
.tap(function () {
|
|
throw exception1;
|
|
})
|
|
.then(function () {
|
|
expect(false).toBe(true);
|
|
},
|
|
function (exception) {
|
|
expect(exception).toBe(exception1);
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("when the promise is rejected", function () {
|
|
it("should not call the callback", function () {
|
|
var called = false;
|
|
|
|
return Q.reject(exception1)
|
|
.tap(function () {
|
|
called = true;
|
|
})
|
|
.then(function () {
|
|
expect(called).toBe(false);
|
|
}, function () {
|
|
expect(called).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
describe("done", function () {
|
|
describe("when the promise is fulfilled", function () {
|
|
describe("and the callback does not throw", function () {
|
|
it("should call the callback and return nothing", function () {
|
|
var called = false;
|
|
|
|
var promise = Q();
|
|
|
|
var returnValue = promise.done(function () {
|
|
called = true;
|
|
});
|
|
|
|
return promise.fail(function () { }).fin(function () {
|
|
expect(called).toBe(true);
|
|
expect(returnValue).toBe(undefined);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("and the callback throws", function () {
|
|
it("should rethrow that error in the next turn and return nothing", function () {
|
|
var turn = 0;
|
|
Q.nextTick(function () {
|
|
++turn;
|
|
});
|
|
|
|
var returnValue = Q().done(
|
|
function () {
|
|
throw "foo";
|
|
}
|
|
);
|
|
|
|
var deferred = Q.defer();
|
|
Q.onerror = function (error) {
|
|
expect(turn).toBe(1);
|
|
expect(error).toBe("foo");
|
|
expect(returnValue).toBe(undefined);
|
|
deferred.resolve();
|
|
};
|
|
Q.delay(100).then(deferred.reject);
|
|
|
|
return deferred.promise;
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when the promise is rejected", function () {
|
|
describe("and the errback handles it", function () {
|
|
it("should call the errback and return nothing", function () {
|
|
var called = false;
|
|
|
|
var promise = Q.reject(new Error());
|
|
|
|
var returnValue = promise.done(
|
|
function () { },
|
|
function () {
|
|
called = true;
|
|
}
|
|
);
|
|
|
|
return promise.fail(function () { }).fin(function () {
|
|
expect(called).toBe(true);
|
|
expect(returnValue).toBe(undefined);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("and the errback throws", function () {
|
|
it("should rethrow that error in the next turn and return nothing", function () {
|
|
var turn = 0;
|
|
Q.nextTick(function () {
|
|
++turn;
|
|
});
|
|
|
|
var returnValue = Q.reject("bar").done(
|
|
null,
|
|
function () {
|
|
throw "foo";
|
|
}
|
|
);
|
|
|
|
var deferred = Q.defer();
|
|
Q.onerror = function (error) {
|
|
expect(turn).toBe(1);
|
|
expect(error).toBe("foo");
|
|
expect(returnValue).toBe(undefined);
|
|
deferred.resolve();
|
|
};
|
|
Q.delay(100).then(deferred.reject);
|
|
|
|
return deferred.promise;
|
|
});
|
|
});
|
|
|
|
describe("and there is no errback", function () {
|
|
it("should throw the original error in the next turn", function () {
|
|
var turn = 0;
|
|
Q.nextTick(function () {
|
|
++turn;
|
|
});
|
|
|
|
var returnValue = Q.reject("bar").done();
|
|
|
|
var deferred = Q.defer();
|
|
Q.onerror = function (error) {
|
|
expect(turn).toBe(1);
|
|
expect(error).toBe("bar");
|
|
expect(returnValue).toBe(undefined);
|
|
deferred.resolve();
|
|
};
|
|
Q.delay(10).then(deferred.reject);
|
|
|
|
return deferred.promise;
|
|
});
|
|
});
|
|
});
|
|
|
|
it("should attach a progress listener", function () {
|
|
var deferred = Q.defer();
|
|
|
|
var spy = jasmine.createSpy();
|
|
deferred.promise.done(null, null, spy);
|
|
|
|
deferred.notify(10);
|
|
deferred.resolve();
|
|
|
|
return deferred.promise.then(function () {
|
|
expect(spy).toHaveBeenCalledWith(10);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("timeout", function () {
|
|
it("should do nothing if the promise fulfills quickly", function () {
|
|
return Q.delay(10).timeout(200);
|
|
});
|
|
|
|
it("should do nothing if the promise rejects quickly", function () {
|
|
var goodError = new Error("haha!");
|
|
return Q.delay(10)
|
|
.then(function () {
|
|
throw goodError;
|
|
})
|
|
.timeout(200)
|
|
.then(undefined, function (error) {
|
|
expect(error).toBe(goodError);
|
|
});
|
|
});
|
|
|
|
it("should reject with a timeout error if the promise is too slow", function () {
|
|
return Q.delay(100)
|
|
.timeout(10)
|
|
.then(
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (error) {
|
|
expect(/time/i.test(error.message)).toBe(true);
|
|
}
|
|
);
|
|
});
|
|
|
|
it("should pass through progress notifications", function () {
|
|
var deferred = Q.defer();
|
|
|
|
var progressValsSeen = [];
|
|
var promise = Q.timeout(deferred.promise, 300).then(function () {
|
|
expect(progressValsSeen).toEqual([1, 2, 3]);
|
|
}, undefined, function (progressVal) {
|
|
progressValsSeen.push(progressVal);
|
|
});
|
|
|
|
Q.delay(5).then(function () { deferred.notify(1); });
|
|
Q.delay(15).then(function () { deferred.notify(2); });
|
|
Q.delay(25).then(function () { deferred.notify(3); });
|
|
Q.delay(35).then(function () { deferred.resolve(); });
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should reject with a custom timeout error if the promise is too slow and msg was provided", function () {
|
|
return Q.delay(100)
|
|
.timeout(10, "custom")
|
|
.then(
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (error) {
|
|
expect(/custom/i.test(error.message)).toBe(true);
|
|
expect(error.code).toBe("ETIMEDOUT");
|
|
}
|
|
);
|
|
});
|
|
|
|
it("should reject with a custom timeout error if the promise is too slow and Error object was provided", function () {
|
|
var customError = new Error("custom");
|
|
customError.isCustom = true;
|
|
return Q.delay(100)
|
|
.timeout(10, customError)
|
|
.then(
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (error) {
|
|
expect(/custom/i.test(error.message)).toBe(true);
|
|
expect(error.isCustom).toBe(true);
|
|
}
|
|
);
|
|
});
|
|
|
|
});
|
|
|
|
describe("delay", function () {
|
|
it("should delay fulfillment", function () {
|
|
var promise = Q(5).delay(50);
|
|
|
|
setTimeout(function () {
|
|
expect(promise.isPending()).toBe(true);
|
|
}, 40);
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should not delay rejection", function () {
|
|
var promise = Q.reject(5).delay(50);
|
|
|
|
return Q.delay(20).then(function () {
|
|
expect(promise.isPending()).toBe(false);
|
|
});
|
|
});
|
|
|
|
it("should treat a single argument as a time", function () {
|
|
var promise = Q.delay(50);
|
|
|
|
setTimeout(function () {
|
|
expect(promise.isPending()).toBe(true);
|
|
}, 40);
|
|
|
|
return promise;
|
|
});
|
|
|
|
it("should treat two arguments as a value + a time", function () {
|
|
var promise = Q.delay("what", 50);
|
|
|
|
setTimeout(function () {
|
|
expect(promise.isPending()).toBe(true);
|
|
}, 40);
|
|
|
|
return promise.then(function (value) {
|
|
expect(value).toBe("what");
|
|
});
|
|
});
|
|
|
|
it("should delay after resolution", function () {
|
|
var promise1 = Q.delay("what", 30);
|
|
var promise2 = promise1.delay(30);
|
|
|
|
setTimeout(function () {
|
|
expect(promise1.isPending()).toBe(false);
|
|
expect(promise2.isPending()).toBe(true);
|
|
}, 40);
|
|
|
|
return promise2.then(function (value) {
|
|
expect(value).toBe("what");
|
|
});
|
|
});
|
|
|
|
|
|
it("should pass through progress notifications from passed promises", function () {
|
|
var deferred = Q.defer();
|
|
|
|
var progressValsSeen = [];
|
|
var promise = Q.delay(deferred.promise, 100).then(function () {
|
|
expect(progressValsSeen).toEqual([1, 2, 3]);
|
|
}, undefined, function (progressVal) {
|
|
progressValsSeen.push(progressVal);
|
|
});
|
|
|
|
Q.delay(5).then(function () { deferred.notify(1); });
|
|
Q.delay(15).then(function () { deferred.notify(2); });
|
|
Q.delay(25).then(function () { deferred.notify(3); });
|
|
Q.delay(35).then(function () { deferred.resolve(); });
|
|
|
|
return promise;
|
|
});
|
|
});
|
|
|
|
describe("thenResolve", function () {
|
|
describe("Resolving with a non-thenable value", function () {
|
|
it("returns a promise for that object once the promise is resolved", function () {
|
|
var waited = false;
|
|
return Q.delay(20)
|
|
.then(function () {
|
|
waited = true;
|
|
})
|
|
.thenResolve("foo")
|
|
.then(function (val) {
|
|
expect(waited).toBe(true);
|
|
expect(val).toBe("foo");
|
|
});
|
|
});
|
|
|
|
describe("based off a rejected promise", function () {
|
|
it("does nothing, letting the rejection flow through", function () {
|
|
return Q.reject("boo")
|
|
.thenResolve("foo")
|
|
.then(
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (reason) {
|
|
expect(reason).toBe("boo");
|
|
}
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Resolving with an promise", function () {
|
|
it("returns a promise for the result of that promise once the promise is resolved", function () {
|
|
var waited = false;
|
|
return Q.delay(20)
|
|
.then(function () {
|
|
waited = true;
|
|
})
|
|
.thenResolve(Q("foo"))
|
|
.then(function (val) {
|
|
expect(waited).toBe(true);
|
|
expect(val).toBe("foo");
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("thenReject", function () {
|
|
describe("Rejecting with a reason", function () {
|
|
it("returns a promise rejected with that object once the original promise is resolved", function () {
|
|
var waited = false;
|
|
return Q.delay(20)
|
|
.then(function () {
|
|
waited = true;
|
|
})
|
|
.thenReject("foo")
|
|
.then(
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (reason) {
|
|
expect(waited).toBe(true);
|
|
expect(reason).toBe("foo");
|
|
}
|
|
);
|
|
});
|
|
|
|
describe("based off a rejected promise", function () {
|
|
it("does nothing, letting the rejection flow through", function () {
|
|
return Q.reject("boo")
|
|
.thenResolve("foo")
|
|
.then(
|
|
function () {
|
|
expect(true).toBe(false);
|
|
},
|
|
function (reason) {
|
|
expect(reason).toBe("boo");
|
|
}
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("thenables", function () {
|
|
|
|
it("assimilates a thenable with fulfillment with resolve", function () {
|
|
return Q({
|
|
then: function (resolved) {
|
|
resolved(10);
|
|
}
|
|
})
|
|
.then(function (ten) {
|
|
expect(ten).toEqual(10);
|
|
})
|
|
.then(function (undefined) {
|
|
expect(undefined).toEqual(void 0);
|
|
});
|
|
});
|
|
|
|
it("assimilates a thenable with progress and fulfillment (using resolve)", function () {
|
|
var progressValueArrays = [];
|
|
return Q({
|
|
then: function (fulfilled, rejected, progressed) {
|
|
Q.nextTick(function () {
|
|
progressed(1, 2);
|
|
progressed(3, 4, 5);
|
|
fulfilled();
|
|
});
|
|
}
|
|
})
|
|
.progress(function () {
|
|
progressValueArrays.push(Array.prototype.slice.call(arguments));
|
|
})
|
|
.then(function () {
|
|
expect(progressValueArrays).toEqual([[1], [3]]);
|
|
});
|
|
});
|
|
|
|
it("assimilates a thenable with progress and fulfillment (using when)", function () {
|
|
var progressValueArrays = [];
|
|
return Q.when({
|
|
then: function (fulfilled, rejected, progressed) {
|
|
Q.nextTick(function () {
|
|
progressed(1, 2);
|
|
progressed(3, 4, 5);
|
|
fulfilled();
|
|
});
|
|
}
|
|
})
|
|
.progress(function () {
|
|
progressValueArrays.push(Array.prototype.slice.call(arguments));
|
|
})
|
|
.then(function () {
|
|
expect(progressValueArrays).toEqual([[1], [3]]);
|
|
});
|
|
});
|
|
|
|
it("flows fulfillment into a promise pipeline", function () {
|
|
return Q({
|
|
then: function (resolved) {
|
|
resolved([10]);
|
|
}
|
|
})
|
|
.get(0)
|
|
.then(function (ten) {
|
|
expect(ten).toEqual(10);
|
|
});
|
|
});
|
|
|
|
it("assimilates an immediately-fulfilled thenable in allSettled", function () {
|
|
return Q.allSettled([
|
|
{then: function (win) {
|
|
win(10);
|
|
}}
|
|
])
|
|
.then(function (snapshots) {
|
|
expect(snapshots).toEqual([{ state: "fulfilled", value: 10 }]);
|
|
});
|
|
});
|
|
|
|
it("assimilates an eventually-fulfilled thenable in allSettled", function () {
|
|
return Q.allSettled([
|
|
{then: function (win) {
|
|
setTimeout(function () {
|
|
win(10);
|
|
}, 100);
|
|
}}
|
|
])
|
|
.then(function (snapshots) {
|
|
expect(snapshots).toEqual([{ state: "fulfilled", value: 10 }]);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("node support", function () {
|
|
|
|
var exception = new Error("That is not your favorite color.");
|
|
|
|
var obj = {
|
|
method: function (a, b, c, callback) {
|
|
callback(null, a + b + c);
|
|
},
|
|
thispChecker: function (callback) {
|
|
callback(null, this === obj);
|
|
},
|
|
errorCallbacker: function (a, b, c, callback) {
|
|
callback(exception);
|
|
},
|
|
errorThrower: function () {
|
|
throw exception;
|
|
}
|
|
};
|
|
|
|
describe("nfapply", function () {
|
|
|
|
it("fulfills with callback result", function () {
|
|
return Q.nfapply(function (a, b, c, callback) {
|
|
callback(null, a + b + c);
|
|
}, [1, 2, 3])
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
|
|
it("rejects with callback error", function () {
|
|
var exception = new Error("That is not your favorite color.");
|
|
return Q.nfapply(function (a, b, c, callback) {
|
|
callback(exception);
|
|
}, [1, 2, 3])
|
|
.then(function () {
|
|
expect(true).toBe(false);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("nfcall", function () {
|
|
it("fulfills with callback result", function () {
|
|
return Q.nfcall(function (a, b, c, callback) {
|
|
callback(null, a + b + c);
|
|
}, 1, 2, 3)
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
|
|
it("rejects with callback error", function () {
|
|
var exception = new Error("That is not your favorite color.");
|
|
return Q.nfcall(function (a, b, c, callback) {
|
|
callback(exception);
|
|
}, 1, 2, 3)
|
|
.then(function () {
|
|
expect(true).toBe(false);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("nfbind", function () {
|
|
|
|
it("mixes partial application with complete application", function () {
|
|
return Q.nfbind(function (a, b, c, d, callback) {
|
|
callback(null, a + b + c + d);
|
|
}, 1, 2).call({}, 3, 4)
|
|
.then(function (ten) {
|
|
expect(ten).toBe(10);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("nbind", function () {
|
|
|
|
it("binds this, and mixes partial application with complete application", function () {
|
|
return Q.nbind(function (a, b, c, callback) {
|
|
callback(null, this + a + b + c);
|
|
}, 1, 2).call(3 /* effectively ignored as fn bound to 1 */, 4, 5)
|
|
.then(function (twelve) {
|
|
expect(twelve).toBe(12);
|
|
});
|
|
});
|
|
|
|
it("second arg binds this", function() {
|
|
var expectedThis = { test: null };
|
|
|
|
return Q.nbind(function(callback) {
|
|
callback(null, this);
|
|
}, expectedThis).call()
|
|
.then(function(actualThis) {
|
|
expect(actualThis).toEqual(expectedThis);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("npost", function () {
|
|
|
|
it("fulfills with callback result", function () {
|
|
return Q.npost(obj, "method", [1, 2, 3])
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
|
|
it("gets the correct thisp", function () {
|
|
return Q.npost(obj, "thispChecker", [])
|
|
.then(function (result) {
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("rejects with callback error", function () {
|
|
return Q.npost(obj, "errorCallbacker", [1, 2, 3])
|
|
.then(function () {
|
|
expect("blue").toBe("no, yellow!");
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
it("rejects with thrown error", function () {
|
|
return Q.npost(obj, "errorThrower", [1, 2, 3])
|
|
.then(function () {
|
|
expect(true).toBe(false);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
it("works on promises for objects with Node methods", function () {
|
|
return Q(obj)
|
|
.npost("method", [1, 2, 3])
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("nsend", function () {
|
|
|
|
it("fulfills with callback result", function () {
|
|
return Q.nsend(obj, "method", 1, 2, 3)
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
|
|
it("gets the correct thisp", function () {
|
|
return Q.nsend(obj, "thispChecker")
|
|
.then(function (result) {
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("rejects with callback error", function () {
|
|
return Q.nsend(obj, "errorCallbacker", 1, 2, 3)
|
|
.then(function () {
|
|
expect("blue").toBe("no, yellow!");
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
it("rejects with thrown error", function () {
|
|
return Q.nsend(obj, "errorThrower", 1, 2, 3)
|
|
.then(function () {
|
|
expect(true).toBe(false);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
it("works on promises for objects with Node methods", function () {
|
|
return Q(obj)
|
|
.nsend("method", 1, 2, 3)
|
|
.then(function (sum) {
|
|
expect(sum).toEqual(6);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("deferred.makeNodeResolver", function () {
|
|
|
|
it("fulfills a promise with a single callback argument", function () {
|
|
var deferred = Q.defer();
|
|
var callback = deferred.makeNodeResolver();
|
|
callback(null, 10);
|
|
return deferred.promise.then(function (value) {
|
|
expect(value).toBe(10);
|
|
});
|
|
});
|
|
|
|
it("fulfills a promise with multiple callback arguments", function () {
|
|
var deferred = Q.defer();
|
|
var callback = deferred.makeNodeResolver();
|
|
callback(null, 10, 20);
|
|
return deferred.promise.then(function (value) {
|
|
expect(value).toEqual([10, 20]);
|
|
});
|
|
});
|
|
|
|
it("rejects a promise", function () {
|
|
var deferred = Q.defer();
|
|
var callback = deferred.makeNodeResolver();
|
|
var exception = new Error("Holy Exception of Anitoch");
|
|
callback(exception);
|
|
return deferred.promise.then(function () {
|
|
expect(5).toBe(3);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("nodeify", function () {
|
|
|
|
it("calls back with a resolution", function () {
|
|
var spy = jasmine.createSpy();
|
|
Q(10).nodeify(spy);
|
|
waitsFor(function () {
|
|
return spy.argsForCall.length;
|
|
});
|
|
runs(function () {
|
|
expect(spy.argsForCall).toEqual([[null, 10]]);
|
|
});
|
|
});
|
|
|
|
it("calls back with an error", function () {
|
|
var spy = jasmine.createSpy();
|
|
Q.reject(10).nodeify(spy);
|
|
waitsFor(function () {
|
|
return spy.argsForCall.length;
|
|
});
|
|
runs(function () {
|
|
expect(spy.argsForCall).toEqual([[10]]);
|
|
});
|
|
});
|
|
|
|
it("forwards a promise", function () {
|
|
return Q(10).nodeify().then(function (ten) {
|
|
expect(ten).toBe(10);
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("isPromise", function () {
|
|
it("returns true if passed a promise", function () {
|
|
expect(Q.isPromise(Q(10))).toBe(true);
|
|
});
|
|
|
|
it("returns false if not passed a promise", function () {
|
|
expect(Q.isPromise(undefined)).toBe(false);
|
|
expect(Q.isPromise(null)).toBe(false);
|
|
expect(Q.isPromise(10)).toBe(false);
|
|
expect(Q.isPromise("str")).toBe(false);
|
|
expect(Q.isPromise("")).toBe(false);
|
|
expect(Q.isPromise(true)).toBe(false);
|
|
expect(Q.isPromise(false)).toBe(false);
|
|
expect(Q.isPromise({})).toBe(false);
|
|
expect(Q.isPromise({
|
|
then: function () {}
|
|
})).toBe(false);
|
|
expect(Q.isPromise(function () {})).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("isPromiseAlike", function () {
|
|
it("returns true if passed a promise like object", function () {
|
|
expect(Q.isPromiseAlike(Q(10))).toBe(true);
|
|
expect(Q.isPromiseAlike({
|
|
then: function () {}
|
|
})).toBe(true);
|
|
});
|
|
|
|
it("returns false if not passed a promise like object", function () {
|
|
expect(Q.isPromiseAlike(undefined)).toBe(false);
|
|
expect(Q.isPromiseAlike(null)).toBe(false);
|
|
expect(Q.isPromiseAlike(10)).toBe(false);
|
|
expect(Q.isPromiseAlike("str")).toBe(false);
|
|
expect(Q.isPromiseAlike("")).toBe(false);
|
|
expect(Q.isPromiseAlike(true)).toBe(false);
|
|
expect(Q.isPromiseAlike(false)).toBe(false);
|
|
expect(Q.isPromiseAlike({})).toBe(false);
|
|
expect(Q.isPromiseAlike(function () {})).toBe(false);
|
|
});
|
|
});
|
|
|
|
if (typeof require === "function") {
|
|
var domain;
|
|
try {
|
|
domain = require("domain");
|
|
} catch (e) { }
|
|
|
|
if (domain) {
|
|
var EventEmitter = require("events").EventEmitter;
|
|
|
|
describe("node domain support", function () {
|
|
var d;
|
|
|
|
beforeEach(function () {
|
|
d = domain.create();
|
|
});
|
|
afterEach(function() {
|
|
d.dispose();
|
|
});
|
|
|
|
it("should work for non-promise async inside a promise handler",
|
|
function (done) {
|
|
var error = new Error("should be caught by the domain");
|
|
|
|
d.run(function () {
|
|
Q().then(function () {
|
|
setTimeout(function () {
|
|
throw error;
|
|
}, 10);
|
|
});
|
|
});
|
|
|
|
var errorTimeout = setTimeout(function () {
|
|
done(new Error("Wasn't caught"));
|
|
}, 100);
|
|
|
|
d.on("error", function (theError) {
|
|
expect(theError).toBe(error);
|
|
clearTimeout(errorTimeout);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("should transfer errors from `done` into the domain",
|
|
function (done) {
|
|
var error = new Error("should be caught by the domain");
|
|
|
|
d.run(function () {
|
|
Q.reject(error).done();
|
|
});
|
|
|
|
var errorTimeout = setTimeout(function () {
|
|
done(new Error("Wasn't caught"));
|
|
}, 100);
|
|
|
|
d.on("error", function (theError) {
|
|
expect(theError).toBe(error);
|
|
clearTimeout(errorTimeout);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("should take care of re-used event emitters", function (done) {
|
|
// See discussion in https://github.com/kriskowal/q/issues/120
|
|
var error = new Error("should be caught by the domain");
|
|
|
|
var e = new EventEmitter();
|
|
|
|
d.run(function () {
|
|
callAsync().done();
|
|
});
|
|
setTimeout(function () {
|
|
e.emit("beep");
|
|
}, 100);
|
|
|
|
var errorTimeout = setTimeout(function () {
|
|
done(new Error("Wasn't caught"));
|
|
}, 500);
|
|
|
|
d.on("error", function (theError) {
|
|
expect(theError).toBe(error);
|
|
clearTimeout(errorTimeout);
|
|
done();
|
|
});
|
|
|
|
function callAsync() {
|
|
var def = Q.defer();
|
|
e.once("beep", function () {
|
|
def.reject(error);
|
|
});
|
|
return def.promise;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
describe("decorator functions", function () {
|
|
describe("promised", function () {
|
|
var exception = new Error("That is not the meaning of life.");
|
|
it("resolves promised arguments", function () {
|
|
var sum = Q.promised(function add(a, b) {
|
|
return a + b;
|
|
});
|
|
return sum(Q(4), Q(5)).then(function (sum) {
|
|
expect(sum).toEqual(9);
|
|
});
|
|
});
|
|
it("resolves promised `this`", function () {
|
|
var inc = Q.promised(function inc(a) {
|
|
return this + a;
|
|
});
|
|
return inc.call(Q(4), Q(5)).then(function (sum) {
|
|
expect(sum).toEqual(9);
|
|
});
|
|
});
|
|
it("is rejected if an argument is rejected", function () {
|
|
var sum = Q.promised(function add(a, b) {
|
|
return a + b;
|
|
});
|
|
return sum(Q.reject(exception), Q(4)).then(function () {
|
|
expect(4).toEqual(42);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
it("is rejected if `this` is rejected", function () {
|
|
var inc = Q.promised(function inc(a) {
|
|
return this + a;
|
|
});
|
|
return inc.call(Q.reject(exception), Q(4)).then(function () {
|
|
expect(4).toEqual(42);
|
|
}, function (_exception) {
|
|
expect(_exception).toBe(exception);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("stack trace formatting", function () {
|
|
it("doesn't mangle a stack trace that gets handled twice", function () {
|
|
var d1 = Q.defer();
|
|
var d2 = Q.defer();
|
|
var captured = [];
|
|
d1.promise.done();
|
|
d2.promise.done();
|
|
|
|
Q.onerror = function (err) {
|
|
captured.push(err.stack);
|
|
};
|
|
|
|
var error = new Error("boom!");
|
|
d1.reject(error);
|
|
d2.reject(error);
|
|
|
|
return Q.all([d1.promise.fail(function () {}), d2.promise.fail(function () { })])
|
|
.then(function () {
|
|
expect(captured[0]).toEqual(captured[1]);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("possible regressions", function () {
|
|
|
|
describe("gh-9", function () {
|
|
it("treats falsy values as resolved values without error", function () {
|
|
expect(Q.isPending(null)).toEqual(false);
|
|
expect(Q.isPending(void 0)).toEqual(false);
|
|
expect(Q.isPending(false)).toEqual(false);
|
|
expect(Q.isPending()).toEqual(false);
|
|
});
|
|
});
|
|
|
|
describe("gh-22", function () {
|
|
it("ensures that the array prototype is intact", function () {
|
|
var keys = [];
|
|
for (var key in []) {
|
|
keys.push(key);
|
|
}
|
|
expect(keys.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("gh-73", function () {
|
|
it("does not choke on non-error rejection reasons", function () {
|
|
Q.reject(REASON).done();
|
|
|
|
var deferred = Q.defer();
|
|
|
|
Q.onerror = function (error) {
|
|
expect(error).toBe(REASON);
|
|
deferred.resolve();
|
|
};
|
|
Q.delay(10).then(deferred.reject);
|
|
|
|
return deferred.promise;
|
|
});
|
|
});
|
|
|
|
describe("gh-90", function () {
|
|
it("does not choke on rejection reasons with an undefined `stack`", function () {
|
|
var error = new RangeError(REASON);
|
|
error.stack = undefined;
|
|
Q.reject(error).done();
|
|
|
|
var deferred = Q.defer();
|
|
|
|
Q.onerror = function (theError) {
|
|
expect(theError).toBe(error);
|
|
deferred.resolve();
|
|
};
|
|
Q.delay(10).then(deferred.reject);
|
|
|
|
return deferred.promise;
|
|
});
|
|
});
|
|
|
|
describe("gh-75", function () {
|
|
it("does not double-resolve misbehaved promises", function () {
|
|
var badPromise = Q.makePromise({
|
|
post: function () { return "hello"; }
|
|
});
|
|
|
|
var resolutions = 0;
|
|
function onResolution() {
|
|
++resolutions;
|
|
}
|
|
|
|
return Q.when(badPromise, onResolution, onResolution).then(function () {
|
|
expect(resolutions).toBe(1);
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe("unhandled rejection reporting", function () {
|
|
beforeEach(function () {
|
|
Q.resetUnhandledRejections();
|
|
});
|
|
|
|
it("doesn't report a resolve, then reject (gh-252)", function () {
|
|
var deferred = Q.defer();
|
|
deferred.resolve();
|
|
deferred.reject();
|
|
|
|
expect(Q.getUnhandledReasons().length).toEqual(0);
|
|
});
|
|
|
|
it("doesn't report when you chain off a rejection", function () {
|
|
return Q.reject("this will be handled").get("property").fail(function () {
|
|
// now it should be handled.
|
|
}).fin(function() {
|
|
expect(Q.getUnhandledReasons().length).toEqual(0);
|
|
});
|
|
});
|
|
|
|
it("reports the most basic case", function () {
|
|
Q.reject("a reason");
|
|
|
|
expect(Q.getUnhandledReasons()).toEqual(["(no stack) a reason"]);
|
|
});
|
|
|
|
it("reports a stack trace", function () {
|
|
var error = new Error("a reason");
|
|
Q.reject(error);
|
|
|
|
expect(Q.getUnhandledReasons()).toEqual([error.stack]);
|
|
});
|
|
|
|
it("doesn't let you mutate the internal array", function () {
|
|
Q.reject("a reason");
|
|
|
|
Q.getUnhandledReasons().length = 0;
|
|
expect(Q.getUnhandledReasons()).toEqual(["(no stack) a reason"]);
|
|
});
|
|
|
|
it("resets after calling `Q.resetUnhandledRejections`", function () {
|
|
Q.reject("a reason");
|
|
|
|
Q.resetUnhandledRejections();
|
|
expect(Q.getUnhandledReasons()).toEqual([]);
|
|
});
|
|
|
|
it("stops tracking after calling `Q.stopUnhandledRejectionTracking`", function () {
|
|
Q.reject("a reason");
|
|
|
|
Q.stopUnhandledRejectionTracking();
|
|
|
|
Q.reject("another reason");
|
|
|
|
expect(Q.getUnhandledReasons()).toEqual([]);
|
|
});
|
|
});
|