diff options
Diffstat (limited to 'test/bun.js/fetch.test.js')
-rw-r--r-- | test/bun.js/fetch.test.js | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/test/bun.js/fetch.test.js b/test/bun.js/fetch.test.js new file mode 100644 index 000000000..9b6093afd --- /dev/null +++ b/test/bun.js/fetch.test.js @@ -0,0 +1,440 @@ +import { it, describe, expect } from "bun:test"; +import fs from "fs"; +import { gc } from "./gc"; + +describe("fetch", () => { + const urls = ["https://example.com", "http://example.com"]; + for (let url of urls) { + gc(); + it(url, async () => { + gc(); + const response = await fetch(url); + gc(); + const text = await response.text(); + gc(); + expect( + fs.readFileSync( + import.meta.path.substring(0, import.meta.path.lastIndexOf("/")) + + "/fetch.js.txt", + "utf8" + ) + ).toBe(text); + }); + } +}); + +function testBlobInterface(blobbyConstructor, hasBlobFn) { + for (let withGC of [false, true]) { + for (let jsonObject of [ + { hello: true }, + { + hello: + "π π π π π π
π π€£ π₯² βΊοΈ π π π π π π π π₯° π π π π π π π π π€ͺ π€¨ π§ π€ π π₯Έ π€© π₯³", + }, + ]) { + it(`${jsonObject.hello === true ? "latin1" : "utf16"} json${ + withGC ? " (with gc) " : "" + }`, async () => { + if (withGC) gc(); + var response = blobbyConstructor(JSON.stringify(jsonObject)); + if (withGC) gc(); + expect(JSON.stringify(await response.json())).toBe( + JSON.stringify(jsonObject) + ); + if (withGC) gc(); + }); + + it(`${ + jsonObject.hello === true ? "latin1" : "utf16" + } arrayBuffer -> json${withGC ? " (with gc) " : ""}`, async () => { + if (withGC) gc(); + var response = blobbyConstructor( + new TextEncoder().encode(JSON.stringify(jsonObject)) + ); + if (withGC) gc(); + expect(JSON.stringify(await response.json())).toBe( + JSON.stringify(jsonObject) + ); + if (withGC) gc(); + }); + + it(`${jsonObject.hello === true ? "latin1" : "utf16"} text${ + withGC ? " (with gc) " : "" + }`, async () => { + if (withGC) gc(); + var response = blobbyConstructor(JSON.stringify(jsonObject)); + if (withGC) gc(); + expect(await response.text()).toBe(JSON.stringify(jsonObject)); + if (withGC) gc(); + }); + + it(`${ + jsonObject.hello === true ? "latin1" : "utf16" + } arrayBuffer -> text${withGC ? " (with gc) " : ""}`, async () => { + if (withGC) gc(); + var response = blobbyConstructor( + new TextEncoder().encode(JSON.stringify(jsonObject)) + ); + if (withGC) gc(); + expect(await response.text()).toBe(JSON.stringify(jsonObject)); + if (withGC) gc(); + }); + + it(`${jsonObject.hello === true ? "latin1" : "utf16"} arrayBuffer${ + withGC ? " (with gc) " : "" + }`, async () => { + if (withGC) gc(); + + var response = blobbyConstructor(JSON.stringify(jsonObject)); + if (withGC) gc(); + + const bytes = new TextEncoder().encode(JSON.stringify(jsonObject)); + if (withGC) gc(); + + const compare = new Uint8Array(await response.arrayBuffer()); + if (withGC) gc(); + + for (let i = 0; i < compare.length; i++) { + if (withGC) gc(); + + expect(compare[i]).toBe(bytes[i]); + if (withGC) gc(); + } + if (withGC) gc(); + }); + + it(`${ + jsonObject.hello === true ? "latin1" : "utf16" + } arrayBuffer -> arrayBuffer${withGC ? " (with gc) " : ""}`, async () => { + if (withGC) gc(); + + var response = blobbyConstructor( + new TextEncoder().encode(JSON.stringify(jsonObject)) + ); + if (withGC) gc(); + + const bytes = new TextEncoder().encode(JSON.stringify(jsonObject)); + if (withGC) gc(); + + const compare = new Uint8Array(await response.arrayBuffer()); + if (withGC) gc(); + + for (let i = 0; i < compare.length; i++) { + if (withGC) gc(); + + expect(compare[i]).toBe(bytes[i]); + if (withGC) gc(); + } + if (withGC) gc(); + }); + + hasBlobFn && + it(`${jsonObject.hello === true ? "latin1" : "utf16"} blob${ + withGC ? " (with gc) " : "" + }`, async () => { + if (withGC) gc(); + const text = JSON.stringify(jsonObject); + var response = blobbyConstructor(text); + if (withGC) gc(); + const size = new TextEncoder().encode(text).byteLength; + if (withGC) gc(); + const blobed = await response.blob(); + if (withGC) gc(); + expect(blobed instanceof Blob).toBe(true); + if (withGC) gc(); + expect(blobed.size).toBe(size); + if (withGC) gc(); + expect(blobed.type).toBe(""); + if (withGC) gc(); + blobed.type = "application/json"; + if (withGC) gc(); + expect(blobed.type).toBe("application/json"); + if (withGC) gc(); + const out = await blobed.text(); + expect(out).toBe(text); + if (withGC) gc(); + await new Promise((resolve) => setTimeout(resolve, 1)); + if (withGC) gc(); + expect(out).toBe(text); + const first = await blobed.arrayBuffer(); + const initial = first[0]; + first[0] = 254; + const second = await blobed.arrayBuffer(); + expect(second[0]).toBe(initial); + expect(first[0]).toBe(254); + }); + } + } +} + +describe("Blob", () => { + testBlobInterface((data) => new Blob([data])); + + var blobConstructorValues = [ + ["123", "456"], + ["123", 456], + ["123", "456", "789"], + ["123", 456, 789], + [1, 2, 3, 4, 5, 6, 7, 8, 9], + [Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 9])], + [Uint8Array.from([1, 2, 3, 4]), "5678", 9], + [new Blob([Uint8Array.from([1, 2, 3, 4])]), "5678", 9], + [ + new Blob([ + new TextEncoder().encode( + "π π π π π π
π π€£ π₯² βΊοΈ π π π π π π π π₯° π π π π π π π π π€ͺ π€¨ π§ π€ π π₯Έ π€© π₯³" + ), + ]), + ], + [ + new TextEncoder().encode( + "π π π π π π
π π€£ π₯² βΊοΈ π π π π π π π π₯° π π π π π π π π π€ͺ π€¨ π§ π€ π π₯Έ π€© π₯³" + ), + ], + ]; + + var expected = [ + "123456", + "123456", + "123456789", + "123456789", + "123456789", + "\x01\x02\x03\x04\x05\x06\x07\t", + "\x01\x02\x03\x0456789", + "\x01\x02\x03\x0456789", + "π π π π π π
π π€£ π₯² βΊοΈ π π π π π π π π₯° π π π π π π π π π€ͺ π€¨ π§ π€ π π₯Έ π€© π₯³", + "π π π π π π
π π€£ π₯² βΊοΈ π π π π π π π π₯° π π π π π π π π π€ͺ π€¨ π§ π€ π π₯Έ π€© π₯³", + ]; + + it(`blobConstructorValues`, async () => { + for (let i = 0; i < blobConstructorValues.length; i++) { + var response = new Blob(blobConstructorValues[i]); + const res = await response.text(); + if (res !== expected[i]) { + throw new Error( + `Failed: ${expected[i] + .split("") + .map((a) => a.charCodeAt(0))}, received: ${res + .split("") + .map((a) => a.charCodeAt(0))}` + ); + } + + expect(res).toBe(expected[i]); + } + }); + + for (let withGC of [false, true]) { + it(`Blob.slice() ${withGC ? " with gc" : ""}`, async () => { + var parts = ["hello", " ", "world"]; + if (withGC) gc(); + var str = parts.join(""); + if (withGC) gc(); + var combined = new Blob(parts); + if (withGC) gc(); + for (let part of parts) { + if (withGC) gc(); + expect( + await combined + .slice(str.indexOf(part), str.indexOf(part) + part.length) + .text() + ).toBe(part); + if (withGC) gc(); + } + if (withGC) gc(); + for (let part of parts) { + if (withGC) gc(); + expect( + await combined + .slice(str.indexOf(part), str.indexOf(part) + part.length) + .text() + ).toBe(part); + if (withGC) gc(); + } + }); + } +}); + +describe("Response", () => { + describe("Response.json", () => { + it("works", async () => { + const inputs = [ + "hellooo", + [[123], 456, 789], + { hello: "world" }, + { ok: "π π π π₯° π " }, + ]; + for (let input of inputs) { + const output = JSON.stringify(input); + expect(await Response.json(input).text()).toBe(output); + } + // JSON.stringify() returns undefined + expect(await Response.json().text()).toBe(""); + // JSON.stringify("") returns '""' + expect(await Response.json("").text()).toBe('""'); + }); + it("sets the content-type header", () => { + let response = Response.json("hello"); + expect(response.type).toBe("basic"); + expect(response.headers.get("content-type")).toBe( + "application/json;charset=utf-8" + ); + expect(response.status).toBe(200); + }); + it("supports number status code", () => { + let response = Response.json("hello", 407); + expect(response.type).toBe("basic"); + expect(response.headers.get("content-type")).toBe( + "application/json;charset=utf-8" + ); + expect(response.status).toBe(407); + }); + + it("supports headers", () => { + var response = Response.json("hello", { + headers: { + "content-type": "potato", + "x-hello": "world", + }, + status: 408, + }); + + expect(response.headers.get("x-hello")).toBe("world"); + expect(response.status).toBe(408); + }); + }); + describe("Response.redirect", () => { + it("works", () => { + const inputs = [ + "http://example.com", + "http://example.com/", + "http://example.com/hello", + "http://example.com/hello/", + "http://example.com/hello/world", + "http://example.com/hello/world/", + ]; + for (let input of inputs) { + expect(Response.redirect(input).headers.get("Location")).toBe(input); + } + }); + + it("supports headers", () => { + var response = Response.redirect("https://example.com", { + headers: { + "content-type": "potato", + "x-hello": "world", + Location: "https://wrong.com", + }, + status: 408, + }); + expect(response.headers.get("x-hello")).toBe("world"); + expect(response.headers.get("Location")).toBe("https://example.com"); + expect(response.status).toBe(302); + expect(response.type).toBe("basic"); + expect(response.ok).toBe(false); + }); + }); + describe("Response.error", () => { + it("works", () => { + expect(Response.error().type).toBe("error"); + expect(Response.error().ok).toBe(false); + expect(Response.error().status).toBe(0); + }); + }); + it("clone", async () => { + gc(); + var body = new Response("<div>hello</div>", { + headers: { + "content-type": "text/html; charset=utf-8", + }, + }); + gc(); + var clone = body.clone(); + gc(); + body.headers.set("content-type", "text/plain"); + gc(); + expect(clone.headers.get("content-type")).toBe("text/html; charset=utf-8"); + gc(); + expect(body.headers.get("content-type")).toBe("text/plain"); + gc(); + expect(await clone.text()).toBe("<div>hello</div>"); + gc(); + }); + it("invalid json", async () => { + gc(); + var body = new Response("<div>hello</div>", { + headers: { + "content-type": "text/html; charset=utf-8", + }, + }); + try { + await body.json(); + expect(false).toBe(true); + } catch (exception) { + expect(exception instanceof SyntaxError); + } + }); + + testBlobInterface((data) => new Response(data), true); +}); + +describe("Request", () => { + it("clone", async () => { + gc(); + var body = new Request("https://hello.com", { + headers: { + "content-type": "text/html; charset=utf-8", + }, + body: "<div>hello</div>", + }); + gc(); + expect(body.headers.get("content-type")).toBe("text/html; charset=utf-8"); + gc(); + var clone = body.clone(); + gc(); + body.headers.set("content-type", "text/plain"); + gc(); + expect(clone.headers.get("content-type")).toBe("text/html; charset=utf-8"); + gc(); + expect(body.headers.get("content-type")).toBe("text/plain"); + gc(); + expect(await clone.text()).toBe("<div>hello</div>"); + gc(); + }); + + testBlobInterface( + (data) => new Request("https://hello.com", { body: data }), + true + ); +}); + +describe("Headers", () => { + it("writes", async () => { + var headers = new Headers({ + "content-type": "text/html; charset=utf-8", + }); + gc(); + expect(headers.get("content-type")).toBe("text/html; charset=utf-8"); + gc(); + headers.delete("content-type"); + gc(); + expect(headers.get("content-type")).toBe(null); + gc(); + headers.append("content-type", "text/plain"); + gc(); + expect(headers.get("content-type")).toBe("text/plain"); + gc(); + headers.append("content-type", "text/plain"); + gc(); + expect(headers.get("content-type")).toBe("text/plain, text/plain"); + gc(); + headers.set("content-type", "text/html; charset=utf-8"); + gc(); + expect(headers.get("content-type")).toBe("text/html; charset=utf-8"); + + headers.delete("content-type"); + gc(); + expect(headers.get("content-type")).toBe(null); + gc(); + }); +}); |