You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
8.2 KiB
353 lines
8.2 KiB
"use strict";
|
|
|
|
var assert = require("chai").assert;
|
|
var sinon = require("sinon");
|
|
var express = require("express");
|
|
var GET = require("./util/http-utils").GET;
|
|
|
|
var delay = function (method, payload) {
|
|
setTimeout(function () {
|
|
method(payload);
|
|
}, 10);
|
|
};
|
|
|
|
var PromiseRouter = require("../lib/express-promise-router.js");
|
|
|
|
describe("new Router().route(...)", function () {
|
|
var app;
|
|
var serverListening;
|
|
var server;
|
|
var router;
|
|
|
|
var bootstrap = function (router) {
|
|
app = express();
|
|
app.use("/", router);
|
|
|
|
if (serverListening) {
|
|
throw "already bootstrapped";
|
|
}
|
|
|
|
serverListening = new Promise(function (resolve, reject) {
|
|
server = app.listen(12345, function (err) {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
|
|
return serverListening;
|
|
};
|
|
|
|
beforeEach(function () {
|
|
router = new PromiseRouter();
|
|
});
|
|
|
|
afterEach(function () {
|
|
if (serverListening) {
|
|
return serverListening.then(function () {
|
|
server.close();
|
|
app = undefined;
|
|
server = undefined;
|
|
serverListening = undefined;
|
|
});
|
|
}
|
|
});
|
|
|
|
it("should call next with an error when a returned promise is rejected", function () {
|
|
var callback = sinon.spy();
|
|
|
|
router.route("/foo").get(function () {
|
|
return new Promise(function (resolve, reject) {
|
|
delay(reject, "some error");
|
|
});
|
|
});
|
|
router.use(function (err, req, res, next) {
|
|
assert.equal("some error", err);
|
|
callback();
|
|
res.send();
|
|
});
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function () {
|
|
assert(callback.calledOnce);
|
|
});
|
|
});
|
|
|
|
it('should call next without an error when a returned promise is resolved with "next"', function () {
|
|
var errorCallback = sinon.spy();
|
|
var nextCallback = sinon.spy();
|
|
|
|
router
|
|
.route("/foo")
|
|
.get(function () {
|
|
return new Promise(function (resolve) {
|
|
delay(resolve, "next");
|
|
});
|
|
})
|
|
.all(function (req, res) {
|
|
nextCallback();
|
|
res.send();
|
|
});
|
|
router.use(function (err, req, res, next) {
|
|
errorCallback();
|
|
next();
|
|
});
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function () {
|
|
assert(errorCallback.notCalled);
|
|
assert(nextCallback.calledOnce);
|
|
});
|
|
});
|
|
|
|
it('should not call next when a returned promise is resolved with anything other than "route" or "next"', function () {
|
|
var callback = sinon.spy();
|
|
|
|
router.route("/foo").get(function (req, res) {
|
|
return new Promise(function (resolve) {
|
|
res.send();
|
|
delay(resolve, "something");
|
|
});
|
|
});
|
|
router.route("/bar").get(function (req, res) {
|
|
return new Promise(function (resolve) {
|
|
res.send();
|
|
delay(resolve, {});
|
|
});
|
|
});
|
|
router.use(function (req, res) {
|
|
callback();
|
|
res.send(500);
|
|
});
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function () {
|
|
assert(callback.notCalled);
|
|
return GET("/bar");
|
|
})
|
|
.then(function () {
|
|
assert(callback.notCalled);
|
|
});
|
|
});
|
|
|
|
it("should move to the next middleware when next is called without an error", function () {
|
|
var callback = sinon.spy();
|
|
|
|
router
|
|
.route("/foo")
|
|
.get(function (req, res, next) {
|
|
next();
|
|
})
|
|
.all(function (req, res, next) {
|
|
callback();
|
|
res.send();
|
|
});
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function () {
|
|
assert(callback.calledOnce);
|
|
});
|
|
});
|
|
|
|
it("should move to the next error handler when next is called with an error", function () {
|
|
var callback = sinon.spy();
|
|
var errorCallback = sinon.spy();
|
|
|
|
router
|
|
.route("/foo")
|
|
.get(function (req, res, next) {
|
|
next("an error");
|
|
})
|
|
.all(function (req, res, next) {
|
|
callback();
|
|
next();
|
|
});
|
|
router.use(function (err, req, res, next) {
|
|
assert.equal("an error", err);
|
|
errorCallback();
|
|
res.send();
|
|
});
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function () {
|
|
assert(errorCallback.calledOnce);
|
|
assert(callback.notCalled);
|
|
});
|
|
});
|
|
|
|
it("should call chained handlers in the correct order", function () {
|
|
var fn2 = sinon.spy(function (req, res) {
|
|
res.send();
|
|
});
|
|
var fn1 = sinon.spy(function () {
|
|
assert(fn2.notCalled);
|
|
return Promise.resolve("next");
|
|
});
|
|
|
|
router.route("/foo").get(fn1, fn2);
|
|
|
|
return bootstrap(router).then(function () {
|
|
return GET("/foo");
|
|
});
|
|
});
|
|
|
|
it("should correctly call an array of handlers", function () {
|
|
var fn2 = sinon.spy(function (req, res) {
|
|
res.send();
|
|
});
|
|
var fn1 = sinon.spy(function () {
|
|
assert(fn2.notCalled);
|
|
return Promise.resolve("next");
|
|
});
|
|
|
|
router.route("/foo").get([[fn1], [fn2]]);
|
|
|
|
return bootstrap(router).then(function () {
|
|
return GET("/foo");
|
|
});
|
|
});
|
|
|
|
it('should call next("route") if a returned promise is resolved with "route"', function () {
|
|
var fn1 = function () {
|
|
return Promise.resolve("route");
|
|
};
|
|
var fn2 = function () {
|
|
assert.fail();
|
|
};
|
|
|
|
router.route("/foo").get(fn1, fn2);
|
|
|
|
router.route("/foo").get(function (req, res) {
|
|
res.send();
|
|
});
|
|
|
|
return bootstrap(router).then(function () {
|
|
return GET("/foo");
|
|
});
|
|
});
|
|
|
|
it("should bind to RegExp routes", function () {
|
|
var fn1 = function (req, res) {
|
|
res.send();
|
|
};
|
|
|
|
router.route(/^\/foo/).get(fn1);
|
|
|
|
return bootstrap(router).then(function () {
|
|
return GET("/foo");
|
|
});
|
|
});
|
|
|
|
it('multiple calls to handlers that have used "next" should not interfere with each other', function () {
|
|
var fn = sinon.spy(function (req, res, next) {
|
|
if (fn.calledOnce) {
|
|
next("error");
|
|
} else {
|
|
setTimeout(function () {
|
|
res.status(200).send("ok");
|
|
}, 15);
|
|
}
|
|
});
|
|
var errHandler = function (err, req, res, next) {
|
|
if (err === "error") {
|
|
res.send("fail");
|
|
} else {
|
|
next(err);
|
|
}
|
|
};
|
|
|
|
router.route("/foo").get(fn, errHandler);
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function (res) {
|
|
assert.equal(res.body, "fail");
|
|
return GET("/foo");
|
|
})
|
|
.then(function (res) {
|
|
assert.equal(res.body, "ok");
|
|
});
|
|
});
|
|
|
|
it("calls next if next is called even if the handler returns a promise", function () {
|
|
var fn = function (req, res, next) {
|
|
next();
|
|
return new Promise(function (resolve, reject) {});
|
|
};
|
|
var fn2 = function (req, res) {
|
|
res.send("ok");
|
|
};
|
|
var errHandler = function (err, req, res, next) {
|
|
res.send("error");
|
|
};
|
|
|
|
router.route("/foo").get(fn, fn2, errHandler);
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function (res) {
|
|
assert.equal(res.body, "ok");
|
|
});
|
|
});
|
|
|
|
it("calls next with an error if the returned promise is rejected with no reason", function () {
|
|
var fn = function () {
|
|
return new Promise(function (resolve, reject) {
|
|
delay(reject, null);
|
|
});
|
|
};
|
|
var errHandler = function (err, req, res, next) {
|
|
res.send("error");
|
|
};
|
|
|
|
router.route("/foo").get(fn, errHandler);
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo");
|
|
})
|
|
.then(function (res) {
|
|
assert.equal(res.body, "error");
|
|
});
|
|
});
|
|
|
|
it("should handle resolved promises returned in req.param() calls", function () {
|
|
router.param("id", function () {
|
|
return new Promise(function (resolve) {
|
|
delay(resolve, "next");
|
|
});
|
|
});
|
|
router.route("/foo/:id").all(function (req, res) {
|
|
res.send("done");
|
|
});
|
|
|
|
return bootstrap(router)
|
|
.then(function () {
|
|
return GET("/foo/1");
|
|
})
|
|
.then(function (res) {
|
|
assert.equal(res.body, "done");
|
|
});
|
|
});
|
|
});
|
|
|