mirror of
https://github.com/oven-sh/bun
synced 2026-02-07 17:38:46 +00:00
Compare commits
3 Commits
dylan/pyth
...
nektro-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2637c36235 | ||
|
|
2b80d8c83b | ||
|
|
0eb7fe1c38 |
1
.github/workflows/update-vendor.yml
vendored
1
.github/workflows/update-vendor.yml
vendored
@@ -16,6 +16,7 @@ jobs:
|
||||
matrix:
|
||||
package:
|
||||
- elysia
|
||||
- express
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -91,5 +91,6 @@ The following globals are automatically available in test files without importin
|
||||
- `describe`: Group tests
|
||||
- `expect`: Make assertions
|
||||
- `beforeAll`, `beforeEach`, `afterAll`, `afterEach`: Lifecycle hooks
|
||||
- `before`, `after`: Alias for `beforeAll`/`afterAll` respectively to better support [Mocha](https://mochajs.org)
|
||||
- `jest`: Jest global object
|
||||
- `vi`: Vitest compatibility alias for common jest methods
|
||||
|
||||
@@ -477,7 +477,7 @@ async function runTests() {
|
||||
failure ||= result;
|
||||
flaky ||= true;
|
||||
|
||||
if (attempt >= maxAttempts || isAlwaysFailure(error)) {
|
||||
if (attempt >= maxAttempts || isAlwaysFailure(error) || title.startsWith("vendor")) {
|
||||
flaky = false;
|
||||
failedResults.push(failure);
|
||||
failedResultsTitles.push(title);
|
||||
@@ -492,7 +492,7 @@ async function runTests() {
|
||||
if (isBuildkite) {
|
||||
// Group flaky tests together, regardless of the title
|
||||
const context = flaky ? "flaky" : title;
|
||||
const style = flaky || title.startsWith("vendor") ? "warning" : "error";
|
||||
const style = flaky ? "warning" : "error";
|
||||
if (!flaky) attempt = 1; // no need to show the retries count on failures, we know it maxed out
|
||||
|
||||
if (title.startsWith("vendor")) {
|
||||
@@ -644,7 +644,7 @@ async function runTests() {
|
||||
}
|
||||
|
||||
if (vendorTests?.length) {
|
||||
for (const { cwd: vendorPath, packageManager, testRunner, testPaths } of vendorTests) {
|
||||
for (const { cwd: vendorPath, packageManager, testRunner, testPaths, build } of vendorTests) {
|
||||
if (!testPaths.length) {
|
||||
continue;
|
||||
}
|
||||
@@ -659,13 +659,12 @@ async function runTests() {
|
||||
throw new Error(`Unsupported package manager: ${packageManager}`);
|
||||
}
|
||||
|
||||
// build
|
||||
const buildResult = await spawnBun(execPath, {
|
||||
cwd: vendorPath,
|
||||
args: ["run", "build"],
|
||||
timeout: 60_000,
|
||||
});
|
||||
if (!buildResult.ok) {
|
||||
if (build && !buildResult.ok) {
|
||||
throw new Error(`Failed to build vendor: ${buildResult.error}`);
|
||||
}
|
||||
|
||||
@@ -1660,6 +1659,7 @@ function getTests(cwd) {
|
||||
* @property {string} [testRunner]
|
||||
* @property {string[]} [testExtensions]
|
||||
* @property {boolean | Record<string, boolean | string>} [skipTests]
|
||||
* @property {boolean} [build]
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -1668,6 +1668,7 @@ function getTests(cwd) {
|
||||
* @property {string} packageManager
|
||||
* @property {string} testRunner
|
||||
* @property {string[]} testPaths
|
||||
* @property {boolean} build
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -1702,7 +1703,17 @@ async function getVendorTests(cwd) {
|
||||
|
||||
return Promise.all(
|
||||
relevantVendors.map(
|
||||
async ({ package: name, repository, tag, testPath, testExtensions, testRunner, packageManager, skipTests }) => {
|
||||
async ({
|
||||
package: name,
|
||||
repository,
|
||||
tag,
|
||||
testPath,
|
||||
testExtensions,
|
||||
testRunner,
|
||||
packageManager,
|
||||
skipTests,
|
||||
build,
|
||||
}) => {
|
||||
const vendorPath = join(cwd, "vendor", name);
|
||||
|
||||
if (!existsSync(vendorPath)) {
|
||||
@@ -1779,6 +1790,7 @@ async function getVendorTests(cwd) {
|
||||
packageManager: packageManager || "bun",
|
||||
testRunner: testRunner || "bun",
|
||||
testPaths,
|
||||
build: build ?? true,
|
||||
};
|
||||
},
|
||||
),
|
||||
|
||||
@@ -2080,9 +2080,11 @@ pub fn NewParser_(
|
||||
p.jest.expect = try p.declareCommonJSSymbol(.unbound, "expect");
|
||||
p.jest.expectTypeOf = try p.declareCommonJSSymbol(.unbound, "expectTypeOf");
|
||||
p.jest.beforeAll = try p.declareCommonJSSymbol(.unbound, "beforeAll");
|
||||
p.jest.before = try p.declareCommonJSSymbol(.unbound, "before");
|
||||
p.jest.beforeEach = try p.declareCommonJSSymbol(.unbound, "beforeEach");
|
||||
p.jest.afterEach = try p.declareCommonJSSymbol(.unbound, "afterEach");
|
||||
p.jest.afterAll = try p.declareCommonJSSymbol(.unbound, "afterAll");
|
||||
p.jest.after = try p.declareCommonJSSymbol(.unbound, "after");
|
||||
p.jest.jest = try p.declareCommonJSSymbol(.unbound, "jest");
|
||||
p.jest.vi = try p.declareCommonJSSymbol(.unbound, "vi");
|
||||
p.jest.xit = try p.declareCommonJSSymbol(.unbound, "xit");
|
||||
|
||||
@@ -62,6 +62,7 @@ pub fn generateOrderDescribe(this: *Order, current: *DescribeScope) bun.JSError!
|
||||
|
||||
// gather beforeAll
|
||||
const beforeall_order: AllOrderResult = if (use_hooks) try generateAllOrder(this, current.beforeAll.items) else .empty;
|
||||
const before_order: AllOrderResult = if (use_hooks) try generateAllOrder(this, current.before.items) else .empty;
|
||||
|
||||
// shuffle entries if randomize flag is set
|
||||
if (this.cfg.randomize) |random| {
|
||||
@@ -76,12 +77,15 @@ pub fn generateOrderDescribe(this: *Order, current: *DescribeScope) bun.JSError!
|
||||
|
||||
// update skip_to values for beforeAll to skip to the first afterAll
|
||||
beforeall_order.setFailureSkipTo(this);
|
||||
before_order.setFailureSkipTo(this);
|
||||
|
||||
// gather afterAll
|
||||
const afterall_order: AllOrderResult = if (use_hooks) try generateAllOrder(this, current.afterAll.items) else .empty;
|
||||
const after_order: AllOrderResult = if (use_hooks) try generateAllOrder(this, current.after.items) else .empty;
|
||||
|
||||
// update skip_to values for afterAll to skip the remaining afterAll items
|
||||
afterall_order.setFailureSkipTo(this);
|
||||
after_order.setFailureSkipTo(this);
|
||||
}
|
||||
|
||||
const EntryList = struct {
|
||||
|
||||
@@ -583,10 +583,14 @@ pub const BunTest = struct {
|
||||
defer order.deinit();
|
||||
|
||||
const beforeall_order: Order.AllOrderResult = if (this.first_last.first) try order.generateAllOrder(this.bun_test_root.hook_scope.beforeAll.items) else .empty;
|
||||
const before_order: Order.AllOrderResult = if (this.first_last.first) try order.generateAllOrder(this.bun_test_root.hook_scope.before.items) else .empty;
|
||||
try order.generateOrderDescribe(this.collection.root_scope);
|
||||
beforeall_order.setFailureSkipTo(&order);
|
||||
before_order.setFailureSkipTo(&order);
|
||||
const afterall_order: Order.AllOrderResult = if (this.first_last.last) try order.generateAllOrder(this.bun_test_root.hook_scope.afterAll.items) else .empty;
|
||||
const after_order: Order.AllOrderResult = if (this.first_last.last) try order.generateAllOrder(this.bun_test_root.hook_scope.after.items) else .empty;
|
||||
afterall_order.setFailureSkipTo(&order);
|
||||
after_order.setFailureSkipTo(&order);
|
||||
|
||||
try this.execution.loadFromOrder(&order);
|
||||
try debug.dumpOrder(&this.execution);
|
||||
@@ -828,9 +832,11 @@ pub const DescribeScope = struct {
|
||||
base: BaseScope,
|
||||
entries: std.ArrayList(TestScheduleEntry),
|
||||
beforeAll: std.ArrayList(*ExecutionEntry),
|
||||
before: std.ArrayList(*ExecutionEntry),
|
||||
beforeEach: std.ArrayList(*ExecutionEntry),
|
||||
afterEach: std.ArrayList(*ExecutionEntry),
|
||||
afterAll: std.ArrayList(*ExecutionEntry),
|
||||
after: std.ArrayList(*ExecutionEntry),
|
||||
|
||||
/// if true, the describe callback threw an error. do not run any tests declared in this scope.
|
||||
failed: bool = false,
|
||||
@@ -841,20 +847,26 @@ pub const DescribeScope = struct {
|
||||
.entries = .init(gpa),
|
||||
.beforeEach = .init(gpa),
|
||||
.beforeAll = .init(gpa),
|
||||
.before = .init(gpa),
|
||||
.afterAll = .init(gpa),
|
||||
.after = .init(gpa),
|
||||
.afterEach = .init(gpa),
|
||||
});
|
||||
}
|
||||
pub fn destroy(this: *DescribeScope, gpa: std.mem.Allocator) void {
|
||||
for (this.entries.items) |*entry| entry.deinit(gpa);
|
||||
for (this.beforeAll.items) |item| item.destroy(gpa);
|
||||
for (this.before.items) |item| item.destroy(gpa);
|
||||
for (this.beforeEach.items) |item| item.destroy(gpa);
|
||||
for (this.afterAll.items) |item| item.destroy(gpa);
|
||||
for (this.after.items) |item| item.destroy(gpa);
|
||||
for (this.afterEach.items) |item| item.destroy(gpa);
|
||||
this.entries.deinit();
|
||||
this.beforeAll.deinit();
|
||||
this.before.deinit();
|
||||
this.beforeEach.deinit();
|
||||
this.afterAll.deinit();
|
||||
this.after.deinit();
|
||||
this.afterEach.deinit();
|
||||
this.base.deinit(gpa);
|
||||
gpa.destroy(this);
|
||||
@@ -889,13 +901,15 @@ pub const DescribeScope = struct {
|
||||
try this.entries.append(.{ .test_callback = entry });
|
||||
return entry;
|
||||
}
|
||||
pub const HookTag = enum { beforeAll, beforeEach, afterEach, afterAll };
|
||||
pub const HookTag = enum { beforeAll, before, beforeEach, afterEach, afterAll, after };
|
||||
pub fn getHookEntries(this: *DescribeScope, tag: HookTag) *std.ArrayList(*ExecutionEntry) {
|
||||
switch (tag) {
|
||||
.beforeAll => return &this.beforeAll,
|
||||
.before => return &this.before,
|
||||
.beforeEach => return &this.beforeEach,
|
||||
.afterEach => return &this.afterEach,
|
||||
.afterAll => return &this.afterAll,
|
||||
.after => return &this.after,
|
||||
}
|
||||
}
|
||||
pub fn appendHook(this: *DescribeScope, gpa: std.mem.Allocator, tag: HookTag, callback: ?jsc.JSValue, cfg: ExecutionEntryCfg, base: BaseScopeCfg, phase: ExecutionEntry.AddedInPhase) bun.JSError!*ExecutionEntry {
|
||||
|
||||
@@ -11,10 +11,12 @@ pub fn dumpDescribe(describe: *DescribeScope) bun.JSError!void {
|
||||
defer group.end();
|
||||
|
||||
for (describe.beforeAll.items) |entry| try dumpTest(entry, "beforeAll");
|
||||
for (describe.before.items) |entry| try dumpTest(entry, "before");
|
||||
for (describe.beforeEach.items) |entry| try dumpTest(entry, "beforeEach");
|
||||
for (describe.entries.items) |entry| try dumpSub(entry);
|
||||
for (describe.afterEach.items) |entry| try dumpTest(entry, "afterEach");
|
||||
for (describe.afterAll.items) |entry| try dumpTest(entry, "afterAll");
|
||||
for (describe.after.items) |entry| try dumpTest(entry, "after");
|
||||
}
|
||||
pub fn dumpTest(current: *ExecutionEntry, label: []const u8) bun.JSError!void {
|
||||
if (!group.getLogEnabled()) return;
|
||||
|
||||
@@ -181,7 +181,9 @@ pub const Jest = struct {
|
||||
|
||||
module.put(globalObject, ZigString.static("beforeEach"), jsc.host_fn.NewFunction(globalObject, ZigString.static("beforeEach"), 1, bun_test.js_fns.genericHook(.beforeEach).hookFn, false));
|
||||
module.put(globalObject, ZigString.static("beforeAll"), jsc.host_fn.NewFunction(globalObject, ZigString.static("beforeAll"), 1, bun_test.js_fns.genericHook(.beforeAll).hookFn, false));
|
||||
module.put(globalObject, ZigString.static("before"), jsc.host_fn.NewFunction(globalObject, ZigString.static("before"), 1, bun_test.js_fns.genericHook(.before).hookFn, false));
|
||||
module.put(globalObject, ZigString.static("afterAll"), jsc.host_fn.NewFunction(globalObject, ZigString.static("afterAll"), 1, bun_test.js_fns.genericHook(.afterAll).hookFn, false));
|
||||
module.put(globalObject, ZigString.static("after"), jsc.host_fn.NewFunction(globalObject, ZigString.static("after"), 1, bun_test.js_fns.genericHook(.after).hookFn, false));
|
||||
module.put(globalObject, ZigString.static("afterEach"), jsc.host_fn.NewFunction(globalObject, ZigString.static("afterEach"), 1, bun_test.js_fns.genericHook(.afterEach).hookFn, false));
|
||||
module.put(globalObject, ZigString.static("setDefaultTimeout"), jsc.host_fn.NewFunction(globalObject, ZigString.static("setDefaultTimeout"), 1, jsSetDefaultTimeout, false));
|
||||
module.put(globalObject, ZigString.static("expect"), Expect.js.getConstructor(globalObject));
|
||||
|
||||
@@ -936,9 +936,11 @@ pub const Jest = struct {
|
||||
expect: Ref = Ref.None,
|
||||
expectTypeOf: Ref = Ref.None,
|
||||
beforeAll: Ref = Ref.None,
|
||||
before: Ref = Ref.None,
|
||||
beforeEach: Ref = Ref.None,
|
||||
afterEach: Ref = Ref.None,
|
||||
afterAll: Ref = Ref.None,
|
||||
after: Ref = Ref.None,
|
||||
jest: Ref = Ref.None,
|
||||
vi: Ref = Ref.None,
|
||||
xit: Ref = Ref.None,
|
||||
|
||||
1
test/js/third_party/express/README.md
vendored
1
test/js/third_party/express/README.md
vendored
@@ -1 +0,0 @@
|
||||
Test cases ported from [express](https://github.com/expressjs/express). MIT license.
|
||||
1108
test/js/third_party/express/app.router.test.ts
vendored
1108
test/js/third_party/express/app.router.test.ts
vendored
File diff suppressed because it is too large
Load Diff
745
test/js/third_party/express/express.json.test.ts
vendored
745
test/js/third_party/express/express.json.test.ts
vendored
@@ -1,745 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var assert = require("node:assert");
|
||||
var AsyncLocalStorage = require("node:async_hooks").AsyncLocalStorage;
|
||||
|
||||
var express = require("express");
|
||||
var request = require("supertest");
|
||||
|
||||
describe("express.json()", function () {
|
||||
let app;
|
||||
|
||||
it("should parse JSON", function (done) {
|
||||
request(createApp())
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it("should handle Content-Length: 0", function (done) {
|
||||
request(createApp())
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.set("Content-Length", "0")
|
||||
.expect(200, "{}", done);
|
||||
});
|
||||
|
||||
it.todo("should handle empty message-body", function (done) {
|
||||
request(createApp())
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.set("Transfer-Encoding", "chunked")
|
||||
.expect(200, "{}", done);
|
||||
});
|
||||
|
||||
it("should handle no message-body", function (done) {
|
||||
request(createApp())
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.unset("Transfer-Encoding")
|
||||
.expect(200, "{}", done);
|
||||
});
|
||||
|
||||
// The old node error message modification in body parser is catching this
|
||||
it("should 400 when only whitespace", function (done) {
|
||||
request(createApp())
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send(" \n")
|
||||
.expect(400, "[entity.parse.failed] " + parseError(" \n"), done);
|
||||
});
|
||||
|
||||
it("should 400 when invalid content-length", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.headers["content-length"] = "20"; // bad length
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"str":')
|
||||
.expect(400, /content length/, done);
|
||||
});
|
||||
|
||||
it("should handle duplicated middleware", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(express.json());
|
||||
app.use(express.json());
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
describe("when JSON is invalid", function () {
|
||||
let app;
|
||||
beforeAll(function () {
|
||||
app = createApp();
|
||||
});
|
||||
|
||||
it("should 400 for bad token", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send("{:")
|
||||
.expect(400, "[entity.parse.failed] " + parseError("{:"), done);
|
||||
});
|
||||
|
||||
it("should 400 for incomplete", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user"')
|
||||
.expect(400, "[entity.parse.failed] " + parseError('{"user"'), done);
|
||||
});
|
||||
|
||||
it("should include original body on error object", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.set("X-Error-Property", "body")
|
||||
.send(' {"user"')
|
||||
.expect(400, ' {"user"', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with limit option", function () {
|
||||
it("should 413 when over limit with Content-Length", function (done) {
|
||||
var buf = Buffer.alloc(1024, ".");
|
||||
request(createApp({ limit: "1kb" }))
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.set("Content-Length", "1034")
|
||||
.send(JSON.stringify({ str: buf.toString() }))
|
||||
.expect(413, "[entity.too.large] request entity too large", done);
|
||||
});
|
||||
|
||||
it("should 413 when over limit with chunked encoding", function (done) {
|
||||
var app = createApp({ limit: "1kb" });
|
||||
var buf = Buffer.alloc(1024, ".");
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.set("Transfer-Encoding", "chunked");
|
||||
test.write('{"str":');
|
||||
test.write('"' + buf.toString() + '"}');
|
||||
test.expect(413, done);
|
||||
});
|
||||
|
||||
it("should 413 when inflated body over limit", function (done) {
|
||||
var app = createApp({ limit: "1kb" });
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000aab562a2e2952b252d21b05a360148c58a0540b0066f7ce1e0a040000", "hex"));
|
||||
test.expect(413, done);
|
||||
});
|
||||
|
||||
it("should accept number of bytes", function (done) {
|
||||
var buf = Buffer.alloc(1024, ".");
|
||||
request(createApp({ limit: 1024 }))
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send(JSON.stringify({ str: buf.toString() }))
|
||||
.expect(413, done);
|
||||
});
|
||||
|
||||
it("should not change when options altered", function (done) {
|
||||
var buf = Buffer.alloc(1024, ".");
|
||||
var options = { limit: "1kb" };
|
||||
var app = createApp(options);
|
||||
|
||||
options.limit = "100kb";
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send(JSON.stringify({ str: buf.toString() }))
|
||||
.expect(413, done);
|
||||
});
|
||||
|
||||
it("should not hang response", function (done) {
|
||||
var buf = Buffer.alloc(10240, ".");
|
||||
var app = createApp({ limit: "8kb" });
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(buf);
|
||||
test.write(buf);
|
||||
test.write(buf);
|
||||
test.expect(413, done);
|
||||
});
|
||||
|
||||
it("should not error when inflating", function (done) {
|
||||
var app = createApp({ limit: "1kb" });
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000aab562a2e2952b252d21b05a360148c58a0540b0066f7ce1e0a0400", "hex"));
|
||||
test.expect(413, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with inflate option", function () {
|
||||
describe("when false", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ inflate: false });
|
||||
});
|
||||
|
||||
it.todo("should not accept content-encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
|
||||
test.expect(415, "[encoding.unsupported] content encoding unsupported", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when true", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ inflate: true });
|
||||
});
|
||||
|
||||
it("should accept content-encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with strict option", function () {
|
||||
describe("when undefined", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp();
|
||||
});
|
||||
|
||||
it("should 400 on primitives", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send("true")
|
||||
.expect(400, "[entity.parse.failed] " + parseError("#rue").replace(/#/g, "t"), done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when false", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ strict: false });
|
||||
});
|
||||
|
||||
it.todo("should parse primitives", function (done) {
|
||||
request(app).post("/").set("Content-Type", "application/json").send("true").expect(200, "true", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when true", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ strict: true });
|
||||
});
|
||||
|
||||
it("should not parse primitives", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send("true")
|
||||
.expect(400, "[entity.parse.failed] " + parseError("#rue").replace(/#/g, "t"), done);
|
||||
});
|
||||
|
||||
it("should not parse primitives with leading whitespaces", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send(" true")
|
||||
.expect(400, "[entity.parse.failed] " + parseError(" #rue").replace(/#/g, "t"), done);
|
||||
});
|
||||
|
||||
it("should allow leading whitespaces in JSON", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send(' { "user": "tobi" }')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it("should include correct message in stack trace", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.set("X-Error-Property", "stack")
|
||||
.send("true")
|
||||
.expect(400)
|
||||
.expect(shouldContainInBody(parseError("#rue").replace(/#/g, "t")))
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with type option", function () {
|
||||
describe.skip('when "application/vnd.api+json"', function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ type: "application/vnd.api+json" });
|
||||
});
|
||||
|
||||
it("should parse JSON for custom type", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/vnd.api+json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it("should ignore standard type", function (done) {
|
||||
request(app).post("/").set("Content-Type", "application/json").send('{"user":"tobi"}').expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when ["application/json", "application/vnd.api+json"]', function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({
|
||||
type: ["application/json", "application/vnd.api+json"],
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse JSON for "application/json"', function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it.todo('should parse JSON for "application/vnd.api+json"', function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/vnd.api+json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it.todo('should ignore "application/x-json"', function (done) {
|
||||
request(app).post("/").set("Content-Type", "application/x-json").send('{"user":"tobi"}').expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when a function", function () {
|
||||
it("should parse when truthy value returned", function (done) {
|
||||
var app = createApp({ type: accept });
|
||||
|
||||
function accept(req) {
|
||||
return req.headers["content-type"] === "application/vnd.api+json";
|
||||
}
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/vnd.api+json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it("should work without content-type", function (done) {
|
||||
var app = createApp({ type: accept });
|
||||
|
||||
function accept(req) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var test = request(app).post("/");
|
||||
test.write('{"user":"tobi"}');
|
||||
test.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it("should not invoke without a body", function (done) {
|
||||
var app = createApp({ type: accept });
|
||||
|
||||
function accept(req) {
|
||||
throw new Error("oops!");
|
||||
}
|
||||
|
||||
request(app).get("/").expect(404, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with verify option", function () {
|
||||
it("should assert value if function", function () {
|
||||
assert.throws(createApp.bind(null, { verify: "lol" }), /TypeError: option verify must be function/);
|
||||
});
|
||||
|
||||
it("should error from verify", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] === 0x5b) throw new Error("no arrays");
|
||||
},
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('["tobi"]')
|
||||
.expect(403, "[entity.verify.failed] no arrays", done);
|
||||
});
|
||||
|
||||
it("should allow custom codes", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] !== 0x5b) return;
|
||||
var err = new Error("no arrays");
|
||||
err.status = 400;
|
||||
throw err;
|
||||
},
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('["tobi"]')
|
||||
.expect(400, "[entity.verify.failed] no arrays", done);
|
||||
});
|
||||
|
||||
it("should allow custom type", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] !== 0x5b) return;
|
||||
var err = new Error("no arrays");
|
||||
err.type = "foo.bar";
|
||||
throw err;
|
||||
},
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('["tobi"]')
|
||||
.expect(403, "[foo.bar] no arrays", done);
|
||||
});
|
||||
|
||||
it("should include original body on error object", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] === 0x5b) throw new Error("no arrays");
|
||||
},
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.set("X-Error-Property", "body")
|
||||
.send('["tobi"]')
|
||||
.expect(403, '["tobi"]', done);
|
||||
});
|
||||
|
||||
it("should allow pass-through", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] === 0x5b) throw new Error("no arrays");
|
||||
},
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{"user":"tobi"}', done);
|
||||
});
|
||||
|
||||
it("should work with different charsets", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] === 0x5b) throw new Error("no arrays");
|
||||
},
|
||||
});
|
||||
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json; charset=utf-16");
|
||||
test.write(Buffer.from("feff007b0022006e0061006d00650022003a00228bba0022007d", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should 415 on unknown charset prior to verify", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
throw new Error("unexpected verify call");
|
||||
},
|
||||
});
|
||||
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json; charset=x-bogus");
|
||||
test.write(Buffer.from("00000000", "hex"));
|
||||
test.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe.todo("async local storage", function () {
|
||||
beforeAll(function () {
|
||||
var app = express();
|
||||
var store = { foo: "bar" };
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new AsyncLocalStorage();
|
||||
req.asyncLocalStorage.run(store, next);
|
||||
});
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
var local = req.asyncLocalStorage.getStore();
|
||||
|
||||
if (local) {
|
||||
res.setHeader("x-store-foo", String(local.foo));
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
var local = req.asyncLocalStorage.getStore();
|
||||
|
||||
if (local) {
|
||||
res.setHeader("x-store-foo", String(local.foo));
|
||||
}
|
||||
|
||||
res.status(err.status || 500);
|
||||
res.send("[" + err.type + "] " + err.message);
|
||||
});
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
app = app;
|
||||
});
|
||||
|
||||
it("should presist store", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200)
|
||||
.expect("x-store-foo", "bar")
|
||||
.expect('{"user":"tobi"}')
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it("should persist store when unmatched content-type", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/fizzbuzz")
|
||||
.send("buzz")
|
||||
.expect(200)
|
||||
.expect("x-store-foo", "bar")
|
||||
.expect("")
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when inflated", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
|
||||
test.expect(200);
|
||||
test.expect("x-store-foo", "bar");
|
||||
test.expect('{"name":"论"}');
|
||||
test.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when inflate error", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
|
||||
test.expect(400);
|
||||
test.expect("x-store-foo", "bar");
|
||||
test.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when parse error", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user":')
|
||||
.expect(400)
|
||||
.expect("x-store-foo", "bar")
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when limit exceeded", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/json")
|
||||
.send('{"user":"' + Buffer.alloc(1024 * 100, ".").toString() + '"}')
|
||||
.expect(413)
|
||||
.expect("x-store-foo", "bar")
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("charset", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp();
|
||||
});
|
||||
|
||||
it("should parse utf-8", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json; charset=utf-8");
|
||||
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should parse utf-16", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json; charset=utf-16");
|
||||
test.write(Buffer.from("feff007b0022006e0061006d00650022003a00228bba0022007d", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should parse when content-length != char length", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json; charset=utf-8");
|
||||
test.set("Content-Length", "13");
|
||||
test.write(Buffer.from("7b2274657374223a22c3a5227d", "hex"));
|
||||
test.expect(200, '{"test":"å"}', done);
|
||||
});
|
||||
|
||||
it("should default to utf-8", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should fail on unknown charset", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json; charset=koi8-r");
|
||||
test.write(Buffer.from("7b226e616d65223a22cec5d4227d", "hex"));
|
||||
test.expect(415, '[charset.unsupported] unsupported charset "KOI8-R"', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("encoding", function () {
|
||||
let app;
|
||||
beforeAll(function () {
|
||||
app = createApp({ limit: "1kb" });
|
||||
});
|
||||
|
||||
it("should parse without encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should support identity encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "identity");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should support gzip encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should support deflate encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "deflate");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("789cab56ca4bcc4d55b2527ab16e97522d00274505ac", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should be case-insensitive", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "GZIP");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
|
||||
test.expect(200, '{"name":"论"}', done);
|
||||
});
|
||||
|
||||
it("should 415 on unknown encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "nulls");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("000000000000", "hex"));
|
||||
test.expect(415, '[encoding.unsupported] unsupported content encoding "nulls"', done);
|
||||
});
|
||||
|
||||
it("should 400 on malformed encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
|
||||
test.expect(400, done);
|
||||
});
|
||||
|
||||
it("should 413 when inflated value exceeds limit", function (done) {
|
||||
// gzip'd data exceeds 1kb, but deflated below 1kb
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "application/json");
|
||||
test.write(Buffer.from("1f8b080000000000000bedc1010d000000c2a0f74f6d0f071400000000000000", "hex"));
|
||||
test.write(Buffer.from("0000000000000000000000000000000000000000000000000000000000000000", "hex"));
|
||||
test.write(Buffer.from("0000000000000000004f0625b3b71650c30000", "hex"));
|
||||
test.expect(413, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createApp(options?) {
|
||||
var app = express();
|
||||
|
||||
app.use(express.json(options));
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
// console.log(err)
|
||||
res.status(err.status || 500);
|
||||
res.send(
|
||||
String(
|
||||
req.headers["x-error-property"] ? err[req.headers["x-error-property"]] : "[" + err.type + "] " + err.message,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
function parseError(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
throw new SyntaxError("strict violation");
|
||||
} catch (e) {
|
||||
return e.message;
|
||||
}
|
||||
}
|
||||
|
||||
function shouldContainInBody(str) {
|
||||
return function (res) {
|
||||
assert.ok(res.text.indexOf(str) !== -1, "expected '" + res.text + "' to contain '" + str + "'");
|
||||
};
|
||||
}
|
||||
44
test/js/third_party/express/express.test.ts
vendored
44
test/js/third_party/express/express.test.ts
vendored
@@ -1,44 +0,0 @@
|
||||
// @ts-nocheck
|
||||
// can't use @types/express or @types/body-parser because they
|
||||
// depend on @types/node which conflicts with bun-types
|
||||
import { expect, test } from "bun:test";
|
||||
import express from "express";
|
||||
import { isIPv6 } from "node:net";
|
||||
// https://github.com/oven-sh/bun/issues/8926
|
||||
test("should respond with 404 when wrong method is used", async () => {
|
||||
const { promise: serve, resolve } = Promise.withResolvers();
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
app.get("/api/hotels", (req, res) => {
|
||||
res.json({
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
|
||||
const server = app.listen(0, (_, host, port) => {
|
||||
if (isIPv6(host)) {
|
||||
resolve(`http://[${host}]:${port}`);
|
||||
} else {
|
||||
resolve(`http://${host}:${port}`);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const url = await serve;
|
||||
const response = await fetch(`${url}/api/hotels`, {
|
||||
method: "POST",
|
||||
signal: AbortSignal.timeout(500),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: "Hotel 1",
|
||||
price: 100,
|
||||
}),
|
||||
});
|
||||
expect(response.status).toBe(404);
|
||||
} finally {
|
||||
server.close();
|
||||
}
|
||||
});
|
||||
531
test/js/third_party/express/express.text.test.ts
vendored
531
test/js/third_party/express/express.text.test.ts
vendored
@@ -1,531 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var assert = require("node:assert");
|
||||
var AsyncLocalStorage = require("node:async_hooks").AsyncLocalStorage;
|
||||
|
||||
var express = require("express");
|
||||
var request = require("supertest");
|
||||
|
||||
describe("express.text()", function () {
|
||||
let app;
|
||||
|
||||
beforeAll(function () {
|
||||
app = createApp();
|
||||
});
|
||||
|
||||
it("should parse text/plain", function (done) {
|
||||
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, '"user is tobi"', done);
|
||||
});
|
||||
|
||||
it("should 400 when invalid content-length", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.headers["content-length"] = "20"; // bad length
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.text());
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.send("user")
|
||||
.expect(400, /content length/, done);
|
||||
});
|
||||
|
||||
it("should handle Content-Length: 0", function (done) {
|
||||
request(createApp({ limit: "1kb" }))
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.set("Content-Length", "0")
|
||||
.expect(200, '""', done);
|
||||
});
|
||||
|
||||
it.todo("should handle empty message-body", function (done) {
|
||||
request(createApp({ limit: "1kb" }))
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.set("Transfer-Encoding", "chunked")
|
||||
.send("")
|
||||
.expect(200, '""', done);
|
||||
});
|
||||
|
||||
it("should handle duplicated middleware", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(express.text());
|
||||
app.use(express.text());
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, '"user is tobi"', done);
|
||||
});
|
||||
|
||||
describe("with defaultCharset option", function () {
|
||||
it("should change default charset", function (done) {
|
||||
var server = createApp({ defaultCharset: "koi8-r" });
|
||||
var test = request(server).post("/");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("6e616d6520697320cec5d4", "hex"));
|
||||
test.expect(200, '"name is нет"', done);
|
||||
});
|
||||
|
||||
it("should honor content-type charset", function (done) {
|
||||
var server = createApp({ defaultCharset: "koi8-r" });
|
||||
var test = request(server).post("/");
|
||||
test.set("Content-Type", "text/plain; charset=utf-8");
|
||||
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with limit option", function () {
|
||||
it("should 413 when over limit with Content-Length", function (done) {
|
||||
var buf = Buffer.alloc(1028, ".");
|
||||
request(createApp({ limit: "1kb" }))
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.set("Content-Length", "1028")
|
||||
.send(buf.toString())
|
||||
.expect(413, done);
|
||||
});
|
||||
|
||||
it.todo("should 413 when over limit with chunked encoding", function (done) {
|
||||
var app = createApp({ limit: "1kb" });
|
||||
var buf = Buffer.alloc(1028, ".");
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.set("Transfer-Encoding", "chunked");
|
||||
test.write(buf.toString());
|
||||
test.expect(413, done);
|
||||
});
|
||||
|
||||
it("should 413 when inflated body over limit", function (done) {
|
||||
var app = createApp({ limit: "1kb" });
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000ad3d31b05a360148c64000087e5a14704040000", "hex"));
|
||||
test.expect(413, done);
|
||||
});
|
||||
|
||||
it("should accept number of bytes", function (done) {
|
||||
var buf = Buffer.alloc(1028, ".");
|
||||
request(createApp({ limit: 1024 }))
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.send(buf.toString())
|
||||
.expect(413, done);
|
||||
});
|
||||
|
||||
it("should not change when options altered", function (done) {
|
||||
var buf = Buffer.alloc(1028, ".");
|
||||
var options = { limit: "1kb" };
|
||||
var app = createApp(options);
|
||||
|
||||
options.limit = "100kb";
|
||||
|
||||
request(app).post("/").set("Content-Type", "text/plain").send(buf.toString()).expect(413, done);
|
||||
});
|
||||
|
||||
it("should not hang response", function (done) {
|
||||
var app = createApp({ limit: "8kb" });
|
||||
var buf = Buffer.alloc(10240, ".");
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(buf);
|
||||
test.write(buf);
|
||||
test.write(buf);
|
||||
test.expect(413, done);
|
||||
});
|
||||
|
||||
it("should not error when inflating", function (done) {
|
||||
var app = createApp({ limit: "1kb" });
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000ad3d31b05a360148c64000087e5a1470404", "hex"));
|
||||
setTimeout(function () {
|
||||
test.expect(413, done);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with inflate option", function () {
|
||||
describe.todo("when false", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ inflate: false });
|
||||
});
|
||||
|
||||
it("should not accept content-encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
|
||||
test.expect(415, "[encoding.unsupported] content encoding unsupported", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when true", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ inflate: true });
|
||||
});
|
||||
|
||||
it("should accept content-encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with type option", function () {
|
||||
describe.todo('when "text/html"', function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ type: "text/html" });
|
||||
});
|
||||
|
||||
it("should parse for custom type", function (done) {
|
||||
request(app).post("/").set("Content-Type", "text/html").send("<b>tobi</b>").expect(200, '"<b>tobi</b>"', done);
|
||||
});
|
||||
|
||||
it("should ignore standard type", function (done) {
|
||||
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when ["text/html", "text/plain"]', function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ type: ["text/html", "text/plain"] });
|
||||
});
|
||||
|
||||
it.todo('should parse "text/html"', function (done) {
|
||||
request(app).post("/").set("Content-Type", "text/html").send("<b>tobi</b>").expect(200, '"<b>tobi</b>"', done);
|
||||
});
|
||||
|
||||
it('should parse "text/plain"', function (done) {
|
||||
request(app).post("/").set("Content-Type", "text/plain").send("tobi").expect(200, '"tobi"', done);
|
||||
});
|
||||
|
||||
it.todo('should ignore "text/xml"', function (done) {
|
||||
request(app).post("/").set("Content-Type", "text/xml").send("<user>tobi</user>").expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when a function", function () {
|
||||
it("should parse when truthy value returned", function (done) {
|
||||
var app = createApp({ type: accept });
|
||||
|
||||
function accept(req) {
|
||||
return req.headers["content-type"] === "text/vnd.something";
|
||||
}
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "text/vnd.something")
|
||||
.send("user is tobi")
|
||||
.expect(200, '"user is tobi"', done);
|
||||
});
|
||||
|
||||
it("should work without content-type", function (done) {
|
||||
var app = createApp({ type: accept });
|
||||
|
||||
function accept(req) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var test = request(app).post("/");
|
||||
test.write("user is tobi");
|
||||
test.expect(200, '"user is tobi"', done);
|
||||
});
|
||||
|
||||
it("should not invoke without a body", function (done) {
|
||||
var app = createApp({ type: accept });
|
||||
|
||||
function accept(req) {
|
||||
throw new Error("oops!");
|
||||
}
|
||||
|
||||
request(app).get("/").expect(404, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with verify option", function () {
|
||||
it("should assert value is function", function () {
|
||||
assert.throws(createApp.bind(null, { verify: "lol" }), /TypeError: option verify must be function/);
|
||||
});
|
||||
|
||||
it("should error from verify", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] === 0x20) throw new Error("no leading space");
|
||||
},
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.send(" user is tobi")
|
||||
.expect(403, "[entity.verify.failed] no leading space", done);
|
||||
});
|
||||
|
||||
it("should allow custom codes", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] !== 0x20) return;
|
||||
var err = new Error("no leading space");
|
||||
err.status = 400;
|
||||
throw err;
|
||||
},
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.send(" user is tobi")
|
||||
.expect(400, "[entity.verify.failed] no leading space", done);
|
||||
});
|
||||
|
||||
it("should allow pass-through", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
if (buf[0] === 0x20) throw new Error("no leading space");
|
||||
},
|
||||
});
|
||||
|
||||
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, '"user is tobi"', done);
|
||||
});
|
||||
|
||||
it("should 415 on unknown charset prior to verify", function (done) {
|
||||
var app = createApp({
|
||||
verify: function (req, res, buf) {
|
||||
throw new Error("unexpected verify call");
|
||||
},
|
||||
});
|
||||
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain; charset=x-bogus");
|
||||
test.write(Buffer.from("00000000", "hex"));
|
||||
test.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe.todo("async local storage", function () {
|
||||
beforeAll(function () {
|
||||
var app = express();
|
||||
var store = { foo: "bar" };
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new AsyncLocalStorage();
|
||||
req.asyncLocalStorage.run(store, next);
|
||||
});
|
||||
|
||||
app.use(express.text());
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
var local = req.asyncLocalStorage.getStore();
|
||||
|
||||
if (local) {
|
||||
res.setHeader("x-store-foo", String(local.foo));
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
var local = req.asyncLocalStorage.getStore();
|
||||
|
||||
if (local) {
|
||||
res.setHeader("x-store-foo", String(local.foo));
|
||||
}
|
||||
|
||||
res.status(err.status || 500);
|
||||
res.send("[" + err.type + "] " + err.message);
|
||||
});
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
app = app;
|
||||
});
|
||||
|
||||
it("should presist store", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.send("user is tobi")
|
||||
.expect(200)
|
||||
.expect("x-store-foo", "bar")
|
||||
.expect('"user is tobi"')
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when unmatched content-type", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "application/fizzbuzz")
|
||||
.send("buzz")
|
||||
.expect(200)
|
||||
.expect("x-store-foo", "bar")
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when inflated", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
|
||||
test.expect(200);
|
||||
test.expect("x-store-foo", "bar");
|
||||
test.expect('"name is 论"');
|
||||
test.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when inflate error", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b0000", "hex"));
|
||||
test.expect(400);
|
||||
test.expect("x-store-foo", "bar");
|
||||
test.end(done);
|
||||
});
|
||||
|
||||
it("should presist store when limit exceeded", function (done) {
|
||||
request(app)
|
||||
.post("/")
|
||||
.set("Content-Type", "text/plain")
|
||||
.send("user is " + Buffer.alloc(1024 * 100, ".").toString())
|
||||
.expect(413)
|
||||
.expect("x-store-foo", "bar")
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("charset", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp();
|
||||
});
|
||||
|
||||
it("should parse utf-8", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain; charset=utf-8");
|
||||
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should parse codepage charsets", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain; charset=koi8-r");
|
||||
test.write(Buffer.from("6e616d6520697320cec5d4", "hex"));
|
||||
test.expect(200, '"name is нет"', done);
|
||||
});
|
||||
|
||||
it("should parse when content-length != char length", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain; charset=utf-8");
|
||||
test.set("Content-Length", "11");
|
||||
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should default to utf-8", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should 415 on unknown charset", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain; charset=x-bogus");
|
||||
test.write(Buffer.from("00000000", "hex"));
|
||||
test.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("encoding", function () {
|
||||
beforeAll(function () {
|
||||
app = createApp({ limit: "10kb" });
|
||||
});
|
||||
|
||||
it("should parse without encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should support identity encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "identity");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should support gzip encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "gzip");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should support deflate encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "deflate");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("789ccb4bcc4d55c82c5678b16e17001a6f050e", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should be case-insensitive", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "GZIP");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
|
||||
test.expect(200, '"name is 论"', done);
|
||||
});
|
||||
|
||||
it("should 415 on unknown encoding", function (done) {
|
||||
var test = request(app).post("/");
|
||||
test.set("Content-Encoding", "nulls");
|
||||
test.set("Content-Type", "text/plain");
|
||||
test.write(Buffer.from("000000000000", "hex"));
|
||||
test.expect(415, '[encoding.unsupported] unsupported content encoding "nulls"', done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createApp(options?) {
|
||||
var app = express();
|
||||
|
||||
app.use(express.text(options));
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
res.status(err.status || 500);
|
||||
res.send(
|
||||
String(
|
||||
req.headers["x-error-property"] ? err[req.headers["x-error-property"]] : "[" + err.type + "] " + err.message,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
app.post("/", function (req, res) {
|
||||
res.json(req.body);
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
20%
|
||||
1
test/js/third_party/express/fixtures/.name
vendored
1
test/js/third_party/express/fixtures/.name
vendored
@@ -1 +0,0 @@
|
||||
tobi
|
||||
@@ -1 +0,0 @@
|
||||
<b>index</b>
|
||||
@@ -1 +0,0 @@
|
||||
<h1>blog post</h1>
|
||||
@@ -1 +0,0 @@
|
||||
tobi
|
||||
@@ -1 +0,0 @@
|
||||
123456789
|
||||
@@ -1 +0,0 @@
|
||||
<p>{{user.name}}</p>
|
||||
7
test/js/third_party/express/package.json
vendored
7
test/js/third_party/express/package.json
vendored
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "express-test",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"express": "4.18.2"
|
||||
}
|
||||
}
|
||||
170
test/js/third_party/express/res.json.test.ts
vendored
170
test/js/third_party/express/res.json.test.ts
vendored
@@ -1,170 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var express = require("express"),
|
||||
request = require("supertest"),
|
||||
assert = require("node:assert");
|
||||
|
||||
describe("res", function () {
|
||||
describe(".json(object)", function () {
|
||||
it("should not support jsonp callbacks", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json({ foo: "bar" });
|
||||
});
|
||||
|
||||
request(app).get("/?callback=foo").expect('{"foo":"bar"}', done);
|
||||
});
|
||||
|
||||
it("should not override previous Content-Types", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.get("/", function (req, res) {
|
||||
res.type("application/vnd.example+json");
|
||||
res.json({ hello: "world" });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "application/vnd.example+json; charset=utf-8")
|
||||
.expect(200, '{"hello":"world"}', done);
|
||||
});
|
||||
|
||||
describe("when given primitives", function () {
|
||||
it("should respond with json for null", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json(null);
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "null", done);
|
||||
});
|
||||
|
||||
it("should respond with json for Number", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json(300);
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "300", done);
|
||||
});
|
||||
|
||||
it("should respond with json for String", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json("str");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, '"str"', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when given an array", function () {
|
||||
it("should respond with json", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json(["foo", "bar", "baz"]);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "application/json; charset=utf-8")
|
||||
.expect(200, '["foo","bar","baz"]', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when given an object", function () {
|
||||
it("should respond with json", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json({ name: "tobi" });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "application/json; charset=utf-8")
|
||||
.expect(200, '{"name":"tobi"}', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('"json escape" setting', function () {
|
||||
it("should be undefined by default", function () {
|
||||
var app = express();
|
||||
assert.strictEqual(app.get("json escape"), undefined);
|
||||
});
|
||||
|
||||
it("should unicode escape HTML-sniffing characters", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.enable("json escape");
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json({ "&": "<script>" });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "application/json; charset=utf-8")
|
||||
.expect(200, '{"\\u0026":"\\u003cscript\\u003e"}', done);
|
||||
});
|
||||
|
||||
it("should not break undefined escape", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.enable("json escape");
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json(undefined);
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('"json replacer" setting', function () {
|
||||
it("should be passed to JSON.stringify()", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.set("json replacer", function (key, val) {
|
||||
return key[0] === "_" ? undefined : val;
|
||||
});
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json({ name: "tobi", _id: 12345 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "application/json; charset=utf-8")
|
||||
.expect(200, '{"name":"tobi"}', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('"json spaces" setting', function () {
|
||||
it("should be undefined by default", function () {
|
||||
var app = express();
|
||||
assert(undefined === app.get("json spaces"));
|
||||
});
|
||||
|
||||
it("should be passed to JSON.stringify()", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.set("json spaces", 2);
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json({ name: "tobi", age: 2 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "application/json; charset=utf-8")
|
||||
.expect(200, '{\n "name": "tobi",\n "age": 2\n}', done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
251
test/js/third_party/express/res.location.test.ts
vendored
251
test/js/third_party/express/res.location.test.ts
vendored
@@ -1,251 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var express = require("express"),
|
||||
request = require("supertest"),
|
||||
assert = require("node:assert"),
|
||||
url = require("node:url");
|
||||
|
||||
describe("res", function () {
|
||||
describe(".location(url)", function () {
|
||||
it("should set the header", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location("http://google.com/").end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "http://google.com/").expect(200, done);
|
||||
});
|
||||
|
||||
it("should preserve trailing slashes when not present", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location("http://google.com").end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "http://google.com").expect(200, done);
|
||||
});
|
||||
|
||||
it('should encode "url"', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location("https://google.com?q=\u2603 §10").end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "https://google.com?q=%E2%98%83%20%C2%A710").expect(200, done);
|
||||
});
|
||||
|
||||
it("should encode data uri1", function (done) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
res.location("data:text/javascript,export default () => { }").end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Location", "data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D")
|
||||
.expect(200, done);
|
||||
});
|
||||
|
||||
it("should encode data uri2", function (done) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
res.location("data:text/javascript,export default () => { }").end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Location", "data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D")
|
||||
.expect(200, done);
|
||||
});
|
||||
|
||||
it("should consistently handle non-string input: boolean", function (done) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
res.location(true).end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "true").expect(200, done);
|
||||
});
|
||||
|
||||
it("should consistently handle non-string inputs: object", function (done) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
res.location({}).end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "[object%20Object]").expect(200, done);
|
||||
});
|
||||
|
||||
it.todo("should consistently handle non-string inputs: array", function (done) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
res.location([]).end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "").expect(200, done);
|
||||
});
|
||||
|
||||
it.todo("should consistently handle empty string input", function (done) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
res.location("").end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "").expect(200, done);
|
||||
});
|
||||
|
||||
if (typeof URL !== "undefined") {
|
||||
it("should accept an instance of URL", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location(new URL("http://google.com/")).end();
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "http://google.com/").expect(200, done);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("location header encoding", function () {
|
||||
function createRedirectServerForDomain(domain) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
var host = url.parse(req.query.q, false, true).host;
|
||||
// This is here to show a basic check one might do which
|
||||
// would pass but then the location header would still be bad
|
||||
if (host !== domain) {
|
||||
res.status(400).end("Bad host: " + host + " !== " + domain);
|
||||
}
|
||||
res.location(req.query.q).end();
|
||||
});
|
||||
return app;
|
||||
}
|
||||
|
||||
function testRequestedRedirect(app, inputUrl, expected, expectedHost, done) {
|
||||
return (
|
||||
request(app)
|
||||
// Encode uri because old supertest does not and is required
|
||||
// to test older node versions. New supertest doesn't re-encode
|
||||
// so this works in both.
|
||||
.get("/?q=" + encodeURIComponent(inputUrl))
|
||||
.expect("") // No body.
|
||||
.expect(200)
|
||||
.expect("Location", expected)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
console.log("headers:", res.headers);
|
||||
console.error("error", res.error, err);
|
||||
return done(err, res);
|
||||
}
|
||||
|
||||
// Parse the hosts from the input URL and the Location header
|
||||
var inputHost = url.parse(inputUrl, false, true).host;
|
||||
var locationHost = url.parse(res.headers["location"], false, true).host;
|
||||
|
||||
assert.strictEqual(locationHost, expectedHost);
|
||||
|
||||
// Assert that the hosts are the same
|
||||
if (inputHost !== locationHost) {
|
||||
return done(new Error("Hosts do not match: " + inputHost + " !== " + locationHost));
|
||||
}
|
||||
|
||||
return done(null, res);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
it('should not touch already-encoded sequences in "url"', function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(app, "https://google.com?q=%A710", "https://google.com?q=%A710", "google.com", done);
|
||||
});
|
||||
|
||||
it("should consistently handle relative urls", function (done) {
|
||||
var app = createRedirectServerForDomain(null);
|
||||
testRequestedRedirect(app, "/foo/bar", "/foo/bar", null, done);
|
||||
});
|
||||
|
||||
it.todo("should not encode urls in such a way that they can bypass redirect allow lists", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(app, "http://google.com\\@apple.com", "http://google.com\\@apple.com", "google.com", done);
|
||||
});
|
||||
|
||||
it.todo("should not be case sensitive", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(app, "HTTP://google.com\\@apple.com", "HTTP://google.com\\@apple.com", "google.com", done);
|
||||
});
|
||||
|
||||
it.todo("should work with https", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(
|
||||
app,
|
||||
"https://google.com\\@apple.com",
|
||||
"https://google.com\\@apple.com",
|
||||
"google.com",
|
||||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it.todo("should correctly encode schemaless paths", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(app, "//google.com\\@apple.com/", "//google.com\\@apple.com/", "google.com", done);
|
||||
});
|
||||
|
||||
it.todo("should keep backslashes in the path", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(
|
||||
app,
|
||||
"https://google.com/foo\\bar\\baz",
|
||||
"https://google.com/foo\\bar\\baz",
|
||||
"google.com",
|
||||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it.todo("should escape header splitting for old node versions", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(
|
||||
app,
|
||||
"http://google.com\\@apple.com/%0d%0afoo:%20bar",
|
||||
"http://google.com\\@apple.com/%0d%0afoo:%20bar",
|
||||
"google.com",
|
||||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it("should encode unicode correctly", function (done) {
|
||||
var app = createRedirectServerForDomain(null);
|
||||
testRequestedRedirect(app, "/%e2%98%83", "/%e2%98%83", null, done);
|
||||
});
|
||||
|
||||
it.todo("should encode unicode correctly even with a bad host", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(
|
||||
app,
|
||||
"http://google.com\\@apple.com/%e2%98%83",
|
||||
"http://google.com\\@apple.com/%e2%98%83",
|
||||
"google.com",
|
||||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it("should work correctly despite using deprecated url.parse", function (done) {
|
||||
var app = createRedirectServerForDomain("google.com");
|
||||
testRequestedRedirect(
|
||||
app,
|
||||
"https://google.com'.bb.com/1.html",
|
||||
"https://google.com'.bb.com/1.html",
|
||||
"google.com",
|
||||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it.todo("should encode file uri path", function (done) {
|
||||
var app = createRedirectServerForDomain("");
|
||||
testRequestedRedirect(app, "file:///etc\\passwd", "file:///etc\\passwd", "", done);
|
||||
});
|
||||
});
|
||||
});
|
||||
206
test/js/third_party/express/res.redirect.test.ts
vendored
206
test/js/third_party/express/res.redirect.test.ts
vendored
@@ -1,206 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var express = require("express");
|
||||
var request = require("supertest");
|
||||
var utils = require("./support/utils");
|
||||
|
||||
describe("res", function () {
|
||||
describe(".redirect(url)", function () {
|
||||
it("should default to a 302 redirect", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("http://google.com");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("location", "http://google.com").expect(302, done);
|
||||
});
|
||||
|
||||
it('should encode "url"', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("https://google.com?q=\u2603 §10");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "https://google.com?q=%E2%98%83%20%C2%A710").expect(302, done);
|
||||
});
|
||||
|
||||
it('should not touch already-encoded sequences in "url"', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("https://google.com?q=%A710");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "https://google.com?q=%A710").expect(302, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".redirect(status, url)", function () {
|
||||
it("should set the response status", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect(303, "http://google.com");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Location", "http://google.com").expect(303, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the request method is HEAD", function () {
|
||||
it("should ignore the body", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("http://google.com");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.head("/")
|
||||
.expect(302)
|
||||
.expect("Location", "http://google.com")
|
||||
.expect(utils.shouldNotHaveBody())
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when accepting html", function () {
|
||||
it.todo("should respond with html", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("http://google.com");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Accept", "text/html")
|
||||
.expect("Content-Type", /html/)
|
||||
.expect("Location", "http://google.com")
|
||||
.expect(302, "<p>Found. Redirecting to http://google.com</p>", done);
|
||||
});
|
||||
|
||||
it.todo("should escape the url", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("<la'me>");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Host", "http://example.com")
|
||||
.set("Accept", "text/html")
|
||||
.expect("Content-Type", /html/)
|
||||
.expect("Location", "%3Cla'me%3E")
|
||||
.expect(302, "<p>Found. Redirecting to %3Cla'me%3E</p>", done);
|
||||
});
|
||||
|
||||
it.todo("should not render evil javascript links in anchor href (prevent XSS)", function (done) {
|
||||
var app = express();
|
||||
var xss = "javascript:eval(document.body.innerHTML=`<p>XSS</p>`);";
|
||||
var encodedXss = "javascript:eval(document.body.innerHTML=%60%3Cp%3EXSS%3C/p%3E%60);";
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect(xss);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Host", "http://example.com")
|
||||
.set("Accept", "text/html")
|
||||
.expect("Content-Type", /html/)
|
||||
.expect("Location", encodedXss)
|
||||
.expect(302, "<p>Found. Redirecting to " + encodedXss + "</p>", done);
|
||||
});
|
||||
|
||||
it.todo("should include the redirect type", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect(301, "http://google.com");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Accept", "text/html")
|
||||
.expect("Content-Type", /html/)
|
||||
.expect("Location", "http://google.com")
|
||||
.expect(301, "<p>Moved Permanently. Redirecting to http://google.com</p>", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when accepting text", function () {
|
||||
it("should respond with text", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("http://google.com");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Accept", "text/plain, */*")
|
||||
.expect("Content-Type", /plain/)
|
||||
.expect("Location", "http://google.com")
|
||||
.expect(302, "Found. Redirecting to http://google.com", done);
|
||||
});
|
||||
|
||||
it("should encode the url", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect('http://example.com/?param=<script>alert("hax");</script>');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Host", "http://example.com")
|
||||
.set("Accept", "text/plain, */*")
|
||||
.expect("Content-Type", /plain/)
|
||||
.expect("Location", "http://example.com/?param=%3Cscript%3Ealert(%22hax%22);%3C/script%3E")
|
||||
.expect(
|
||||
302,
|
||||
"Found. Redirecting to http://example.com/?param=%3Cscript%3Ealert(%22hax%22);%3C/script%3E",
|
||||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it("should include the redirect type", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect(301, "http://google.com");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Accept", "text/plain, */*")
|
||||
.expect("Content-Type", /plain/)
|
||||
.expect("Location", "http://google.com")
|
||||
.expect(301, "Moved Permanently. Redirecting to http://google.com", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when accepting neither text or html", function () {
|
||||
it("should respond with an empty body", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.redirect("http://google.com");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("Accept", "application/octet-stream")
|
||||
.expect(302)
|
||||
.expect("location", "http://google.com")
|
||||
.expect("content-length", "0")
|
||||
.expect(utils.shouldNotHaveHeader("Content-Type"))
|
||||
.expect(utils.shouldNotHaveBody())
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
475
test/js/third_party/express/res.send.test.ts
vendored
475
test/js/third_party/express/res.send.test.ts
vendored
@@ -1,475 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var assert = require("node:assert");
|
||||
var express = require("express");
|
||||
var request = require("supertest");
|
||||
var utils = require("./support/utils");
|
||||
|
||||
var shouldSkipQuery = require("./support/utils").shouldSkipQuery;
|
||||
var methods = utils.methods;
|
||||
|
||||
describe("res", function () {
|
||||
describe(".send()", function () {
|
||||
it('should set body to ""', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send();
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".send(null)", function () {
|
||||
it('should set body to ""', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send(null);
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Length", "0").expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".send(undefined)", function () {
|
||||
it('should set body to ""', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send(undefined);
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".send(Number)", function () {
|
||||
it.todo("should send as application/json", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send(1000);
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "1000", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".send(String)", function () {
|
||||
it("should send as html", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("<p>hey</p>");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "text/html; charset=utf-8").expect(200, "<p>hey</p>", done);
|
||||
});
|
||||
|
||||
it("should set ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
var str = Array(1000).join("-");
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
request(app).get("/").expect("ETag", 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"').expect(200, done);
|
||||
});
|
||||
|
||||
it("should not override Content-Type", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.set("Content-Type", "text/plain").send("hey");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
|
||||
});
|
||||
|
||||
it("should override charset in Content-Type", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.set("Content-Type", "text/plain; charset=iso-8859-1").send("hey");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
|
||||
});
|
||||
|
||||
it("should keep charset in Content-Type for Buffers", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.set("Content-Type", "text/plain; charset=iso-8859-1").send(Buffer.from("hi"));
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "text/plain; charset=iso-8859-1").expect(200, "hi", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".send(Buffer)", function () {
|
||||
it("should send as octet-stream", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send(Buffer.from("hello"));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(200)
|
||||
.expect("Content-Type", "application/octet-stream")
|
||||
.expect(utils.shouldHaveBody(Buffer.from("hello")))
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it("should set ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send(Buffer.alloc(999, "-"));
|
||||
});
|
||||
|
||||
request(app).get("/").expect("ETag", 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"').expect(200, done);
|
||||
});
|
||||
|
||||
it("should not override Content-Type", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.set("Content-Type", "text/plain").send(Buffer.from("hey"));
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
|
||||
});
|
||||
|
||||
it.todo("should accept Uint8Array", function (done) {
|
||||
var app = express();
|
||||
app.use(function (req, res) {
|
||||
const encodedHey = new TextEncoder().encode("hey");
|
||||
res.set("Content-Type", "text/plain").send(encodedHey);
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
|
||||
});
|
||||
|
||||
it("should not override ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.type("text/plain").set("ETag", '"foo"').send(Buffer.from("hey"));
|
||||
});
|
||||
|
||||
request(app).get("/").expect("ETag", '"foo"').expect(200, "hey", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".send(Object)", function () {
|
||||
it("should send as application/json", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send({ name: "tobi" });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "application/json; charset=utf-8")
|
||||
.expect(200, '{"name":"tobi"}', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the request method is HEAD", function () {
|
||||
it("should ignore the body", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("yay");
|
||||
});
|
||||
|
||||
request(app).head("/").expect(200).expect(utils.shouldNotHaveBody()).end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when .statusCode is 204", function () {
|
||||
it.todo("should strip Content-* fields, Transfer-Encoding field, and body", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(204).set("Transfer-Encoding", "chunked").send("foo");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(utils.shouldNotHaveHeader("Content-Type"))
|
||||
.expect(utils.shouldNotHaveHeader("Content-Length"))
|
||||
.expect(utils.shouldNotHaveHeader("Transfer-Encoding"))
|
||||
.expect(204, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when .statusCode is 205", function () {
|
||||
it("should strip Transfer-Encoding field and body, set Content-Length", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(205).set("Transfer-Encoding", "chunked").send("foo");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(utils.shouldNotHaveHeader("Transfer-Encoding"))
|
||||
.expect("Content-Length", "0")
|
||||
.expect(205, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when .statusCode is 304", function () {
|
||||
it.todo("should strip Content-* fields, Transfer-Encoding field, and body", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(304).set("Transfer-Encoding", "chunked").send("foo");
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(utils.shouldNotHaveHeader("Content-Type"))
|
||||
.expect(utils.shouldNotHaveHeader("Content-Length"))
|
||||
.expect(utils.shouldNotHaveHeader("Transfer-Encoding"))
|
||||
.expect(304, "", done);
|
||||
});
|
||||
});
|
||||
|
||||
it("should always check regardless of length", function (done) {
|
||||
var app = express();
|
||||
var etag = '"asdf"';
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
res.set("ETag", etag);
|
||||
res.send("hey");
|
||||
});
|
||||
|
||||
request(app).get("/").set("If-None-Match", etag).expect(304, done);
|
||||
});
|
||||
|
||||
it("should respond with 304 Not Modified when fresh", function (done) {
|
||||
var app = express();
|
||||
var etag = '"asdf"';
|
||||
|
||||
app.use(function (req, res) {
|
||||
var str = Array(1000).join("-");
|
||||
res.set("ETag", etag);
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
request(app).get("/").set("If-None-Match", etag).expect(304, done);
|
||||
});
|
||||
|
||||
it("should not perform freshness check unless 2xx or 304", function (done) {
|
||||
var app = express();
|
||||
var etag = '"asdf"';
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
res.status(500);
|
||||
res.set("ETag", etag);
|
||||
res.send("hey");
|
||||
});
|
||||
|
||||
request(app).get("/").set("If-None-Match", etag).expect("hey").expect(500, done);
|
||||
});
|
||||
|
||||
it("should not support jsonp callbacks", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send({ foo: "bar" });
|
||||
});
|
||||
|
||||
request(app).get("/?callback=foo").expect('{"foo":"bar"}', done);
|
||||
});
|
||||
|
||||
it("should be chainable", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
assert.equal(res.send("hey"), res);
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200, "hey", done);
|
||||
});
|
||||
|
||||
describe('"etag" setting', function () {
|
||||
describe("when enabled", function () {
|
||||
it("should send ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("kajdslfkasdf");
|
||||
});
|
||||
|
||||
app.enable("etag");
|
||||
|
||||
request(app).get("/").expect("ETag", 'W/"c-IgR/L5SF7CJQff4wxKGF/vfPuZ0"').expect(200, done);
|
||||
});
|
||||
|
||||
methods.forEach(function (method) {
|
||||
if (method === "connect") return;
|
||||
|
||||
it("should send ETag in response to " + method.toUpperCase() + " request", function (done) {
|
||||
if (method === "query" && shouldSkipQuery(process.versions.node)) {
|
||||
this.skip();
|
||||
}
|
||||
var app = express();
|
||||
|
||||
app[method]("/", function (req, res) {
|
||||
res.send("kajdslfkasdf");
|
||||
});
|
||||
|
||||
request(app)[method]("/").expect("ETag", 'W/"c-IgR/L5SF7CJQff4wxKGF/vfPuZ0"').expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
it("should send ETag for empty string response", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("");
|
||||
});
|
||||
|
||||
app.enable("etag");
|
||||
|
||||
request(app).get("/").expect("ETag", 'W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"').expect(200, done);
|
||||
});
|
||||
|
||||
it("should send ETag for long response", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
var str = Array(1000).join("-");
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
app.enable("etag");
|
||||
|
||||
request(app).get("/").expect("ETag", 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"').expect(200, done);
|
||||
});
|
||||
|
||||
it("should not override ETag when manually set", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.set("etag", '"asdf"');
|
||||
res.send("hello!");
|
||||
});
|
||||
|
||||
app.enable("etag");
|
||||
|
||||
request(app).get("/").expect("ETag", '"asdf"').expect(200, done);
|
||||
});
|
||||
|
||||
it("should not send ETag for res.send()", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send();
|
||||
});
|
||||
|
||||
app.enable("etag");
|
||||
|
||||
request(app).get("/").expect(utils.shouldNotHaveHeader("ETag")).expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when disabled", function () {
|
||||
it("should send no ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
var str = Array(1000).join("-");
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
app.disable("etag");
|
||||
|
||||
request(app).get("/").expect(utils.shouldNotHaveHeader("ETag")).expect(200, done);
|
||||
});
|
||||
|
||||
it("should send ETag when manually set", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.disable("etag");
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.set("etag", '"asdf"');
|
||||
res.send("hello!");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("ETag", '"asdf"').expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "strong"', function () {
|
||||
it("should send strong ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.set("etag", "strong");
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("hello, world!");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("ETag", '"d-HwnTDHB9U/PRbFMN1z1wps51lqk"').expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "weak"', function () {
|
||||
it("should send weak ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.set("etag", "weak");
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("hello, world!");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("ETag", 'W/"d-HwnTDHB9U/PRbFMN1z1wps51lqk"').expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when a function", function () {
|
||||
it("should send custom ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.set("etag", function (body, encoding) {
|
||||
var chunk = !Buffer.isBuffer(body) ? Buffer.from(body, encoding) : body;
|
||||
assert.strictEqual(chunk.toString(), "hello, world!");
|
||||
return '"custom"';
|
||||
});
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("hello, world!");
|
||||
});
|
||||
|
||||
request(app).get("/").expect("ETag", '"custom"').expect(200, done);
|
||||
});
|
||||
|
||||
it("should not send falsy ETag", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.set("etag", function (body, encoding) {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send("hello, world!");
|
||||
});
|
||||
|
||||
request(app).get("/").expect(utils.shouldNotHaveHeader("ETag")).expect(200, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
774
test/js/third_party/express/res.sendFile.test.ts
vendored
774
test/js/third_party/express/res.sendFile.test.ts
vendored
@@ -1,774 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var after = require("./support/after");
|
||||
var assert = require("node:assert");
|
||||
var AsyncLocalStorage = require("node:async_hooks").AsyncLocalStorage;
|
||||
|
||||
var express = require("express"),
|
||||
request = require("supertest");
|
||||
// var onFinished = require("on-finished");
|
||||
var path = require("node:path");
|
||||
var fixtures = path.join(__dirname, "fixtures");
|
||||
var utils = require("./support/utils");
|
||||
|
||||
describe("res", function () {
|
||||
describe(".sendFile(path)", function () {
|
||||
it("should error missing path", function (done) {
|
||||
var app = createApp();
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(500, /path.*required/, done);
|
||||
});
|
||||
|
||||
it("should error for non-string path", function (done) {
|
||||
var app = createApp(42);
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(500, /TypeError: path must be a string to res.sendFile/, done);
|
||||
});
|
||||
|
||||
it("should error for non-absolute path", function (done) {
|
||||
var app = createApp("name.txt");
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(500, /TypeError: path must be absolute/, done);
|
||||
});
|
||||
|
||||
it.todo("should transfer a file", function (done) {
|
||||
var app = createApp(path.resolve(fixtures, "name.txt"));
|
||||
|
||||
request(app).get("/").expect(200, "tobi", done);
|
||||
});
|
||||
|
||||
it("should transfer a file with special characters in string", function (done) {
|
||||
var app = createApp(path.resolve(fixtures, "% of dogs.txt"));
|
||||
|
||||
request(app).get("/").expect(200, "20%", done);
|
||||
});
|
||||
|
||||
it.todo("should include ETag", function (done) {
|
||||
var app = createApp(path.resolve(fixtures, "name.txt"));
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("ETag", /^(?:W\/)?"[^"]+"$/)
|
||||
.expect(200, "tobi", done);
|
||||
});
|
||||
|
||||
it.todo("should 304 when ETag matches", function (done) {
|
||||
var app = createApp(path.resolve(fixtures, "name.txt"));
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("ETag", /^(?:W\/)?"[^"]+"$/)
|
||||
.expect(200, "tobi", function (err, res) {
|
||||
if (err) return done(err);
|
||||
var etag = res.headers.etag;
|
||||
request(app).get("/").set("If-None-Match", etag).expect(304, done);
|
||||
});
|
||||
});
|
||||
|
||||
it.todo("should disable the ETag function if requested", function (done) {
|
||||
var app = createApp(path.resolve(fixtures, "name.txt")).disable("etag");
|
||||
|
||||
request(app).get("/").expect(handleHeaders).expect(200, done);
|
||||
|
||||
function handleHeaders(res) {
|
||||
assert(res.headers.etag === undefined);
|
||||
}
|
||||
});
|
||||
|
||||
it("should 404 for directory", function (done) {
|
||||
var app = createApp(path.resolve(fixtures, "blog"));
|
||||
|
||||
request(app).get("/").expect(404, done);
|
||||
});
|
||||
|
||||
it("should 404 when not found", function (done) {
|
||||
var app = createApp(path.resolve(fixtures, "does-no-exist"));
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.statusCode = 200;
|
||||
res.send("no!");
|
||||
});
|
||||
|
||||
request(app).get("/").expect(404, done);
|
||||
});
|
||||
|
||||
it("should send cache-control by default", function (done) {
|
||||
var app = createApp(path.resolve(__dirname, "fixtures/name.txt"));
|
||||
|
||||
request(app).get("/").expect("Cache-Control", "public, max-age=0").expect(200, done);
|
||||
});
|
||||
|
||||
it("should not serve dotfiles by default", function (done) {
|
||||
var app = createApp(path.resolve(__dirname, "fixtures/.name"));
|
||||
|
||||
request(app).get("/").expect(404, done);
|
||||
});
|
||||
|
||||
it("should not override manual content-types", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.contentType("application/x-bogus");
|
||||
res.sendFile(path.resolve(fixtures, "name.txt"));
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "application/x-bogus").end(done);
|
||||
});
|
||||
|
||||
it.todo("should not error if the client aborts", function (done) {
|
||||
var app = express();
|
||||
var cb = after(2, done);
|
||||
var error = null;
|
||||
|
||||
app.use(function (req, res) {
|
||||
setImmediate(function () {
|
||||
res.sendFile(path.resolve(fixtures, "name.txt"));
|
||||
setTimeout(function () {
|
||||
cb(error);
|
||||
}, 10);
|
||||
});
|
||||
test.req.abort();
|
||||
});
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
error = err;
|
||||
next(err);
|
||||
});
|
||||
|
||||
var server = app.listen();
|
||||
var test = request(server).get("/");
|
||||
test.end(function (err) {
|
||||
assert.ok(err);
|
||||
server.close(cb);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(".sendFile(path, fn)", function () {
|
||||
it("should invoke the callback when complete", function (done) {
|
||||
var cb = after(2, done);
|
||||
var app = createApp(path.resolve(fixtures, "name.txt"), cb);
|
||||
|
||||
request(app).get("/").expect(200, cb);
|
||||
});
|
||||
|
||||
it.todo("should invoke the callback when client aborts", function (done) {
|
||||
var cb = after(2, done);
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
setImmediate(function () {
|
||||
res.sendFile(path.resolve(fixtures, "name.txt"), function (err) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(err.code, "ECONNABORTED");
|
||||
cb();
|
||||
});
|
||||
});
|
||||
test.req.abort();
|
||||
});
|
||||
|
||||
var server = app.listen();
|
||||
var test = request(server).get("/");
|
||||
test.end(function (err) {
|
||||
assert.ok(err);
|
||||
server.close(cb);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: refactor to not use onFinished
|
||||
// it("should invoke the callback when client already aborted", function (done) {
|
||||
// var cb = after(2, done);
|
||||
// var app = express();
|
||||
|
||||
// app.use(function (req, res) {
|
||||
// onFinished(res, function () {
|
||||
// res.sendFile(path.resolve(fixtures, "name.txt"), function (err) {
|
||||
// assert.ok(err);
|
||||
// assert.strictEqual(err.code, "ECONNABORTED");
|
||||
// cb();
|
||||
// });
|
||||
// });
|
||||
// test.req.abort();
|
||||
// });
|
||||
|
||||
// var server = app.listen();
|
||||
// var test = request(server).get("/");
|
||||
// test.end(function (err) {
|
||||
// assert.ok(err);
|
||||
// server.close(cb);
|
||||
// });
|
||||
// });
|
||||
|
||||
it("should invoke the callback without error when HEAD", function (done) {
|
||||
var app = express();
|
||||
var cb = after(2, done);
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "name.txt"), cb);
|
||||
});
|
||||
|
||||
request(app).head("/").expect(200, cb);
|
||||
});
|
||||
|
||||
it.todo("should invoke the callback without error when 304", function (done) {
|
||||
var app = express();
|
||||
var cb = after(3, done);
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "name.txt"), cb);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("ETag", /^(?:W\/)?"[^"]+"$/)
|
||||
.expect(200, "tobi", function (err, res) {
|
||||
if (err) return cb(err);
|
||||
var etag = res.headers.etag;
|
||||
request(app).get("/").set("If-None-Match", etag).expect(304, cb);
|
||||
});
|
||||
});
|
||||
|
||||
it("should invoke the callback on 404", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "does-not-exist"), function (err) {
|
||||
res.send(err ? "got " + err.status + " error" : "no error");
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200, "got 404 error", done);
|
||||
});
|
||||
|
||||
describe.todo("async local storage", function () {
|
||||
it("should presist store", function (done) {
|
||||
var app = express();
|
||||
var cb = after(2, done);
|
||||
var store = { foo: "bar" };
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new AsyncLocalStorage();
|
||||
req.asyncLocalStorage.run(store, next);
|
||||
});
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "name.txt"), function (err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var local = req.asyncLocalStorage.getStore();
|
||||
|
||||
assert.strictEqual(local.foo, "bar");
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "tobi", cb);
|
||||
});
|
||||
|
||||
it("should presist store on error", function (done) {
|
||||
var app = express();
|
||||
var store = { foo: "bar" };
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new AsyncLocalStorage();
|
||||
req.asyncLocalStorage.run(store, next);
|
||||
});
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "does-not-exist"), function (err) {
|
||||
var local = req.asyncLocalStorage.getStore();
|
||||
|
||||
if (local) {
|
||||
res.setHeader("x-store-foo", String(local.foo));
|
||||
}
|
||||
|
||||
res.send(err ? "got " + err.status + " error" : "no error");
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("x-store-foo", "bar").expect("got 404 error").end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(".sendFile(path, options)", function () {
|
||||
it("should pass options to send module", function (done) {
|
||||
request(createApp(path.resolve(fixtures, "name.txt"), { start: 0, end: 1 }))
|
||||
.get("/")
|
||||
.expect(200, "to", done);
|
||||
});
|
||||
|
||||
describe('with "acceptRanges" option', function () {
|
||||
describe("when true", function () {
|
||||
it("should advertise byte range accepted", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "nums.txt"), {
|
||||
acceptRanges: true,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Accept-Ranges", "bytes").expect("123456789").end(done);
|
||||
});
|
||||
|
||||
it("should respond to range request", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "nums.txt"), {
|
||||
acceptRanges: true,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").set("Range", "bytes=0-4").expect(206, "12345", done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when false", function () {
|
||||
it("should not advertise accept-ranges", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "nums.txt"), {
|
||||
acceptRanges: false,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Accept-Ranges")).end(done);
|
||||
});
|
||||
|
||||
it("should not honor range requests", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "nums.txt"), {
|
||||
acceptRanges: false,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").set("Range", "bytes=0-4").expect(200, "123456789", done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with "cacheControl" option', function () {
|
||||
describe("when true", function () {
|
||||
it("should send cache-control header", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
cacheControl: true,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0").end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when false", function () {
|
||||
it("should not send cache-control header", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
cacheControl: false,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Cache-Control")).end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with "dotfiles" option', function () {
|
||||
describe('when "allow"', function () {
|
||||
it("should allow dotfiles", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, ".name"), {
|
||||
dotfiles: "allow",
|
||||
});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(200)
|
||||
.expect(utils.shouldHaveBody(Buffer.from("tobi")))
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "deny"', function () {
|
||||
it("should deny dotfiles", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, ".name"), {
|
||||
dotfiles: "deny",
|
||||
});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(403)
|
||||
.expect(/Forbidden/)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "ignore"', function () {
|
||||
it("should ignore dotfiles", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, ".name"), {
|
||||
dotfiles: "ignore",
|
||||
});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(404)
|
||||
.expect(/Not Found/)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with "headers" option', function () {
|
||||
it("should set headers on response", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
headers: {
|
||||
"X-Foo": "Bar",
|
||||
"X-Bar": "Foo",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("X-Foo", "Bar").expect("X-Bar", "Foo").end(done);
|
||||
});
|
||||
|
||||
it("should use last header when duplicated", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
headers: {
|
||||
"X-Foo": "Bar",
|
||||
"x-foo": "bar",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("X-Foo", "bar").end(done);
|
||||
});
|
||||
|
||||
it("should override Content-Type", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
headers: {
|
||||
"Content-Type": "text/x-custom",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Content-Type", "text/x-custom").end(done);
|
||||
});
|
||||
|
||||
it("should not set headers on 404", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "does-not-exist"), {
|
||||
headers: {
|
||||
"X-Foo": "Bar",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(404).expect(utils.shouldNotHaveHeader("X-Foo")).end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with "immutable" option', function () {
|
||||
describe("when true", function () {
|
||||
it("should send cache-control header with immutable", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
immutable: true,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0, immutable").end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when false", function () {
|
||||
it("should not send cache-control header with immutable", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
immutable: false,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0").end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with "lastModified" option', function () {
|
||||
describe("when true", function () {
|
||||
it("should send last-modified header", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
lastModified: true,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect(utils.shouldHaveHeader("Last-Modified")).end(done);
|
||||
});
|
||||
|
||||
it("should conditionally respond with if-modified-since", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
lastModified: true,
|
||||
});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("If-Modified-Since", new Date(Date.now() + 99999).toUTCString())
|
||||
.expect(304, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when false", function () {
|
||||
it("should not have last-modified header", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
lastModified: false,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Last-Modified")).end(done);
|
||||
});
|
||||
|
||||
it("should not honor if-modified-since", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
lastModified: false,
|
||||
});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.set("If-Modified-Since", new Date(Date.now() + 99999).toUTCString())
|
||||
.expect(200)
|
||||
.expect(utils.shouldNotHaveHeader("Last-Modified"))
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with "maxAge" option', function () {
|
||||
it("should set cache-control max-age to milliseconds", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: 20000,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=20").end(done);
|
||||
});
|
||||
|
||||
it("should cap cache-control max-age to 1 year", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: 99999999999,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=31536000").end(done);
|
||||
});
|
||||
|
||||
it.todo("should min cache-control max-age to 0", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: -20000,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0").end(done);
|
||||
});
|
||||
|
||||
it.todo("should floor cache-control max-age", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: 21911.23,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=21").end(done);
|
||||
});
|
||||
|
||||
describe("when cacheControl: false", function () {
|
||||
it("should not send cache-control", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
cacheControl: false,
|
||||
maxAge: 20000,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Cache-Control")).end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when string", function () {
|
||||
it("should accept plain number as milliseconds", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: "20000",
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=20").end(done);
|
||||
});
|
||||
|
||||
it('should accept suffix "s" for seconds', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: "20s",
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=20").end(done);
|
||||
});
|
||||
|
||||
it('should accept suffix "m" for minutes', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: "20m",
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=1200").end(done);
|
||||
});
|
||||
|
||||
it('should accept suffix "d" for days', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(path.resolve(fixtures, "user.html"), {
|
||||
maxAge: "20d",
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=1728000").end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe.todo('with "root" option', function () {
|
||||
it("should allow relative path", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile("name.txt", {
|
||||
root: fixtures,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200, "tobi", done);
|
||||
});
|
||||
|
||||
it("should allow up within root", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile("fake/../name.txt", {
|
||||
root: fixtures,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(200, "tobi", done);
|
||||
});
|
||||
|
||||
it.todo("should reject up outside root", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile(".." + path.sep + path.relative(path.dirname(fixtures), path.join(fixtures, "name.txt")), {
|
||||
root: fixtures,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(403, done);
|
||||
});
|
||||
|
||||
it("should reject reading outside root", function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendFile("../name.txt", {
|
||||
root: fixtures,
|
||||
});
|
||||
});
|
||||
|
||||
request(app).get("/").expect(403, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createApp(path?, options?, fn?) {
|
||||
var app = express();
|
||||
|
||||
app.use(function sendFileMiddleware(req, res) {
|
||||
res.sendFile(path, options, fn);
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
36
test/js/third_party/express/support/after.ts
vendored
36
test/js/third_party/express/support/after.ts
vendored
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* https://www.npmjs.com/package/after
|
||||
*
|
||||
* I refuse to install a 30 line function via npm
|
||||
*/
|
||||
module.exports = after;
|
||||
|
||||
/**
|
||||
* Invoke a callback after `n` calls
|
||||
*/
|
||||
function after(count, callback, err_cb) {
|
||||
var bail = false;
|
||||
err_cb = err_cb || noop;
|
||||
proxy.count = count;
|
||||
|
||||
return count === 0 ? callback() : proxy;
|
||||
|
||||
function proxy(err, result) {
|
||||
if (proxy.count <= 0) {
|
||||
throw new Error("after called too many times");
|
||||
}
|
||||
--proxy.count;
|
||||
|
||||
// after first error, rest are passed to err_cb
|
||||
if (err) {
|
||||
bail = true;
|
||||
callback(err);
|
||||
// future error callbacks will go to error handler
|
||||
callback = err_cb;
|
||||
} else if (proxy.count === 0 && !bail) {
|
||||
callback(null, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
83
test/js/third_party/express/support/utils.ts
vendored
83
test/js/third_party/express/support/utils.ts
vendored
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var assert = require("node:assert");
|
||||
var { METHODS } = require("node:http");
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
exports.shouldHaveBody = shouldHaveBody;
|
||||
exports.shouldHaveHeader = shouldHaveHeader;
|
||||
exports.shouldNotHaveBody = shouldNotHaveBody;
|
||||
exports.shouldNotHaveHeader = shouldNotHaveHeader;
|
||||
exports.shouldSkipQuery = shouldSkipQuery;
|
||||
exports.methods = METHODS.map(method => method.toLowerCase()); // from lib/utils.js
|
||||
|
||||
/**
|
||||
* Assert that a supertest response has a specific body.
|
||||
*
|
||||
* @param {Buffer} buf
|
||||
* @returns {function}
|
||||
*/
|
||||
|
||||
function shouldHaveBody(buf) {
|
||||
return function (res) {
|
||||
var body = !Buffer.isBuffer(res.body) ? Buffer.from(res.text) : res.body;
|
||||
assert.ok(body, "response has body");
|
||||
assert.strictEqual(body.toString("hex"), buf.toString("hex"));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a supertest response does have a header.
|
||||
*
|
||||
* @param {string} header Header name to check
|
||||
* @returns {function}
|
||||
*/
|
||||
|
||||
function shouldHaveHeader(header) {
|
||||
return function (res) {
|
||||
assert.ok(header.toLowerCase() in res.headers, "should have header " + header);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a supertest response does not have a body.
|
||||
*
|
||||
* @returns {function}
|
||||
*/
|
||||
|
||||
function shouldNotHaveBody() {
|
||||
return function (res) {
|
||||
assert.ok(res.text === "" || res.text === undefined);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a supertest response does not have a header.
|
||||
*
|
||||
* @param {string} header Header name to check
|
||||
* @returns {function}
|
||||
*/
|
||||
function shouldNotHaveHeader(header) {
|
||||
return function (res) {
|
||||
assert.ok(!(header.toLowerCase() in res.headers), "should not have header " + header);
|
||||
};
|
||||
}
|
||||
|
||||
function getMajorVersion(versionString) {
|
||||
return versionString.split(".")[0];
|
||||
}
|
||||
|
||||
function shouldSkipQuery(versionString) {
|
||||
// Skipping HTTP QUERY tests on Node 21, it is reported in http.METHODS on 21.7.2 but not supported
|
||||
// update this implementation to run on supported versions of 21 once they exist
|
||||
// upstream tracking https://github.com/nodejs/node/issues/51562
|
||||
// express tracking issue: https://github.com/expressjs/express/issues/5615
|
||||
return Number(getMajorVersion(versionString)) === 21;
|
||||
}
|
||||
@@ -3,5 +3,12 @@
|
||||
"package": "elysia",
|
||||
"repository": "https://github.com/elysiajs/elysia",
|
||||
"tag": "1.4.12"
|
||||
},
|
||||
{
|
||||
"package": "express",
|
||||
"repository": "https://github.com/expressjs/express",
|
||||
"tag": "v5.1.0",
|
||||
"testExtensions": ["js"],
|
||||
"build": false
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user