mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 02:48:50 +00:00
### What does this PR do? Allow upgrade to websockets using fetch This will avoid hanging in http.request and is a step necessary to implement the upgrade event in the node:http client. Changes in node:http need to be made in another PR to support 'upgrade' event (see https://github.com/oven-sh/bun/pull/22412) ### How did you verify your code works? Test --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { decodeFrames, encodeCloseFrame, encodeTextFrame, upgradeHeaders } from "./websocket.helpers";
|
|
|
|
describe("fetch upgrade", () => {
|
|
test("should upgrade to websocket", async () => {
|
|
const serverMessages: string[] = [];
|
|
using server = Bun.serve({
|
|
port: 0,
|
|
fetch(req) {
|
|
if (server.upgrade(req)) return;
|
|
return new Response("Hello World");
|
|
},
|
|
websocket: {
|
|
open(ws) {
|
|
ws.send("Hello World");
|
|
},
|
|
message(ws, message) {
|
|
serverMessages.push(message as string);
|
|
},
|
|
close(ws) {
|
|
serverMessages.push("close");
|
|
},
|
|
},
|
|
});
|
|
const res = await fetch(server.url, {
|
|
method: "GET",
|
|
headers: upgradeHeaders(),
|
|
async *body() {
|
|
yield encodeTextFrame("hello");
|
|
yield encodeTextFrame("world");
|
|
yield encodeTextFrame("bye");
|
|
yield encodeCloseFrame();
|
|
},
|
|
});
|
|
expect(res.status).toBe(101);
|
|
expect(res.headers.get("upgrade")).toBe("websocket");
|
|
expect(res.headers.get("sec-websocket-accept")).toBeString();
|
|
expect(res.headers.get("connection")).toBe("Upgrade");
|
|
|
|
const clientMessages: string[] = [];
|
|
const { promise, resolve } = Promise.withResolvers<void>();
|
|
const reader = res.body!.getReader();
|
|
|
|
while (true) {
|
|
const { value, done } = await reader.read();
|
|
if (done) break;
|
|
for (const msg of decodeFrames(Buffer.from(value))) {
|
|
if (typeof msg === "string") {
|
|
clientMessages.push(msg);
|
|
} else {
|
|
clientMessages.push(msg.type);
|
|
}
|
|
|
|
if (msg.type === "close") {
|
|
resolve();
|
|
}
|
|
}
|
|
}
|
|
await promise;
|
|
expect(serverMessages).toEqual(["hello", "world", "bye", "close"]);
|
|
expect(clientMessages).toEqual(["Hello World", "close"]);
|
|
});
|
|
});
|