mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 10:58:56 +00:00
1109 lines
28 KiB
TypeScript
1109 lines
28 KiB
TypeScript
"use strict";
|
|
|
|
var after = require("./support/after");
|
|
var express = require("express"),
|
|
request = require("supertest"),
|
|
assert = require("node:assert"),
|
|
methods = require("./support/utils").methods;
|
|
|
|
var shouldSkipQuery = require("./support/utils").shouldSkipQuery;
|
|
|
|
describe("app.router", function () {
|
|
it("should restore req.params after leaving router", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
function handler1(req, res, next) {
|
|
res.setHeader("x-user-id", String(req.params.id));
|
|
next();
|
|
}
|
|
|
|
function handler2(req, res) {
|
|
res.send(req.params.id);
|
|
}
|
|
|
|
router.use(function (req, res, next) {
|
|
res.setHeader("x-router", String(req.params.id));
|
|
next();
|
|
});
|
|
|
|
app.get("/user/:id", handler1, router, handler2);
|
|
|
|
request(app).get("/user/1").expect("x-router", "undefined").expect("x-user-id", "1").expect(200, "1", done);
|
|
});
|
|
|
|
describe("methods", function () {
|
|
methods.forEach(function (method) {
|
|
if (method === "connect") return;
|
|
|
|
it("should include " + method.toUpperCase(), function (done) {
|
|
if (method === "query" && shouldSkipQuery(process.versions.node)) {
|
|
this.skip();
|
|
}
|
|
var app = express();
|
|
|
|
app[method]("/foo", function (req, res) {
|
|
res.send(method);
|
|
});
|
|
|
|
request(app)[method]("/foo").expect(200, done);
|
|
});
|
|
|
|
it.todo("should reject numbers for app." + method, function () {
|
|
var app = express();
|
|
assert.throws(app[method].bind(app, "/", 3), /argument handler must be a function/);
|
|
});
|
|
});
|
|
|
|
it("should re-route when method is altered", function (done) {
|
|
var app = express();
|
|
var cb = after(3, done);
|
|
|
|
app.use(function (req, res, next) {
|
|
if (req.method !== "POST") return next();
|
|
req.method = "DELETE";
|
|
res.setHeader("X-Method-Altered", "1");
|
|
next();
|
|
});
|
|
|
|
app.delete("/", function (req, res) {
|
|
res.end("deleted everything");
|
|
});
|
|
|
|
request(app).get("/").expect(404, cb);
|
|
|
|
request(app).delete("/").expect(200, "deleted everything", cb);
|
|
|
|
request(app).post("/").expect("X-Method-Altered", "1").expect(200, "deleted everything", cb);
|
|
});
|
|
});
|
|
|
|
describe("decode params", function () {
|
|
it("should decode correct params", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/:name", function (req, res) {
|
|
res.send(req.params.name);
|
|
});
|
|
|
|
request(app).get("/foo%2Fbar").expect("foo/bar", done);
|
|
});
|
|
|
|
it("should not accept params in malformed paths", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/:name", function (req, res) {
|
|
res.send(req.params.name);
|
|
});
|
|
|
|
request(app).get("/%foobar").expect(400, done);
|
|
});
|
|
|
|
it("should not decode spaces", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/:name", function (req, res) {
|
|
res.send(req.params.name);
|
|
});
|
|
|
|
request(app).get("/foo+bar").expect("foo+bar", done);
|
|
});
|
|
|
|
it("should work with unicode", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/:name", function (req, res) {
|
|
res.send(req.params.name);
|
|
});
|
|
|
|
request(app).get("/%ce%b1").expect("\u03b1", done);
|
|
});
|
|
});
|
|
|
|
it("should be .use()able", function (done) {
|
|
var app = express();
|
|
|
|
var calls = [];
|
|
|
|
app.use(function (req, res, next) {
|
|
calls.push("before");
|
|
next();
|
|
});
|
|
|
|
app.get("/", function (req, res, next) {
|
|
calls.push("GET /");
|
|
next();
|
|
});
|
|
|
|
app.use(function (req, res, next) {
|
|
calls.push("after");
|
|
res.json(calls);
|
|
});
|
|
|
|
request(app).get("/").expect(200, ["before", "GET /", "after"], done);
|
|
});
|
|
|
|
describe("when given a regexp", function () {
|
|
it("should match the pathname only", function (done) {
|
|
var app = express();
|
|
|
|
app.get(/^\/user\/[0-9]+$/, function (req, res) {
|
|
res.end("user");
|
|
});
|
|
|
|
request(app).get("/user/12?foo=bar").expect("user", done);
|
|
});
|
|
|
|
it("should populate req.params with the captures", function (done) {
|
|
var app = express();
|
|
|
|
app.get(/^\/user\/([0-9]+)\/(view|edit)?$/, function (req, res) {
|
|
var id = req.params[0],
|
|
op = req.params[1];
|
|
res.end(op + "ing user " + id);
|
|
});
|
|
|
|
request(app).get("/user/10/edit").expect("editing user 10", done);
|
|
});
|
|
|
|
if (supportsRegexp("(?<foo>.*)")) {
|
|
it.todo("should populate req.params with named captures", function (done) {
|
|
var app = express();
|
|
var re = new RegExp("^/user/(?<userId>[0-9]+)/(view|edit)?$");
|
|
|
|
app.get(re, function (req, res) {
|
|
var id = req.params.userId,
|
|
op = req.params[0];
|
|
res.end(op + "ing user " + id);
|
|
});
|
|
|
|
request(app).get("/user/10/edit").expect("editing user 10", done);
|
|
});
|
|
}
|
|
|
|
it("should ensure regexp matches path prefix", function (done) {
|
|
var app = express();
|
|
var p = [];
|
|
|
|
app.use(/\/api.*/, function (req, res, next) {
|
|
p.push("a");
|
|
next();
|
|
});
|
|
app.use(/api/, function (req, res, next) {
|
|
p.push("b");
|
|
next();
|
|
});
|
|
app.use(/\/test/, function (req, res, next) {
|
|
p.push("c");
|
|
next();
|
|
});
|
|
app.use(function (req, res) {
|
|
res.end();
|
|
});
|
|
|
|
request(app)
|
|
.get("/test/api/1234")
|
|
.expect(200, function (err) {
|
|
if (err) return done(err);
|
|
assert.deepEqual(p, ["c"]);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("case sensitivity", function () {
|
|
it("should be disabled by default", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/USER").expect("tj", done);
|
|
});
|
|
|
|
describe('when "case sensitive routing" is enabled', function () {
|
|
it("should match identical casing", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("case sensitive routing");
|
|
|
|
app.get("/uSer", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/uSer").expect("tj", done);
|
|
});
|
|
|
|
it("should not match otherwise", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("case sensitive routing");
|
|
|
|
app.get("/uSer", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user").expect(404, done);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("params", function () {
|
|
it("should overwrite existing req.params by default", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.get("/:action", function (req, res) {
|
|
res.send(req.params);
|
|
});
|
|
|
|
app.use("/user/:user", router);
|
|
|
|
request(app).get("/user/1/get").expect(200, '{"action":"get"}', done);
|
|
});
|
|
|
|
it("should allow merging existing req.params", function (done) {
|
|
var app = express();
|
|
var router = new express.Router({ mergeParams: true });
|
|
|
|
router.get("/:action", function (req, res) {
|
|
var keys = Object.keys(req.params).sort();
|
|
res.send(
|
|
keys.map(function (k) {
|
|
return [k, req.params[k]];
|
|
}),
|
|
);
|
|
});
|
|
|
|
app.use("/user/:user", router);
|
|
|
|
request(app).get("/user/tj/get").expect(200, '[["action","get"],["user","tj"]]', done);
|
|
});
|
|
|
|
it("should use params from router", function (done) {
|
|
var app = express();
|
|
var router = new express.Router({ mergeParams: true });
|
|
|
|
router.get("/:thing", function (req, res) {
|
|
var keys = Object.keys(req.params).sort();
|
|
res.send(
|
|
keys.map(function (k) {
|
|
return [k, req.params[k]];
|
|
}),
|
|
);
|
|
});
|
|
|
|
app.use("/user/:thing", router);
|
|
|
|
request(app).get("/user/tj/get").expect(200, '[["thing","get"]]', done);
|
|
});
|
|
|
|
it("should merge numeric indices req.params", function (done) {
|
|
var app = express();
|
|
var router = new express.Router({ mergeParams: true });
|
|
|
|
router.get(/^\/(.*)\.(.*)/, function (req, res) {
|
|
var keys = Object.keys(req.params).sort();
|
|
res.send(
|
|
keys.map(function (k) {
|
|
return [k, req.params[k]];
|
|
}),
|
|
);
|
|
});
|
|
|
|
app.use(/^\/user\/id:(\d+)/, router);
|
|
|
|
request(app).get("/user/id:10/profile.json").expect(200, '[["0","10"],["1","profile"],["2","json"]]', done);
|
|
});
|
|
|
|
it("should merge numeric indices req.params when more in parent", function (done) {
|
|
var app = express();
|
|
var router = new express.Router({ mergeParams: true });
|
|
|
|
router.get(/\/(.*)/, function (req, res) {
|
|
var keys = Object.keys(req.params).sort();
|
|
res.send(
|
|
keys.map(function (k) {
|
|
return [k, req.params[k]];
|
|
}),
|
|
);
|
|
});
|
|
|
|
app.use(/^\/user\/id:(\d+)\/name:(\w+)/, router);
|
|
|
|
request(app).get("/user/id:10/name:tj/profile").expect(200, '[["0","10"],["1","tj"],["2","profile"]]', done);
|
|
});
|
|
|
|
it("should merge numeric indices req.params when parent has same number", function (done) {
|
|
var app = express();
|
|
var router = new express.Router({ mergeParams: true });
|
|
|
|
router.get(/\/name:(\w+)/, function (req, res) {
|
|
var keys = Object.keys(req.params).sort();
|
|
res.send(
|
|
keys.map(function (k) {
|
|
return [k, req.params[k]];
|
|
}),
|
|
);
|
|
});
|
|
|
|
app.use(/\/user\/id:(\d+)/, router);
|
|
|
|
request(app).get("/user/id:10/name:tj").expect(200, '[["0","10"],["1","tj"]]', done);
|
|
});
|
|
|
|
it("should ignore invalid incoming req.params", function (done) {
|
|
var app = express();
|
|
var router = new express.Router({ mergeParams: true });
|
|
|
|
router.get("/:name", function (req, res) {
|
|
var keys = Object.keys(req.params).sort();
|
|
res.send(
|
|
keys.map(function (k) {
|
|
return [k, req.params[k]];
|
|
}),
|
|
);
|
|
});
|
|
|
|
app.use("/user/", function (req, res, next) {
|
|
req.params = 3; // wat?
|
|
router(req, res, next);
|
|
});
|
|
|
|
request(app).get("/user/tj").expect(200, '[["name","tj"]]', done);
|
|
});
|
|
|
|
it("should restore req.params", function (done) {
|
|
var app = express();
|
|
var router = new express.Router({ mergeParams: true });
|
|
|
|
router.get(/\/user:(\w+)\//, function (req, res, next) {
|
|
next();
|
|
});
|
|
|
|
app.use(/\/user\/id:(\d+)/, function (req, res, next) {
|
|
router(req, res, function (err) {
|
|
var keys = Object.keys(req.params).sort();
|
|
res.send(
|
|
keys.map(function (k) {
|
|
return [k, req.params[k]];
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
request(app).get("/user/id:42/user:tj/profile").expect(200, '[["0","42"]]', done);
|
|
});
|
|
});
|
|
|
|
describe("trailing slashes", function () {
|
|
it("should be optional by default", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user/").expect("tj", done);
|
|
});
|
|
|
|
describe('when "strict routing" is enabled', function () {
|
|
it("should match trailing slashes", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.get("/user/", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user/").expect("tj", done);
|
|
});
|
|
|
|
it("should pass-though middleware", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.use(function (req, res, next) {
|
|
res.setHeader("x-middleware", "true");
|
|
next();
|
|
});
|
|
|
|
app.get("/user/", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user/").expect("x-middleware", "true").expect(200, "tj", done);
|
|
});
|
|
|
|
it("should pass-though mounted middleware", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.use("/user/", function (req, res, next) {
|
|
res.setHeader("x-middleware", "true");
|
|
next();
|
|
});
|
|
|
|
app.get("/user/test/", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user/test/").expect("x-middleware", "true").expect(200, "tj", done);
|
|
});
|
|
|
|
it("should match no slashes", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.get("/user", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user").expect("tj", done);
|
|
});
|
|
|
|
it("should match middleware when omitting the trailing slash", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.use("/user/", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user").expect(200, "tj", done);
|
|
});
|
|
|
|
it("should match middleware", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.use("/user", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user").expect(200, "tj", done);
|
|
});
|
|
|
|
it("should match middleware when adding the trailing slash", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.use("/user", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user/").expect(200, "tj", done);
|
|
});
|
|
|
|
it("should fail when omitting the trailing slash", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.get("/user/", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user").expect(404, done);
|
|
});
|
|
|
|
it("should fail when adding the trailing slash", function (done) {
|
|
var app = express();
|
|
|
|
app.enable("strict routing");
|
|
|
|
app.get("/user", function (req, res) {
|
|
res.end("tj");
|
|
});
|
|
|
|
request(app).get("/user/").expect(404, done);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should allow literal "."', function (done) {
|
|
var app = express();
|
|
|
|
app.get("/api/users/:from..:to", function (req, res) {
|
|
var from = req.params.from,
|
|
to = req.params.to;
|
|
|
|
res.end("users from " + from + " to " + to);
|
|
});
|
|
|
|
request(app).get("/api/users/1..50").expect("users from 1 to 50", done);
|
|
});
|
|
|
|
describe(":name", function () {
|
|
it("should denote a capture group", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/:user", function (req, res) {
|
|
res.end(req.params.user);
|
|
});
|
|
|
|
request(app).get("/user/tj").expect("tj", done);
|
|
});
|
|
|
|
it("should match a single segment only", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/:user", function (req, res) {
|
|
res.end(req.params.user);
|
|
});
|
|
|
|
request(app).get("/user/tj/edit").expect(404, done);
|
|
});
|
|
|
|
it("should allow several capture groups", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/:user/:op", function (req, res) {
|
|
res.end(req.params.op + "ing " + req.params.user);
|
|
});
|
|
|
|
request(app).get("/user/tj/edit").expect("editing tj", done);
|
|
});
|
|
|
|
it.todo("should work following a partial capture group", function (done) {
|
|
var app = express();
|
|
var cb = after(2, done);
|
|
|
|
app.get("/user{s}/:user/:op", function (req, res) {
|
|
res.end(req.params.op + "ing " + req.params.user + (req.url.startsWith("/users") ? " (old)" : ""));
|
|
});
|
|
|
|
request(app).get("/user/tj/edit").expect("editing tj", cb);
|
|
|
|
request(app).get("/users/tj/edit").expect("editing tj (old)", cb);
|
|
});
|
|
|
|
it("should work inside literal parenthesis", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/:user\\(:op\\)", function (req, res) {
|
|
res.end(req.params.op + "ing " + req.params.user);
|
|
});
|
|
|
|
request(app).get("/tj(edit)").expect("editing tj", done);
|
|
});
|
|
|
|
it("should work in array of paths", function (done) {
|
|
var app = express();
|
|
var cb = after(2, done);
|
|
|
|
app.get(["/user/:user/poke", "/user/:user/pokes"], function (req, res) {
|
|
res.end("poking " + req.params.user);
|
|
});
|
|
|
|
request(app).get("/user/tj/poke").expect("poking tj", cb);
|
|
|
|
request(app).get("/user/tj/pokes").expect("poking tj", cb);
|
|
});
|
|
});
|
|
|
|
describe.todo(":name?", function () {
|
|
it("should denote an optional capture group", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/:user{/:op}", function (req, res) {
|
|
var op = req.params.op || "view";
|
|
res.end(op + "ing " + req.params.user);
|
|
});
|
|
|
|
request(app).get("/user/tj").expect("viewing tj", done);
|
|
});
|
|
|
|
it("should populate the capture group", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/:user{/:op}", function (req, res) {
|
|
var op = req.params.op || "view";
|
|
res.end(op + "ing " + req.params.user);
|
|
});
|
|
|
|
request(app).get("/user/tj/edit").expect("editing tj", done);
|
|
});
|
|
});
|
|
|
|
describe.todo(":name*", function () {
|
|
it("should match one segment", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/*user", function (req, res) {
|
|
res.end(req.params.user[0]);
|
|
});
|
|
|
|
request(app).get("/user/122").expect("122", done);
|
|
});
|
|
|
|
it("should match many segments", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/*user", function (req, res) {
|
|
res.end(req.params.user.join("/"));
|
|
});
|
|
|
|
request(app).get("/user/1/2/3/4").expect("1/2/3/4", done);
|
|
});
|
|
|
|
it("should match zero segments", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user{/*user}", function (req, res) {
|
|
res.end(req.params.user);
|
|
});
|
|
|
|
request(app).get("/user").expect("", done);
|
|
});
|
|
});
|
|
|
|
describe.todo(":name+", function () {
|
|
it("should match one segment", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/*user", function (req, res) {
|
|
res.end(req.params.user[0]);
|
|
});
|
|
|
|
request(app).get("/user/122").expect(200, "122", done);
|
|
});
|
|
|
|
it("should match many segments", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/*user", function (req, res) {
|
|
res.end(req.params.user.join("/"));
|
|
});
|
|
|
|
request(app).get("/user/1/2/3/4").expect(200, "1/2/3/4", done);
|
|
});
|
|
|
|
it("should not match zero segments", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/user/*user", function (req, res) {
|
|
res.end(req.params.user);
|
|
});
|
|
|
|
request(app).get("/user").expect(404, done);
|
|
});
|
|
});
|
|
|
|
describe.todo(".:name", function () {
|
|
it("should denote a format", function (done) {
|
|
var app = express();
|
|
var cb = after(2, done);
|
|
|
|
app.get("/:name.:format", function (req, res) {
|
|
res.end(req.params.name + " as " + req.params.format);
|
|
});
|
|
|
|
request(app).get("/foo.json").expect(200, "foo as json", cb);
|
|
|
|
request(app).get("/foo").expect(404, cb);
|
|
});
|
|
});
|
|
|
|
describe.todo(".:name?", function () {
|
|
it("should denote an optional format", function (done) {
|
|
var app = express();
|
|
var cb = after(2, done);
|
|
|
|
app.get("/:name{.:format}", function (req, res) {
|
|
res.end(req.params.name + " as " + (req.params.format || "html"));
|
|
});
|
|
|
|
request(app).get("/foo").expect(200, "foo as html", cb);
|
|
|
|
request(app).get("/foo.json").expect(200, "foo as json", cb);
|
|
});
|
|
});
|
|
|
|
describe.todo("when next() is called", function () {
|
|
it("should continue lookup", function (done) {
|
|
var app = express(),
|
|
calls = [];
|
|
|
|
app.get("/foo{/:bar}", function (req, res, next) {
|
|
calls.push("/foo/:bar?");
|
|
next();
|
|
});
|
|
|
|
app.get("/bar", function () {
|
|
assert(0);
|
|
});
|
|
|
|
app.get("/foo", function (req, res, next) {
|
|
calls.push("/foo");
|
|
next();
|
|
});
|
|
|
|
app.get("/foo", function (req, res) {
|
|
calls.push("/foo 2");
|
|
res.json(calls);
|
|
});
|
|
|
|
request(app).get("/foo").expect(200, ["/foo/:bar?", "/foo", "/foo 2"], done);
|
|
});
|
|
});
|
|
|
|
describe('when next("route") is called', function () {
|
|
it("should jump to next route", function (done) {
|
|
var app = express();
|
|
|
|
function fn(req, res, next) {
|
|
res.set("X-Hit", "1");
|
|
next("route");
|
|
}
|
|
|
|
app.get("/foo", fn, function (req, res) {
|
|
res.end("failure");
|
|
});
|
|
|
|
app.get("/foo", function (req, res) {
|
|
res.end("success");
|
|
});
|
|
|
|
request(app).get("/foo").expect("X-Hit", "1").expect(200, "success", done);
|
|
});
|
|
});
|
|
|
|
describe('when next("router") is called', function () {
|
|
it("should jump out of router", function (done) {
|
|
var app = express();
|
|
var router = express.Router();
|
|
|
|
function fn(req, res, next) {
|
|
res.set("X-Hit", "1");
|
|
next("router");
|
|
}
|
|
|
|
router.get("/foo", fn, function (req, res) {
|
|
res.end("failure");
|
|
});
|
|
|
|
router.get("/foo", function (req, res) {
|
|
res.end("failure");
|
|
});
|
|
|
|
app.use(router);
|
|
|
|
app.get("/foo", function (req, res) {
|
|
res.end("success");
|
|
});
|
|
|
|
request(app).get("/foo").expect("X-Hit", "1").expect(200, "success", done);
|
|
});
|
|
});
|
|
|
|
describe("when next(err) is called", function () {
|
|
it.todo("should break out of app.router", function (done) {
|
|
var app = express(),
|
|
calls = [];
|
|
|
|
app.get("/foo{/:bar}", function (req, res, next) {
|
|
calls.push("/foo/:bar?");
|
|
next();
|
|
});
|
|
|
|
app.get("/bar", function () {
|
|
assert(0);
|
|
});
|
|
|
|
app.get("/foo", function (req, res, next) {
|
|
calls.push("/foo");
|
|
next(new Error("fail"));
|
|
});
|
|
|
|
app.get("/foo", function () {
|
|
assert(0);
|
|
});
|
|
|
|
app.use(function (err, req, res, next) {
|
|
res.json({
|
|
calls: calls,
|
|
error: err.message,
|
|
});
|
|
});
|
|
|
|
request(app)
|
|
.get("/foo")
|
|
.expect(200, { calls: ["/foo/:bar?", "/foo"], error: "fail" }, done);
|
|
});
|
|
|
|
it("should call handler in same route, if exists", function (done) {
|
|
var app = express();
|
|
|
|
function fn1(req, res, next) {
|
|
next(new Error("boom!"));
|
|
}
|
|
|
|
function fn2(req, res, next) {
|
|
res.send("foo here");
|
|
}
|
|
|
|
function fn3(err, req, res, next) {
|
|
res.send("route go " + err.message);
|
|
}
|
|
|
|
app.get("/foo", fn1, fn2, fn3);
|
|
|
|
app.use(function (err, req, res, next) {
|
|
res.end("error!");
|
|
});
|
|
|
|
request(app).get("/foo").expect("route go boom!", done);
|
|
});
|
|
});
|
|
|
|
// TODO: upgrade to express v5
|
|
describe.todo("promise support", function () {
|
|
it("should pass rejected promise value", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.use(function createError(req, res, next) {
|
|
return Promise.reject(new Error("boom!"));
|
|
});
|
|
|
|
router.use(function sawError(err, req, res, next) {
|
|
res.send("saw " + err.name + ": " + err.message);
|
|
});
|
|
|
|
app.use(router);
|
|
|
|
request(app).get("/").expect(200, "saw Error: boom!", done);
|
|
});
|
|
|
|
it("should pass rejected promise without value", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.use(function createError(req, res, next) {
|
|
return Promise.reject();
|
|
});
|
|
|
|
router.use(function sawError(err, req, res, next) {
|
|
res.send("saw " + err.name + ": " + err.message);
|
|
});
|
|
|
|
app.use(router);
|
|
|
|
request(app).get("/").expect(200, "saw Error: Rejected promise", done);
|
|
});
|
|
|
|
it("should ignore resolved promise", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.use(function createError(req, res, next) {
|
|
res.send("saw GET /foo");
|
|
return Promise.resolve("foo");
|
|
});
|
|
|
|
router.use(function () {
|
|
done(new Error("Unexpected middleware invoke"));
|
|
});
|
|
|
|
app.use(router);
|
|
|
|
request(app).get("/foo").expect(200, "saw GET /foo", done);
|
|
});
|
|
|
|
describe("error handling", function () {
|
|
it("should pass rejected promise value", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.use(function createError(req, res, next) {
|
|
return Promise.reject(new Error("boom!"));
|
|
});
|
|
|
|
router.use(function handleError(err, req, res, next) {
|
|
return Promise.reject(new Error("caught: " + err.message));
|
|
});
|
|
|
|
router.use(function sawError(err, req, res, next) {
|
|
res.send("saw " + err.name + ": " + err.message);
|
|
});
|
|
|
|
app.use(router);
|
|
|
|
request(app).get("/").expect(200, "saw Error: caught: boom!", done);
|
|
});
|
|
|
|
it("should pass rejected promise without value", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.use(function createError(req, res, next) {
|
|
return Promise.reject();
|
|
});
|
|
|
|
router.use(function handleError(err, req, res, next) {
|
|
return Promise.reject(new Error("caught: " + err.message));
|
|
});
|
|
|
|
router.use(function sawError(err, req, res, next) {
|
|
res.send("saw " + err.name + ": " + err.message);
|
|
});
|
|
|
|
app.use(router);
|
|
|
|
request(app).get("/").expect(200, "saw Error: caught: Rejected promise", done);
|
|
});
|
|
|
|
it("should ignore resolved promise", function (done) {
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.use(function createError(req, res, next) {
|
|
return Promise.reject(new Error("boom!"));
|
|
});
|
|
|
|
router.use(function handleError(err, req, res, next) {
|
|
res.send("saw " + err.name + ": " + err.message);
|
|
return Promise.resolve("foo");
|
|
});
|
|
|
|
router.use(function () {
|
|
done(new Error("Unexpected middleware invoke"));
|
|
});
|
|
|
|
app.use(router);
|
|
|
|
request(app).get("/foo").expect(200, "saw Error: boom!", done);
|
|
});
|
|
});
|
|
});
|
|
|
|
it("should allow rewriting of the url", function (done) {
|
|
var app = express();
|
|
|
|
app.get("/account/edit", function (req, res, next) {
|
|
req.user = { id: 12 }; // faux authenticated user
|
|
req.url = "/user/" + req.user.id + "/edit";
|
|
next();
|
|
});
|
|
|
|
app.get("/user/:id/edit", function (req, res) {
|
|
res.send("editing user " + req.params.id);
|
|
});
|
|
|
|
request(app).get("/account/edit").expect("editing user 12", done);
|
|
});
|
|
|
|
it.todo("should run in order added", function (done) {
|
|
var app = express();
|
|
var path = [];
|
|
|
|
app.get("/*path", function (req, res, next) {
|
|
path.push(0);
|
|
next();
|
|
});
|
|
|
|
app.get("/user/:id", function (req, res, next) {
|
|
path.push(1);
|
|
next();
|
|
});
|
|
|
|
app.use(function (req, res, next) {
|
|
path.push(2);
|
|
next();
|
|
});
|
|
|
|
app.all("/user/:id", function (req, res, next) {
|
|
path.push(3);
|
|
next();
|
|
});
|
|
|
|
app.get("/*splat", function (req, res, next) {
|
|
path.push(4);
|
|
next();
|
|
});
|
|
|
|
app.use(function (req, res, next) {
|
|
path.push(5);
|
|
res.end(path.join(","));
|
|
});
|
|
|
|
request(app).get("/user/1").expect(200, "0,1,2,3,4,5", done);
|
|
});
|
|
|
|
it("should be chainable", function () {
|
|
var app = express();
|
|
assert.strictEqual(
|
|
app.get("/", function () {}),
|
|
app,
|
|
);
|
|
});
|
|
|
|
it("should should not use disposed router/middleware", function (done) {
|
|
// more context: https://github.com/expressjs/express/issues/5743#issuecomment-2277148412
|
|
|
|
var app = express();
|
|
var router = new express.Router();
|
|
|
|
router.use(function (req, res, next) {
|
|
res.setHeader("old", "foo");
|
|
next();
|
|
});
|
|
|
|
app.use(function (req, res, next) {
|
|
return router.handle(req, res, next);
|
|
});
|
|
|
|
app.get("/", function (req, res, next) {
|
|
res.send("yee");
|
|
next();
|
|
});
|
|
|
|
request(app)
|
|
.get("/")
|
|
.expect("old", "foo")
|
|
.expect(function (res) {
|
|
if (typeof res.headers["new"] !== "undefined") {
|
|
throw new Error("`new` header should not be present");
|
|
}
|
|
})
|
|
.expect(200, "yee", function (err, res) {
|
|
if (err) return done(err);
|
|
|
|
router = new express.Router();
|
|
|
|
router.use(function (req, res, next) {
|
|
res.setHeader("new", "bar");
|
|
next();
|
|
});
|
|
|
|
request(app)
|
|
.get("/")
|
|
.expect("new", "bar")
|
|
.expect(function (res) {
|
|
if (typeof res.headers["old"] !== "undefined") {
|
|
throw new Error("`old` header should not be present");
|
|
}
|
|
})
|
|
.expect(200, "yee", done);
|
|
});
|
|
});
|
|
});
|
|
|
|
function supportsRegexp(source) {
|
|
try {
|
|
new RegExp(source);
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|