Files
bun.sh/test/js/web/broadcastchannel/broadcast-channel.test.ts

225 lines
6.3 KiB
TypeScript

import util from "util";
test("postMessage results in correct event", done => {
let c1 = new BroadcastChannel("eventType");
let c2 = new BroadcastChannel("eventType");
c2.onmessage = (e: MessageEvent) => {
expect(e).toBeInstanceOf(MessageEvent);
expect(e.target).toBe(c2);
expect(e.type).toBe("message");
expect(e.origin).toBe("");
expect(e.data).toBe("hello world");
expect(e.source).toBe(null);
c1.close();
c2.close();
done();
};
c1.postMessage("hello world");
});
test("broadcast channel properties", () => {
let c1 = new BroadcastChannel("props");
expect(c1.name).toBe("props");
expect(c1.onmessage).toBe(null);
expect(c1.onmessageerror).toBe(null);
expect(c1.close).toBeInstanceOf(Function);
expect(c1.postMessage).toBeInstanceOf(Function);
expect(c1.ref).toBeInstanceOf(Function);
expect(c1.unref).toBeInstanceOf(Function);
c1.close();
});
test("broadcast channel worker wait", done => {
var worker = new Worker(new URL("broadcast-channel-worker-simple.ts", import.meta.url).href);
worker.ref();
Bun.sleepSync(500);
var bc = new BroadcastChannel("sleep");
bc.onmessage = (e: MessageEvent) => {
expect(e.data).toBe("done!");
bc.close();
worker.unref();
done();
};
bc.postMessage("rise and shine!");
});
test("messages are delivered in port creation order", done => {
let c1 = new BroadcastChannel("order");
let c2 = new BroadcastChannel("order");
let c3 = new BroadcastChannel("order");
let events: MessageEvent[] = [];
let doneCount = 0;
let handler = (e: MessageEvent) => {
events.push(e);
if (e.data == "done") {
doneCount++;
if (doneCount == 2) {
expect(events.length).toBe(6);
expect(events[0].target).toBe(c2);
expect(events[0].data).toBe("from c1");
expect(events[1].target).toBe(c3);
expect(events[1].data).toBe("from c1");
expect(events[2].target).toBe(c1);
expect(events[2].data).toBe("from c3");
expect(events[3].target).toBe(c2);
expect(events[3].data).toBe("from c3");
expect(events[4].target).toBe(c1);
expect(events[4].data).toBe("done");
expect(events[5].target).toBe(c3);
expect(events[5].data).toBe("done");
c1.close();
c2.close();
c3.close();
done();
}
}
};
c1.onmessage = handler;
c2.onmessage = handler;
c3.onmessage = handler;
c1.postMessage("from c1");
c3.postMessage("from c3");
c2.postMessage("done");
});
test("messages aren't deliverd to a closed port.", done => {
let c1 = new BroadcastChannel("closed");
let c2 = new BroadcastChannel("closed");
let c3 = new BroadcastChannel("closed");
c2.onmessage = () => {
expect().fail();
};
c2.close();
c3.onmessage = () => {
c1.close();
c3.close();
done();
};
c1.postMessage("test");
});
test("close broadcast channel and create another with the same name", done => {
let c1 = new BroadcastChannel("close-and-create");
c1.close();
let c2 = new BroadcastChannel("close-and-create");
let c3 = new BroadcastChannel("close-and-create");
c2.onmessage = (e: MessageEvent) => {
expect(e.data).toBe("done");
c2.close();
c3.close();
done();
};
c3.postMessage("done");
});
test("messages aren't delivered to a port closed after calling postMessage.", done => {
let c1 = new BroadcastChannel("closed");
let c2 = new BroadcastChannel("closed");
let c3 = new BroadcastChannel("closed");
c2.onmessage = () => expect().fail();
c3.onmessage = () => {
c1.close();
c3.close();
done();
};
c1.postMessage("test");
c2.close();
});
test("closing and creating channels during message delivery works correctly.", done => {
let c1 = new BroadcastChannel("create-in-onmessage");
let c2 = new BroadcastChannel("create-in-onmessage");
c2.onmessage = (e: MessageEvent) => {
expect(e.data).toBe("first");
c2.close();
let c3 = new BroadcastChannel("create-in-onmessage");
c3.onmessage = (event: MessageEvent) => {
expect(event.data).toBe("done");
c1.close();
c3.close();
done();
};
c1.postMessage("done");
};
c1.postMessage("first");
c2.postMessage("second");
});
test("Closing a channel in onmessage prevents already queued tasks from firing onmessage events", done => {
let c1 = new BroadcastChannel("close-in-onmessage");
let c2 = new BroadcastChannel("close-in-onmessage");
let c3 = new BroadcastChannel("close-in-onmessage");
let events: string[] = [];
c1.onmessage = (e: MessageEvent) => events.push("c1: " + e.data);
c2.onmessage = (e: MessageEvent) => events.push("c2: " + e.data);
c3.onmessage = (e: MessageEvent) => events.push("c3: " + e.data);
// c2 closes itself when it receives the first message
c2.addEventListener("message", (e: MessageEvent) => {
c2.close();
});
c3.addEventListener("message", (e: MessageEvent) => {
if (e.data == "done") {
expect(events).toEqual(["c2: first", "c3: first", "c3: done"]);
c1.close();
c3.close();
done();
}
});
c1.postMessage("first");
c1.postMessage("done");
});
test("broadcast channel used with workers", async () => {
const batchSize = 1;
for (let total = 0; total < 100; total++) {
let bc = new BroadcastChannel("hello test");
let promises: Promise<void>[] = [];
let resolveFns = [];
for (var i = 0; i < batchSize; i++) {
const { promise, resolve } = Promise.withResolvers();
promises.push(promise);
resolveFns.push(resolve);
}
bc.onmessage = (e: MessageEvent) => {
expect(e).toBeInstanceOf(MessageEvent);
expect(e.target).toBe(bc);
expect(e.data).toBe("hello from worker");
const resolve = resolveFns.shift();
if (resolve) {
resolve();
} else {
console.warn("resolve fn not found");
}
console.count("resolve fn called");
};
for (let i = 0; i < batchSize; i++) {
new Worker(new URL("./broadcast-channel-worker.ts", import.meta.url).href);
}
await Promise.all(promises);
bc.close();
console.count("Batch complete");
}
}, 99999);
test("user options are forwarded through custom inspect", () => {
const bc = new BroadcastChannel("hello");
expect(util.inspect(bc, { compact: true, breakLength: 2 })).toBe(
"BroadcastChannel { name:\n 'hello',\n active:\n true }",
);
});