diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/js/bun/http/fetch-file-upload.test.ts | 82 | ||||
-rw-r--r-- | test/js/bun/http/serve.test.ts | 52 | ||||
-rw-r--r-- | test/js/node/path/path.test.js | 70 | ||||
-rw-r--r-- | test/js/web/html/FormData.test.ts | 119 | ||||
-rw-r--r-- | test/regression/issue/02499.test.ts | 7 |
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); |