aboutsummaryrefslogtreecommitdiff
path: root/test/js/web
diff options
context:
space:
mode:
Diffstat (limited to 'test/js/web')
-rw-r--r--test/js/web/console/console-log.expected.txt8
-rw-r--r--test/js/web/console/console-log.js6
-rw-r--r--test/js/web/fetch/fetch-leak-test-fixture.js2
-rw-r--r--test/js/web/fetch/fetch.test.ts23
-rw-r--r--test/js/web/html/FormData.test.ts19
-rw-r--r--test/js/web/html/URLSearchParams.test.ts5
-rw-r--r--test/js/web/timers/process-setImmediate-fixture.js9
-rw-r--r--test/js/web/timers/setImmediate.test.js27
-rw-r--r--test/js/web/timers/setTimeout-unref-fixture-2.js9
-rw-r--r--test/js/web/timers/setTimeout-unref-fixture-3.js7
-rw-r--r--test/js/web/timers/setTimeout-unref-fixture-4.js5
-rw-r--r--test/js/web/timers/setTimeout-unref-fixture-5.js5
-rw-r--r--test/js/web/timers/setTimeout-unref-fixture.js12
-rw-r--r--test/js/web/timers/setTimeout.test.js51
-rw-r--r--test/js/web/util/atob.test.js9
-rw-r--r--test/js/web/web-globals.test.js19
-rw-r--r--test/js/web/websocket/websocket.test.js34
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);