diff options
Diffstat (limited to 'test/js/web')
-rw-r--r-- | test/js/web/console/console-log.expected.txt | 8 | ||||
-rw-r--r-- | test/js/web/console/console-log.js | 6 | ||||
-rw-r--r-- | test/js/web/fetch/fetch-leak-test-fixture.js | 2 | ||||
-rw-r--r-- | test/js/web/fetch/fetch.test.ts | 23 | ||||
-rw-r--r-- | test/js/web/html/FormData.test.ts | 19 | ||||
-rw-r--r-- | test/js/web/html/URLSearchParams.test.ts | 5 | ||||
-rw-r--r-- | test/js/web/timers/process-setImmediate-fixture.js | 9 | ||||
-rw-r--r-- | test/js/web/timers/setImmediate.test.js | 27 | ||||
-rw-r--r-- | test/js/web/timers/setTimeout-unref-fixture-2.js | 9 | ||||
-rw-r--r-- | test/js/web/timers/setTimeout-unref-fixture-3.js | 7 | ||||
-rw-r--r-- | test/js/web/timers/setTimeout-unref-fixture-4.js | 5 | ||||
-rw-r--r-- | test/js/web/timers/setTimeout-unref-fixture-5.js | 5 | ||||
-rw-r--r-- | test/js/web/timers/setTimeout-unref-fixture.js | 12 | ||||
-rw-r--r-- | test/js/web/timers/setTimeout.test.js | 51 | ||||
-rw-r--r-- | test/js/web/util/atob.test.js | 9 | ||||
-rw-r--r-- | test/js/web/web-globals.test.js | 19 | ||||
-rw-r--r-- | test/js/web/websocket/websocket.test.js | 34 |
17 files changed, 223 insertions, 27 deletions
diff --git a/test/js/web/console/console-log.expected.txt b/test/js/web/console/console-log.expected.txt index 97191c8be..332322665 100644 --- a/test/js/web/console/console-log.expected.txt +++ b/test/js/web/console/console-log.expected.txt @@ -1,4 +1,6 @@ Hello World! +0 +-0 123 -123 123.567 @@ -7,6 +9,8 @@ true false null undefined +Infinity +-Infinity Symbol(Symbol Description) 2000-06-27T02:24:34.304Z [ 123, 456, 789 ] @@ -29,7 +33,9 @@ Symbol(Symbol Description) } Promise { <pending> } [Function] -[Function: Foo] +[Function] +[class Foo] +[class] {} [Function: foooo] /FooRegex/ diff --git a/test/js/web/console/console-log.js b/test/js/web/console/console-log.js index e23a3e9cb..4db40aaac 100644 --- a/test/js/web/console/console-log.js +++ b/test/js/web/console/console-log.js @@ -1,4 +1,6 @@ console.log("Hello World!"); +console.log(0); +console.log(-0); console.log(123); console.log(-123); console.log(123.567); @@ -7,6 +9,8 @@ console.log(true); console.log(false); console.log(null); console.log(undefined); +console.log(Infinity); +console.log(-Infinity); console.log(Symbol("Symbol Description")); console.log(new Date(Math.pow(2, 34) * 56)); console.log([123, 456, 789]); @@ -27,7 +31,9 @@ console.log(new Promise(() => {})); class Foo {} console.log(() => {}); +console.log(function () {}); console.log(Foo); +console.log(class {}); console.log(new Foo()); console.log(function foooo() {}); diff --git a/test/js/web/fetch/fetch-leak-test-fixture.js b/test/js/web/fetch/fetch-leak-test-fixture.js index 07275a425..c83bbea83 100644 --- a/test/js/web/fetch/fetch-leak-test-fixture.js +++ b/test/js/web/fetch/fetch-leak-test-fixture.js @@ -29,6 +29,6 @@ await (async function runAll() { await Bun.sleep(10); Bun.gc(true); -if ((heapStats().objectTypeCounts.Response ?? 0) > 10) { +if ((heapStats().objectTypeCounts.Response ?? 0) > 1 + ((COUNT / 2) | 0)) { throw new Error("Too many Response objects: " + heapStats().objectTypeCounts.Response); } diff --git a/test/js/web/fetch/fetch.test.ts b/test/js/web/fetch/fetch.test.ts index 4d529b231..768818420 100644 --- a/test/js/web/fetch/fetch.test.ts +++ b/test/js/web/fetch/fetch.test.ts @@ -387,6 +387,25 @@ describe("fetch", () => { }).toThrow("fetch() request with GET/HEAD/OPTIONS method cannot have body."); }), ); + + it("content length is inferred", async () => { + startServer({ + fetch(req) { + return new Response(req.headers.get("content-length")); + }, + hostname: "localhost", + }); + + // POST with body + const url = `http://${server.hostname}:${server.port}`; + const response = await fetch(url, { method: "POST", body: "buntastic" }); + expect(response.status).toBe(200); + expect(await response.text()).toBe("9"); + + const response2 = await fetch(url, { method: "POST", body: "" }); + expect(response2.status).toBe(200); + expect(await response2.text()).toBe("0"); + }); }); it("simultaneous HTTPS fetch", async () => { @@ -1156,6 +1175,10 @@ it("#2794", () => { expect(typeof Bun.fetch.bind).toBe("function"); }); +it("#3545", () => { + expect(() => fetch("http://example.com?a=b")).not.toThrow(); +}); + it("invalid header doesnt crash", () => { expect(() => fetch("http://example.com", { diff --git a/test/js/web/html/FormData.test.ts b/test/js/web/html/FormData.test.ts index cbaf5aaa7..45b4f2f5a 100644 --- a/test/js/web/html/FormData.test.ts +++ b/test/js/web/html/FormData.test.ts @@ -301,17 +301,18 @@ describe("FormData", () => { expect(await (body.get("foo") as Blob).text()).toBe("baz"); server.stop(true); }); - + type FetchReqArgs = [request: Request, init?: RequestInit]; + type FetchURLArgs = [url: string | URL | Request, init?: FetchRequestInit]; for (let useRequestConstructor of [true, false]) { describe(useRequestConstructor ? "Request constructor" : "fetch()", () => { - function send(args: Parameters<typeof fetch>) { + function send(args: FetchReqArgs | FetchURLArgs) { if (useRequestConstructor) { - return fetch(new Request(...args)); + return fetch(new Request(...(args as FetchReqArgs))); } else { - return fetch(...args); + return fetch(...(args as FetchURLArgs)); } } - for (let headers of [{}, undefined, { headers: { X: "Y" } }]) { + for (let headers of [{} as {}, undefined, { headers: { X: "Y" } }]) { describe("headers: " + Bun.inspect(headers).replaceAll(/([\n ])/gim, ""), () => { it("send on HTTP server with FormData & Blob (roundtrip)", async () => { let contentType = ""; @@ -330,11 +331,10 @@ describe("FormData", () => { form.append("bar", "baz"); // @ts-ignore - const reqBody = [ + const reqBody: FetchURLArgs = [ `http://${server.hostname}:${server.port}`, { body: form, - headers, method: "POST", }, @@ -364,7 +364,6 @@ describe("FormData", () => { form.append("foo", file); form.append("bar", "baz"); - // @ts-ignore const reqBody = [ `http://${server.hostname}:${server.port}`, { @@ -374,7 +373,7 @@ describe("FormData", () => { method: "POST", }, ]; - const res = await send(reqBody); + const res = await send(reqBody as FetchURLArgs); const body = await res.formData(); expect(await (body.get("foo") as Blob).text()).toBe(text); expect(contentType).toContain("multipart/form-data"); @@ -410,7 +409,7 @@ describe("FormData", () => { method: "POST", }, ]; - const res = await send(reqBody); + const res = await send(reqBody as FetchURLArgs); const body = await res.formData(); expect(contentType).toContain("multipart/form-data"); expect(body.get("foo")).toBe("boop"); diff --git a/test/js/web/html/URLSearchParams.test.ts b/test/js/web/html/URLSearchParams.test.ts index 120bb2321..41c42c25d 100644 --- a/test/js/web/html/URLSearchParams.test.ts +++ b/test/js/web/html/URLSearchParams.test.ts @@ -7,15 +7,20 @@ describe("URLSearchParams", () => { params.append("foo", "bar"); params.append("foo", "boop"); params.append("bar", "baz"); + // @ts-ignore expect(params.length).toBe(3); params.delete("foo"); + // @ts-ignore expect(params.length).toBe(1); params.append("foo", "bar"); + // @ts-ignore expect(params.length).toBe(2); params.delete("foo"); params.delete("foo"); + // @ts-ignore expect(params.length).toBe(1); params.delete("bar"); + // @ts-ignore expect(params.length).toBe(0); }); diff --git a/test/js/web/timers/process-setImmediate-fixture.js b/test/js/web/timers/process-setImmediate-fixture.js new file mode 100644 index 000000000..6ffd91c8d --- /dev/null +++ b/test/js/web/timers/process-setImmediate-fixture.js @@ -0,0 +1,9 @@ +setImmediate(() => { + console.log("setImmediate"); + return { + a: 1, + b: 2, + c: 3, + d: 4, + }; +}); diff --git a/test/js/web/timers/setImmediate.test.js b/test/js/web/timers/setImmediate.test.js index 9cd6fa1c9..d00224e0f 100644 --- a/test/js/web/timers/setImmediate.test.js +++ b/test/js/web/timers/setImmediate.test.js @@ -1,4 +1,6 @@ import { it, expect } from "bun:test"; +import { bunExe, bunEnv } from "harness"; +import path from "path"; it("setImmediate", async () => { var lastID = -1; @@ -45,3 +47,28 @@ it("clearImmediate", async () => { }); expect(called).toBe(false); }); + +it("setImmediate should not keep the process alive forever", async () => { + let process = null; + const success = async () => { + process = Bun.spawn({ + cmd: [bunExe(), "run", path.join(import.meta.dir, "process-setImmediate-fixture.js")], + stdout: "ignore", + env: { + ...bunEnv, + NODE_ENV: undefined, + }, + }); + await process.exited; + process = null; + return true; + }; + + const fail = async () => { + await Bun.sleep(500); + process?.kill(); + return false; + }; + + expect(await Promise.race([success(), fail()])).toBe(true); +}); diff --git a/test/js/web/timers/setTimeout-unref-fixture-2.js b/test/js/web/timers/setTimeout-unref-fixture-2.js new file mode 100644 index 000000000..6a78f13cd --- /dev/null +++ b/test/js/web/timers/setTimeout-unref-fixture-2.js @@ -0,0 +1,9 @@ +setTimeout(() => { + console.log("TEST FAILED!"); +}, 100) + .ref() + .unref(); + +setTimeout(() => { + // this one should always run +}, 1); diff --git a/test/js/web/timers/setTimeout-unref-fixture-3.js b/test/js/web/timers/setTimeout-unref-fixture-3.js new file mode 100644 index 000000000..41808f5fc --- /dev/null +++ b/test/js/web/timers/setTimeout-unref-fixture-3.js @@ -0,0 +1,7 @@ +setTimeout(() => { + setTimeout(() => {}, 999_999); +}, 100).unref(); + +setTimeout(() => { + // this one should always run +}, 1); diff --git a/test/js/web/timers/setTimeout-unref-fixture-4.js b/test/js/web/timers/setTimeout-unref-fixture-4.js new file mode 100644 index 000000000..9968f3b36 --- /dev/null +++ b/test/js/web/timers/setTimeout-unref-fixture-4.js @@ -0,0 +1,5 @@ +setTimeout(() => { + console.log("TEST PASSED!"); +}, 1) + .unref() + .ref(); diff --git a/test/js/web/timers/setTimeout-unref-fixture-5.js b/test/js/web/timers/setTimeout-unref-fixture-5.js new file mode 100644 index 000000000..e5caa1be4 --- /dev/null +++ b/test/js/web/timers/setTimeout-unref-fixture-5.js @@ -0,0 +1,5 @@ +setTimeout(() => { + console.log("TEST FAILED!"); +}, 100) + .ref() + .unref(); diff --git a/test/js/web/timers/setTimeout-unref-fixture.js b/test/js/web/timers/setTimeout-unref-fixture.js new file mode 100644 index 000000000..97a0f78a2 --- /dev/null +++ b/test/js/web/timers/setTimeout-unref-fixture.js @@ -0,0 +1,12 @@ +const timer = setTimeout(() => {}, 999_999_999); +if (timer.unref() !== timer) throw new Error("Expected timer.unref() === timer"); + +var ranCount = 0; +const going2Refresh = setTimeout(() => { + if (ranCount < 1) going2Refresh.refresh(); + ranCount++; + + if (ranCount === 2) { + console.log("SUCCESS"); + } +}, 1); diff --git a/test/js/web/timers/setTimeout.test.js b/test/js/web/timers/setTimeout.test.js index dbe89dea8..eef6bbae0 100644 --- a/test/js/web/timers/setTimeout.test.js +++ b/test/js/web/timers/setTimeout.test.js @@ -1,5 +1,7 @@ +import { spawnSync } from "bun"; import { it, expect } from "bun:test"; - +import { bunEnv, bunExe } from "harness"; +import path from "node:path"; it("setTimeout", async () => { var lastID = -1; const result = await new Promise((resolve, reject) => { @@ -172,11 +174,56 @@ it.skip("order of setTimeouts", done => { Promise.resolve().then(maybeDone(() => nums.push(1))); }); +it("setTimeout -> refresh", () => { + const { exitCode, stdout } = spawnSync({ + cmd: [bunExe(), path.join(import.meta.dir, "setTimeout-unref-fixture.js")], + env: bunEnv, + }); + expect(exitCode).toBe(0); + expect(stdout.toString()).toBe("SUCCESS\n"); +}); + +it("setTimeout -> unref -> ref works", () => { + const { exitCode, stdout } = spawnSync({ + cmd: [bunExe(), path.join(import.meta.dir, "setTimeout-unref-fixture-4.js")], + env: bunEnv, + }); + expect(exitCode).toBe(0); + expect(stdout.toString()).toBe("TEST PASSED!\n"); +}); + +it("setTimeout -> ref -> unref works, even if there is another timer", () => { + const { exitCode, stdout } = spawnSync({ + cmd: [bunExe(), path.join(import.meta.dir, "setTimeout-unref-fixture-2.js")], + env: bunEnv, + }); + expect(exitCode).toBe(0); + expect(stdout.toString()).toBe(""); +}); + +it("setTimeout -> ref -> unref works", () => { + const { exitCode, stdout } = spawnSync({ + cmd: [bunExe(), path.join(import.meta.dir, "setTimeout-unref-fixture-5.js")], + env: bunEnv, + }); + expect(exitCode).toBe(0); + expect(stdout.toString()).toBe(""); +}); + +it("setTimeout -> unref doesn't keep event loop alive forever", () => { + const { exitCode, stdout } = spawnSync({ + cmd: [bunExe(), path.join(import.meta.dir, "setTimeout-unref-fixture-3.js")], + env: bunEnv, + }); + expect(exitCode).toBe(0); + expect(stdout.toString()).toBe(""); +}); + it("setTimeout should refresh N times", done => { let count = 0; let timer = setTimeout(() => { count++; - timer.refresh(); + expect(timer.refresh()).toBe(timer); }, 50); setTimeout(() => { diff --git a/test/js/web/util/atob.test.js b/test/js/web/util/atob.test.js index 4945829e1..20c029f14 100644 --- a/test/js/web/util/atob.test.js +++ b/test/js/web/util/atob.test.js @@ -60,18 +60,15 @@ it("btoa", () => { expect(btoa("abcde")).toBe("YWJjZGU="); expect(btoa("abcdef")).toBe("YWJjZGVm"); expect(typeof btoa).toBe("function"); - try { - btoa(); - throw new Error("Expected error"); - } catch (error) { - expect(error.name).toBe("TypeError"); - } + expect(() => btoa()).toThrow("btoa requires 1 argument (a string)"); var window = "[object Window]"; expect(btoa("")).toBe(""); expect(btoa(null)).toBe("bnVsbA=="); expect(btoa(undefined)).toBe("dW5kZWZpbmVk"); expect(btoa(window)).toBe("W29iamVjdCBXaW5kb3dd"); expect(btoa("éé")).toBe("6ek="); + // check for utf16 + expect(btoa("🧐éé".substring("🧐".length))).toBe("6ek="); expect(btoa("\u0080\u0081")).toBe("gIE="); expect(btoa(Bun)).toBe(btoa("[object Bun]")); }); diff --git a/test/js/web/web-globals.test.js b/test/js/web/web-globals.test.js index b7a243190..d687a1290 100644 --- a/test/js/web/web-globals.test.js +++ b/test/js/web/web-globals.test.js @@ -138,6 +138,25 @@ it("crypto.randomUUID", () => { }); }); +it("crypto.randomUUID version, issues#3575", () => { + var uuid = crypto.randomUUID(); + + function validate(uuid) { + const regex = + /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; + return typeof uuid === "string" && regex.test(uuid); + } + function version(uuid) { + if (!validate(uuid)) { + throw TypeError("Invalid UUID"); + } + + return parseInt(uuid.slice(14, 15), 16); + } + + expect(version(uuid)).toBe(4); +}); + it("URL.prototype.origin", () => { const url = new URL("https://html.spec.whatwg.org/"); const { origin, host, hostname } = url; diff --git a/test/js/web/websocket/websocket.test.js b/test/js/web/websocket/websocket.test.js index 867b86123..76ff16ecb 100644 --- a/test/js/web/websocket/websocket.test.js +++ b/test/js/web/websocket/websocket.test.js @@ -6,16 +6,33 @@ const TEST_WEBSOCKET_HOST = process.env.TEST_WEBSOCKET_HOST || "wss://ws.postman describe("WebSocket", () => { it("should connect", async () => { - const ws = new WebSocket(TEST_WEBSOCKET_HOST); - await new Promise((resolve, reject) => { + const server = Bun.serve({ + port: 0, + fetch(req, server) { + if (server.upgrade(req)) { + server.stop(); + return; + } + + return new Response(); + }, + websocket: { + open(ws) {}, + message(ws) { + ws.close(); + }, + }, + }); + const ws = new WebSocket(`ws://${server.hostname}:${server.port}`, {}); + await new Promise(resolve => { ws.onopen = resolve; - ws.onerror = reject; }); - var closed = new Promise((resolve, reject) => { + var closed = new Promise(resolve => { ws.onclose = resolve; }); ws.close(); await closed; + server.stop(true); }); it("should connect over https", async () => { @@ -59,17 +76,18 @@ describe("WebSocket", () => { const server = Bun.serve({ port: 0, fetch(req, server) { - server.stop(); done(); + server.stop(); return new Response(); }, websocket: { - open(ws) { + open(ws) {}, + message(ws) { ws.close(); }, }, }); - const ws = new WebSocket(`http://${server.hostname}:${server.port}`, {}); + new WebSocket(`http://${server.hostname}:${server.port}`, {}); }); describe("nodebuffer", () => { it("should support 'nodebuffer' binaryType", done => { @@ -93,6 +111,7 @@ describe("WebSocket", () => { expect(ws.binaryType).toBe("nodebuffer"); Bun.gc(true); ws.onmessage = ({ data }) => { + ws.close(); expect(Buffer.isBuffer(data)).toBe(true); expect(data).toEqual(new Uint8Array([1, 2, 3])); server.stop(true); @@ -117,6 +136,7 @@ describe("WebSocket", () => { ws.sendBinary(new Uint8Array([1, 2, 3])); setTimeout(() => { client.onmessage = ({ data }) => { + client.close(); expect(Buffer.isBuffer(data)).toBe(true); expect(data).toEqual(new Uint8Array([1, 2, 3])); server.stop(true); |