aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/js/bun/http/fetch-file-upload.test.ts82
-rw-r--r--test/js/bun/http/serve.test.ts52
-rw-r--r--test/js/node/path/path.test.js70
-rw-r--r--test/js/web/html/FormData.test.ts119
-rw-r--r--test/regression/issue/02499.test.ts7
5 files changed, 326 insertions, 4 deletions
diff --git a/test/js/bun/http/fetch-file-upload.test.ts b/test/js/bun/http/fetch-file-upload.test.ts
new file mode 100644
index 000000000..b070fbd6e
--- /dev/null
+++ b/test/js/bun/http/fetch-file-upload.test.ts
@@ -0,0 +1,82 @@
+import { expect, test, describe } from "bun:test";
+import { withoutAggressiveGC } from "harness";
+import { tmpdir } from "os";
+import { join } from "path";
+
+test("uploads roundtrip", async () => {
+ const body = Bun.file(import.meta.dir + "/fetch.js.txt");
+ const bodyText = await body.text();
+
+ const server = Bun.serve({
+ port: 0,
+ development: false,
+ async fetch(req) {
+ const text = await req.text();
+ expect(text).toBe(bodyText);
+
+ return new Response(Bun.file(import.meta.dir + "/fetch.js.txt"));
+ },
+ });
+
+ // @ts-ignore
+ const reqBody = new Request(`http://${server.hostname}:${server.port}`, {
+ body,
+ method: "POST",
+ });
+ const res = await fetch(reqBody);
+ expect(res.status).toBe(200);
+
+ // but it does for Response
+ expect(res.headers.get("Content-Type")).toBe("text/plain;charset=utf-8");
+ const resText = await res.text();
+ expect(resText).toBe(bodyText);
+
+ server.stop(true);
+});
+
+test("uploads roundtrip with sendfile()", async () => {
+ var hugeTxt = "huge".repeat(1024 * 1024 * 32);
+ const path = join(tmpdir(), "huge.txt");
+ require("fs").writeFileSync(path, hugeTxt);
+
+ const server = Bun.serve({
+ maxRequestBodySize: 1024 * 1024 * 1024 * 8,
+ async fetch(req) {
+ var count = 0;
+ for await (let chunk of req.body!) {
+ count += chunk.byteLength;
+ }
+ return new Response(count + "");
+ },
+ });
+
+ const resp = await fetch("http://" + server.hostname + ":" + server.port, {
+ body: Bun.file(path),
+ method: "PUT",
+ });
+
+ expect(resp.status).toBe(200);
+
+ const body = parseInt(await resp.text());
+ expect(body).toBe(hugeTxt.length);
+
+ server.stop(true);
+});
+
+test("missing file throws the expected error", async () => {
+ Bun.gc(true);
+ // Run this 1000 times to check for GC bugs
+ withoutAggressiveGC(() => {
+ const body = Bun.file(import.meta.dir + "/fetch123123231123.js.txt");
+ for (let i = 0; i < 1000; i++) {
+ const resp = fetch(`http://example.com`, {
+ body,
+ method: "POST",
+ proxy: "http://localhost:3000",
+ });
+ expect(Bun.peek.status(resp)).toBe("rejected");
+ expect(async () => await resp).toThrow("No such file or directory");
+ }
+ });
+ Bun.gc(true);
+});
diff --git a/test/js/bun/http/serve.test.ts b/test/js/bun/http/serve.test.ts
index 73de6a381..a152e7e09 100644
--- a/test/js/bun/http/serve.test.ts
+++ b/test/js/bun/http/serve.test.ts
@@ -1006,3 +1006,55 @@ it("request body and signal life cycle", async () => {
server.stop(true);
}
});
+
+it("propagates content-type from a Bun.file()'s file path in fetch()", async () => {
+ const body = Bun.file(import.meta.dir + "/fetch.js.txt");
+ const bodyText = await body.text();
+
+ const server = Bun.serve({
+ port: 0,
+ development: false,
+ async fetch(req) {
+ expect(req.headers.get("Content-Type")).toBe("text/plain;charset=utf-8");
+ const text = await req.text();
+ expect(text).toBe(bodyText);
+
+ return new Response(Bun.file(import.meta.dir + "/fetch.js.txt"));
+ },
+ });
+
+ // @ts-ignore
+ const reqBody = new Request(`http://${server.hostname}:${server.port}`, {
+ body,
+ method: "POST",
+ });
+ const res = await fetch(reqBody);
+ expect(res.status).toBe(200);
+
+ // but it does for Response
+ expect(res.headers.get("Content-Type")).toBe("text/plain;charset=utf-8");
+
+ server.stop(true);
+});
+
+it("does propagate type for Blob", async () => {
+ const server = Bun.serve({
+ port: 0,
+ development: false,
+ async fetch(req) {
+ expect(req.headers.get("Content-Type")).toBeNull();
+ return new Response(new Blob(["hey"], { type: "text/plain;charset=utf-8" }));
+ },
+ });
+
+ const body = new Blob(["hey"], { type: "text/plain;charset=utf-8" });
+ // @ts-ignore
+ const res = await fetch(`http://${server.hostname}:${server.port}`, {
+ body,
+ method: "POST",
+ });
+ expect(res.status).toBe(200);
+ expect(res.headers.get("Content-Type")).toBe("text/plain;charset=utf-8");
+
+ server.stop(true);
+});
diff --git a/test/js/node/path/path.test.js b/test/js/node/path/path.test.js
index d2880f124..caaf12db0 100644
--- a/test/js/node/path/path.test.js
+++ b/test/js/node/path/path.test.js
@@ -450,3 +450,73 @@ it("path.resolve", () => {
});
strictEqual(failures.length, 0, failures.join("\n"));
});
+
+it("path.parse", () => {
+ expect(path.parse("/tmp")).toStrictEqual({ root: "/", dir: "/", base: "tmp", ext: "", name: "tmp" });
+
+ expect(path.parse("/tmp/test.txt")).toStrictEqual({
+ root: "/",
+ dir: "/tmp",
+ base: "test.txt",
+ ext: ".txt",
+ name: "test",
+ });
+
+ expect(path.parse("/tmp/test/file.txt")).toStrictEqual({
+ root: "/",
+ dir: "/tmp/test",
+ base: "file.txt",
+ ext: ".txt",
+ name: "file",
+ });
+
+ expect(path.parse("/tmp/test/dir")).toStrictEqual({ root: "/", dir: "/tmp/test", base: "dir", ext: "", name: "dir" });
+ expect(path.parse("/tmp/test/dir/")).toStrictEqual({
+ root: "/",
+ dir: "/tmp/test",
+ base: "dir",
+ ext: "",
+ name: "dir",
+ });
+
+ expect(path.parse(".")).toStrictEqual({ root: "", dir: "", base: ".", ext: "", name: "." });
+ expect(path.parse("./")).toStrictEqual({ root: "", dir: "", base: ".", ext: "", name: "." });
+ expect(path.parse("/.")).toStrictEqual({ root: "/", dir: "/", base: ".", ext: "", name: "." });
+ expect(path.parse("/../")).toStrictEqual({ root: "/", dir: "/", base: "..", ext: ".", name: "." });
+
+ expect(path.parse("./file.txt")).toStrictEqual({ root: "", dir: ".", base: "file.txt", ext: ".txt", name: "file" });
+ expect(path.parse("../file.txt")).toStrictEqual({ root: "", dir: "..", base: "file.txt", ext: ".txt", name: "file" });
+ expect(path.parse("../test/file.txt")).toStrictEqual({
+ root: "",
+ dir: "../test",
+ base: "file.txt",
+ ext: ".txt",
+ name: "file",
+ });
+ expect(path.parse("test/file.txt")).toStrictEqual({
+ root: "",
+ dir: "test",
+ base: "file.txt",
+ ext: ".txt",
+ name: "file",
+ });
+
+ expect(path.parse("test/dir")).toStrictEqual({ root: "", dir: "test", base: "dir", ext: "", name: "dir" });
+ expect(path.parse("test/dir/another_dir")).toStrictEqual({
+ root: "",
+ dir: "test/dir",
+ base: "another_dir",
+ ext: "",
+ name: "another_dir",
+ });
+
+ expect(path.parse("./dir")).toStrictEqual({ root: "", dir: ".", base: "dir", ext: "", name: "dir" });
+ expect(path.parse("../dir")).toStrictEqual({ root: "", dir: "..", base: "dir", ext: "", name: "dir" });
+ expect(path.parse("../dir/another_dir")).toStrictEqual({
+ root: "",
+ dir: "../dir",
+ base: "another_dir",
+ ext: "",
+ name: "another_dir",
+ });
+});
diff --git a/test/js/web/html/FormData.test.ts b/test/js/web/html/FormData.test.ts
index abb298c1a..cbaf5aaa7 100644
--- a/test/js/web/html/FormData.test.ts
+++ b/test/js/web/html/FormData.test.ts
@@ -302,6 +302,125 @@ describe("FormData", () => {
server.stop(true);
});
+ for (let useRequestConstructor of [true, false]) {
+ describe(useRequestConstructor ? "Request constructor" : "fetch()", () => {
+ function send(args: Parameters<typeof fetch>) {
+ if (useRequestConstructor) {
+ return fetch(new Request(...args));
+ } else {
+ return fetch(...args);
+ }
+ }
+ for (let headers of [{}, undefined, { headers: { X: "Y" } }]) {
+ describe("headers: " + Bun.inspect(headers).replaceAll(/([\n ])/gim, ""), () => {
+ it("send on HTTP server with FormData & Blob (roundtrip)", async () => {
+ let contentType = "";
+ const server = Bun.serve({
+ port: 0,
+ development: false,
+ async fetch(req) {
+ const formData = await req.formData();
+ contentType = req.headers.get("Content-Type")!;
+ return new Response(formData);
+ },
+ });
+
+ const form = new FormData();
+ form.append("foo", new Blob(["baz"], { type: "text/plain" }), "bar");
+ form.append("bar", "baz");
+
+ // @ts-ignore
+ const reqBody = [
+ `http://${server.hostname}:${server.port}`,
+ {
+ body: form,
+
+ headers,
+ method: "POST",
+ },
+ ];
+ const res = await send(reqBody);
+ const body = await res.formData();
+ expect(await (body.get("foo") as Blob).text()).toBe("baz");
+ expect(body.get("bar")).toBe("baz");
+ server.stop(true);
+ });
+
+ it("send on HTTP server with FormData & Bun.file (roundtrip)", async () => {
+ let contentType = "";
+ const server = Bun.serve({
+ port: 0,
+ development: false,
+ async fetch(req) {
+ const formData = await req.formData();
+ contentType = req.headers.get("Content-Type")!;
+ return new Response(formData);
+ },
+ });
+
+ const form = new FormData();
+ const file = Bun.file(import.meta.dir + "/form-data-fixture.txt");
+ const text = await file.text();
+ form.append("foo", file);
+ form.append("bar", "baz");
+
+ // @ts-ignore
+ const reqBody = [
+ `http://${server.hostname}:${server.port}`,
+ {
+ body: form,
+
+ headers,
+ method: "POST",
+ },
+ ];
+ const res = await send(reqBody);
+ const body = await res.formData();
+ expect(await (body.get("foo") as Blob).text()).toBe(text);
+ expect(contentType).toContain("multipart/form-data");
+ expect(body.get("bar")).toBe("baz");
+ expect(contentType).toContain("multipart/form-data");
+
+ server.stop(true);
+ });
+
+ it("send on HTTP server with FormData (roundtrip)", async () => {
+ let contentType = "";
+ const server = Bun.serve({
+ port: 0,
+ development: false,
+ async fetch(req) {
+ const formData = await req.formData();
+ contentType = req.headers.get("Content-Type")!;
+ return new Response(formData);
+ },
+ });
+
+ const form = new FormData();
+ form.append("foo", "boop");
+ form.append("bar", "baz");
+
+ // @ts-ignore
+ const reqBody = [
+ `http://${server.hostname}:${server.port}`,
+ {
+ body: form,
+
+ headers,
+ method: "POST",
+ },
+ ];
+ const res = await send(reqBody);
+ const body = await res.formData();
+ expect(contentType).toContain("multipart/form-data");
+ expect(body.get("foo")).toBe("boop");
+ expect(body.get("bar")).toBe("baz");
+ server.stop(true);
+ });
+ });
+ }
+ });
+ }
describe("Bun.file support", () => {
describe("roundtrip", () => {
const path = import.meta.dir + "/form-data-fixture.txt";
diff --git a/test/regression/issue/02499.test.ts b/test/regression/issue/02499.test.ts
index 0e4666b36..f1ee1da80 100644
--- a/test/regression/issue/02499.test.ts
+++ b/test/regression/issue/02499.test.ts
@@ -12,8 +12,7 @@ it("onAborted() and onWritable are not called after receiving an empty response
testDone(new Error("Test timed out, which means it failed"));
};
- const body = new FormData();
- body.append("hey", "hi");
+ const invalidJSON = Buffer.from("invalid json");
// We want to test that the server isn't keeping the connection open in a
// zombie-like state when an error occurs due to an unhandled rejected promise
@@ -69,7 +68,7 @@ it("onAborted() and onWritable are not called after receiving an empty response
try {
await fetch(`http://${hostname}:${port}/upload`, {
- body,
+ body: invalidJSON,
keepalive: false,
method: "POST",
timeout: true,
@@ -91,4 +90,4 @@ it("onAborted() and onWritable are not called after receiving an empty response
}
timeout.onabort = () => {};
testDone();
-});
+}, 30_000);