summaryrefslogtreecommitdiff
path: root/scorpion-tests.js
diff options
context:
space:
mode:
Diffstat (limited to 'scorpion-tests.js')
-rw-r--r--scorpion-tests.js359
1 files changed, 359 insertions, 0 deletions
diff --git a/scorpion-tests.js b/scorpion-tests.js
new file mode 100644
index 0000000..0bbe721
--- /dev/null
+++ b/scorpion-tests.js
@@ -0,0 +1,359 @@
+/*global describe,it,expect,beforeEach,Scorpion, setTimeout*/
+
+describe("deferred", function() {
+ var deferred, promise;
+ beforeEach(function() {
+ deferred = Scorpion.defer();
+ promise = deferred.promise;
+ });
+ this.timeout(100);
+
+ describe("promise", function() {
+ it("should have a 'then' method", function() {
+ expect(promise.then).not.to.equal(undefined);
+ });
+
+ it("should be able to chain 'then' methods", function() {
+ var promise1 = promise;
+ var promise2 = promise1.then(function(x) {
+ return x + 1;
+ });
+ var promise3 = promise1.then(function(x) {
+ return x + 1;
+ });
+ expect(promise1.then).not.to.equal(undefined);
+ expect(promise2.then).not.to.equal(undefined);
+ expect(promise3.then).not.to.equal(undefined);
+ });
+ });
+
+ describe("resolution", function() {
+
+ it("should resolve asynchronously", function(done) {
+ var hasRun = false;
+ promise.then(function(val) {
+ hasRun = true;
+ return val;
+ });
+ deferred.resolve("value");
+ expect(hasRun).to.equal(false);
+ setTimeout(function() {
+ expect(hasRun).to.equal(true);
+ done();
+ });
+ });
+
+ it("should propagate through multiple promises", function(done) {
+ var promise2 = promise.then(function(value) {
+ return value + 1;
+ });
+ var promise3 = promise2.then(function(value) {
+ return value + 1;
+ });
+ promise3.then(function(value) {
+ expect(value).to.equal(3);
+ done();
+ });
+ deferred.resolve(1);
+ });
+
+ it("should call all registered handlers", function(done) {
+ var called = 0;
+ promise.then(function() {called++;});
+ promise.then(function() {called++;});
+ promise.then(function() {called++;});
+ expect(called).to.equal(0);
+ deferred.resolve(null);
+ setTimeout(function() {
+ expect(called).to.equal(3);
+ done();
+ });
+ });
+
+ it("should call handlers, even when added after resolution", function(done) {
+ deferred.resolve(null);
+ promise.then(function() {
+ done();
+ });
+ });
+
+ it("should not allow multiple resolution", function() {
+ deferred.resolve(1);
+ expect(function() {
+ deferred.resolve(2);
+ }).to.throw();
+ });
+
+ it("should not allow rejecting after resolving", function() {
+ deferred.resolve(1);
+ expect(function() {
+ deferred.reject(2);
+ }).to.throw();
+ });
+
+ it("should handle a returned promise by 'unwrapping' it", function(done) {
+ promise.then(function(value) {
+ var deferred = Scorpion.defer();
+ deferred.resolve(value + 1);
+ return deferred.promise;
+ }).then(function(value) {
+ try {
+ expect(value).to.equal(2);
+ done();
+ } catch (e) {
+ done(e);
+ }
+ });
+ deferred.resolve(1);
+ });
+ });
+
+ describe("rejection", function() {
+ it("should reject asynchronously", function(done) {
+ var hasRun = false;
+ promise.then(null, function(val) {
+ hasRun = true;
+ return val;
+ });
+ deferred.reject("value");
+ expect(hasRun).to.equal(false);
+ setTimeout(function() {
+ expect(hasRun).to.equal(true);
+ done();
+ });
+ });
+
+
+ it("should be turned into resolution by a handler", function(done) {
+ var promise2 = promise.then(function(value) {
+ return value + 1;
+ }, function(value) {
+ return value + 100;
+ });
+ promise2.then(function(value) {
+ try {
+ expect(value).to.equal(101);
+ done();
+ } catch (e) {
+ done(e);
+ }
+ });
+ deferred.reject(1);
+ });
+
+ it("should call all registered handlers", function(done) {
+ var called = 0;
+ promise.then(null, function() {called++;});
+ promise.then(null, function() {called++;});
+ promise.then(null, function() {called++;});
+ expect(called).to.equal(0);
+ deferred.reject(null);
+ setTimeout(function() {
+ expect(called).to.equal(3);
+ done();
+ });
+ });
+
+ it("should not allow multiple rejection", function() {
+ deferred.reject(1);
+ expect(function() {
+ deferred.reject(2);
+ }).to.throw();
+ });
+
+ it("should not allow resolving after rejecting", function() {
+ deferred.reject(1);
+ expect(function() {
+ deferred.resolve(2);
+ }).to.throw();
+ });
+
+ it("should call handlers, even when added after resolution", function(done) {
+ deferred.reject(null);
+ promise.then(null, function() {
+ done();
+ });
+ });
+
+ it("should handle a returned promise by 'unwrapping' in the error case", function(done) {
+ promise.then(function(value) {
+ var deferred = Scorpion.defer();
+ deferred.reject(value + 1);
+ return deferred.promise;
+ }).then(null, function(value) {
+ try {
+ expect(value).to.equal(2);
+ done();
+ } catch (e) {
+ done(e);
+ }
+ });
+ deferred.resolve(1);
+ });
+ });
+
+ describe("waitForAll", function() {
+ it("should resolve with an array if all successful", function(done) {
+ var d1 = Scorpion.defer(),
+ d2 = Scorpion.defer(),
+ d3 = Scorpion.defer();
+ Scorpion
+ .waitForAll([d1.promise, d2.promise, d3.promise])
+ .then(function(values) {
+ if (values.length == 3 &&
+ values[0] === 0 &&
+ values[1] === 1 &&
+ values[2] === 2) {
+ done();
+ } else {
+ done(new Error("Error in resolved result: " + values));
+ }
+ }, done);
+ d1.resolve(0);
+ d2.resolve(1);
+ d3.resolve(2);
+ });
+
+ it("should reject with an object of successes/errors if any fail", function(done) {
+ var d1 = Scorpion.defer(),
+ d2 = Scorpion.defer(),
+ d3 = Scorpion.defer();
+ Scorpion
+ .waitForAll([d1.promise, d2.promise, d3.promise])
+ .then(function(values) {
+ done(new Error("incorrectly resolved promise"));
+ }, function(e) {
+ if (e.errors && e.values &&
+ e.values[0] === 0 &&
+ e.values[1] === 1 &&
+ e.errors[2] === 2) {
+ done();
+ } else {
+ done(new Error("incorrect reject value"));
+ }
+ });
+ d1.resolve(0);
+ d2.resolve(1);
+ d3.reject(2);
+ });
+ });
+});
+
+describe("injector", function() {
+ var injector, valuePlugin;
+ beforeEach(function() {
+ valuePlugin = new Scorpion.ValuePlugin();
+ injector = new Scorpion([valuePlugin]);
+ });
+ this.timeout(100);
+
+ describe("value registration and retrieval", function() {
+ it("works", function(done) {
+ injector.register("a", function(){return "the value of a";});
+ injector.get("a").then(function(value){
+ if (value == "the value of a")
+ done();
+ else
+ done(new Error("incorrect value for a (" + value + ")"));
+ }, done);
+ });
+
+ it("with dependencies works", function(done) {
+ injector
+ .register("a", function(){return "the value of a";})
+ .register("b", ["a", function(a){return a.replace(/a/g, "b");}]);
+ injector.get("b").then(function(value){
+ if (value == "the vblue of b")
+ done();
+ else
+ done(new Error("incorrect value for b (" + value + ")"));
+ }, done);
+ });
+ });
+
+ describe("destroy handlers", function() {
+ it("work with single gets", function(done) {
+ injector.register("a", function(){return "a";});
+ expect("a" in valuePlugin.values).to.equal(false);
+ var result = injector.get("a");
+ result.then(function() {
+ if ("a" in valuePlugin.values) {
+ result.destroy().then(function() {
+ if ("a" in valuePlugin.values) {
+ done(new Error("Value found for a after destruction"));
+ } else {
+ done();
+ }
+ });
+ } else {
+ done(new Error("No value found for a"));
+ }
+ }, done);
+ });
+
+ it("works with multiple gets", function(done) {
+ injector.register("a", function(){return "a";});
+ expect("a" in valuePlugin.values).to.equal(false);
+ var result = [injector.get("a"), injector.get("a"), injector.get("a")];
+ result[1].destroy();
+ result[2].destroy();
+ result[0].then(function() {
+ if ("a" in valuePlugin.values) {
+ result[0].destroy().then(function() {
+ if ("a" in valuePlugin.values) {
+ done(new Error("Value found for a after destruction"));
+ } else {
+ done();
+ }
+ });
+ } else {
+ done(new Error("No value found for a"));
+ }
+ }, done);
+ });
+
+ it("works through dependencies", function(done) {
+ injector
+ .register("a", function(){return "a";})
+ .register("b", ["a", function(a){return a + "b";}]);
+ expect("a" in valuePlugin.values).to.equal(false);
+ var result = injector.get("b");
+ result.then(function() {
+ if ("a" in valuePlugin.values) {
+ result.destroy().then(function() {
+ if ("a" in valuePlugin.values) {
+ done(new Error("Value found for a after destruction"));
+ } else {
+ done();
+ }
+ });
+ } else {
+ done(new Error("No value found for a"));
+ }
+ }, done);
+ });
+ });
+
+ describe("cyclic dependency detection", function() {
+ it("detects simple cycles", function(done) {
+ injector.register("a", ["b", function(b) {return b;}]);
+ injector.register("b", ["a", function(a) {return a;}]);
+ injector.get("a").then(function() {
+ done(new Error("Promise should have been rejected"));
+ }, function(e) {
+ done();
+ });
+ });
+
+ it("detects cycles with intermediate nodes", function(done) {
+ injector.register("a", ["c", function(c) {return c;}]);
+ injector.register("b", ["a", function(a) {return a;}]);
+ injector.register("c", ["b", function(b) {return b;}]);
+ injector.get("a").then(function() {
+ done(new Error("Promise should have been rejected"));
+ }, function(e) {
+ done();
+ });
+ });
+ });
+});