aboutsummaryrefslogtreecommitdiff
path: root/packages/bun-inspector-protocol/test
diff options
context:
space:
mode:
Diffstat (limited to 'packages/bun-inspector-protocol/test')
-rw-r--r--packages/bun-inspector-protocol/test/inspector/websocket.test.ts190
-rw-r--r--packages/bun-inspector-protocol/test/util/__snapshots__/preview.test.ts.snap143
-rw-r--r--packages/bun-inspector-protocol/test/util/preview.js99
-rw-r--r--packages/bun-inspector-protocol/test/util/preview.test.ts61
4 files changed, 190 insertions, 303 deletions
diff --git a/packages/bun-inspector-protocol/test/inspector/websocket.test.ts b/packages/bun-inspector-protocol/test/inspector/websocket.test.ts
new file mode 100644
index 000000000..4a6c60c28
--- /dev/null
+++ b/packages/bun-inspector-protocol/test/inspector/websocket.test.ts
@@ -0,0 +1,190 @@
+import { describe, test, expect, mock, beforeAll, afterAll } from "bun:test";
+import { WebSocketInspector } from "../../src/inspector/websocket";
+import type { Server } from "bun";
+import { serve } from "bun";
+
+let server: Server;
+let url: URL;
+
+describe("WebSocketInspector", () => {
+ test("fails without a URL", () => {
+ const ws = new WebSocketInspector();
+ const fn = mock(error => {
+ expect(error).toBeInstanceOf(Error);
+ });
+ ws.on("Inspector.error", fn);
+ expect(ws.start()).resolves.toBeFalse();
+ expect(fn).toHaveBeenCalled();
+ });
+
+ test("fails with invalid URL", () => {
+ const ws = new WebSocketInspector("notaurl");
+ const fn = mock(error => {
+ expect(error).toBeInstanceOf(Error);
+ });
+ ws.on("Inspector.error", fn);
+ expect(ws.start()).resolves.toBeFalse();
+ expect(fn).toHaveBeenCalled();
+ });
+
+ test("fails with valid URL but no server", () => {
+ const ws = new WebSocketInspector("ws://localhost:0/doesnotexist/");
+ const fn = mock(error => {
+ expect(error).toBeInstanceOf(Error);
+ });
+ ws.on("Inspector.error", fn);
+ expect(ws.start()).resolves.toBeFalse();
+ expect(fn).toHaveBeenCalled();
+ });
+
+ test("fails with invalid upgrade response", () => {
+ const ws = new WebSocketInspector(new URL("/", url));
+ const fn = mock(error => {
+ expect(error).toBeInstanceOf(Error);
+ });
+ ws.on("Inspector.error", fn);
+ expect(ws.start()).resolves.toBeFalse();
+ expect(fn).toHaveBeenCalled();
+ });
+
+ test("can connect to a server", () => {
+ const ws = new WebSocketInspector(url);
+ const fn = mock(() => {
+ expect(ws.closed).toBe(false);
+ });
+ ws.on("Inspector.connected", fn);
+ expect(ws.start()).resolves.toBeTrue();
+ expect(fn).toHaveBeenCalled();
+ ws.close();
+ });
+
+ test("can disconnect from a server", () => {
+ const ws = new WebSocketInspector(url);
+ const fn = mock(() => {
+ expect(ws.closed).toBeTrue();
+ });
+ ws.on("Inspector.disconnected", fn);
+ expect(ws.start()).resolves.toBeTrue();
+ ws.close();
+ expect(fn).toHaveBeenCalled();
+ });
+
+ test("can connect to a server multiple times", () => {
+ const ws = new WebSocketInspector(url);
+ const fn0 = mock(() => {
+ expect(ws.closed).toBeFalse();
+ });
+ ws.on("Inspector.connected", fn0);
+ const fn1 = mock(() => {
+ expect(ws.closed).toBeTrue();
+ });
+ ws.on("Inspector.disconnected", fn1);
+ for (let i = 0; i < 3; i++) {
+ expect(ws.start()).resolves.toBeTrue();
+ ws.close();
+ }
+ expect(fn0).toHaveBeenCalledTimes(3);
+ expect(fn1).toHaveBeenCalledTimes(3);
+ });
+
+ test("can send a request", () => {
+ const ws = new WebSocketInspector(url);
+ const fn0 = mock(request => {
+ expect(request).toStrictEqual({
+ id: 1,
+ method: "Debugger.setPauseOnAssertions",
+ params: {
+ enabled: true,
+ },
+ });
+ });
+ ws.on("Inspector.request", fn0);
+ const fn1 = mock(response => {
+ expect(response).toStrictEqual({
+ id: 1,
+ result: {
+ ok: true,
+ },
+ });
+ });
+ ws.on("Inspector.response", fn1);
+ expect(ws.start()).resolves.toBeTrue();
+ expect(ws.send("Debugger.setPauseOnAssertions", { enabled: true })).resolves.toMatchObject({ ok: true });
+ expect(fn0).toHaveBeenCalled();
+ expect(fn1).toHaveBeenCalled();
+ ws.close();
+ });
+
+ test("can send a request before connecting", () => {
+ const ws = new WebSocketInspector(url);
+ const fn0 = mock(request => {
+ expect(request).toStrictEqual({
+ id: 1,
+ method: "Runtime.enable",
+ params: {},
+ });
+ });
+ ws.on("Inspector.pendingRequest", fn0);
+ ws.on("Inspector.request", fn0);
+ const fn1 = mock(response => {
+ expect(response).toStrictEqual({
+ id: 1,
+ result: {
+ ok: true,
+ },
+ });
+ });
+ ws.on("Inspector.response", fn1);
+ const request = ws.send("Runtime.enable");
+ expect(ws.start()).resolves.toBe(true);
+ expect(request).resolves.toMatchObject({ ok: true });
+ expect(fn0).toHaveBeenCalledTimes(2);
+ expect(fn1).toHaveBeenCalled();
+ ws.close();
+ });
+
+ test("can receive an event", () => {
+ const ws = new WebSocketInspector(url);
+ const fn = mock(event => {
+ expect(event).toStrictEqual({
+ method: "Debugger.scriptParsed",
+ params: {
+ scriptId: "1",
+ },
+ });
+ });
+ ws.on("Inspector.event", fn);
+ expect(ws.start()).resolves.toBeTrue();
+ expect(ws.send("Debugger.enable")).resolves.toMatchObject({ ok: true });
+ expect(fn).toHaveBeenCalled();
+ ws.close();
+ });
+});
+
+beforeAll(() => {
+ server = serve({
+ port: 0,
+ fetch(request, server) {
+ if (request.url.endsWith("/ws") && server.upgrade(request)) {
+ return;
+ }
+ return new Response();
+ },
+ websocket: {
+ message(ws, message) {
+ const { id, method } = JSON.parse(String(message));
+ ws.send(JSON.stringify({ id, result: { ok: true } }));
+
+ if (method === "Debugger.enable") {
+ ws.send(JSON.stringify({ method: "Debugger.scriptParsed", params: { scriptId: "1" } }));
+ }
+ },
+ },
+ });
+ const { hostname, port } = server;
+ url = new URL(`ws://${hostname}:${port}/ws`);
+});
+
+afterAll(() => {
+ server?.stop(true);
+});
diff --git a/packages/bun-inspector-protocol/test/util/__snapshots__/preview.test.ts.snap b/packages/bun-inspector-protocol/test/util/__snapshots__/preview.test.ts.snap
deleted file mode 100644
index 0acc17575..000000000
--- a/packages/bun-inspector-protocol/test/util/__snapshots__/preview.test.ts.snap
+++ /dev/null
@@ -1,143 +0,0 @@
-// Bun Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`remoteObjectToString 1`] = `"undefined"`;
-
-exports[`remoteObjectToString 2`] = `"null"`;
-
-exports[`remoteObjectToString 3`] = `"true"`;
-
-exports[`remoteObjectToString 4`] = `"false"`;
-
-exports[`remoteObjectToString 5`] = `"0"`;
-
-exports[`remoteObjectToString 6`] = `"1"`;
-
-exports[`remoteObjectToString 7`] = `"3.141592653589793"`;
-
-exports[`remoteObjectToString 8`] = `"-2.718281828459045"`;
-
-exports[`remoteObjectToString 9`] = `"NaN"`;
-
-exports[`remoteObjectToString 10`] = `"Infinity"`;
-
-exports[`remoteObjectToString 11`] = `"-Infinity"`;
-
-exports[`remoteObjectToString 12`] = `"0n"`;
-
-exports[`remoteObjectToString 13`] = `"1n"`;
-
-exports[`remoteObjectToString 14`] = `"10000000000000n"`;
-
-exports[`remoteObjectToString 15`] = `"-10000000000000n"`;
-
-exports[`remoteObjectToString 16`] = `""""`;
-
-exports[`remoteObjectToString 17`] = `"" ""`;
-
-exports[`remoteObjectToString 18`] = `""Hello""`;
-
-exports[`remoteObjectToString 19`] = `""Hello World""`;
-
-exports[`remoteObjectToString 20`] = `"Array(0)"`;
-
-exports[`remoteObjectToString 21`] = `"Array(3) [1, 2, 3]"`;
-
-exports[`remoteObjectToString 22`] = `"Array(4) ["a", 1, null, undefined]"`;
-
-exports[`remoteObjectToString 23`] = `"Array(2) [1, Array]"`;
-
-exports[`remoteObjectToString 24`] = `"Array(1) [Array]"`;
-
-exports[`remoteObjectToString 25`] = `"{}"`;
-
-exports[`remoteObjectToString 26`] = `"{a: 1}"`;
-
-exports[`remoteObjectToString 27`] = `"{a: 1, b: 2, c: 3}"`;
-
-exports[`remoteObjectToString 28`] = `"{a: Object}"`;
-
-exports[`remoteObjectToString 29`] = `
-"ƒ() {
-}"
-`;
-
-exports[`remoteObjectToString 30`] = `
-"ƒ namedFunction() {
-}"
-`;
-
-exports[`remoteObjectToString 31`] = `
-"class {
-}"
-`;
-
-exports[`remoteObjectToString 32`] = `
-"class namedClass {
-}"
-`;
-
-exports[`remoteObjectToString 33`] = `
-"class namedClass {
- a() {
- }
- b = 1;
- c = [
- null,
- undefined,
- "a",
- {
- a: 1,
- b: 2,
- c: 3
- }
- ];
-}"
-`;
-
-exports[`remoteObjectToString 34`] = `"Wed Dec 31 1969 16:00:00 GMT-0800 (Pacific Standard Time)"`;
-
-exports[`remoteObjectToString 35`] = `"Invalid Date"`;
-
-exports[`remoteObjectToString 36`] = `"/(?:)/"`;
-
-exports[`remoteObjectToString 37`] = `"/abc/"`;
-
-exports[`remoteObjectToString 38`] = `"/abc/g"`;
-
-exports[`remoteObjectToString 39`] = `"/abc/"`;
-
-exports[`remoteObjectToString 40`] = `"Set(0)"`;
-
-exports[`remoteObjectToString 41`] = `"Set(3) [1, 2, 3]"`;
-
-exports[`remoteObjectToString 42`] = `"WeakSet(0)"`;
-
-exports[`remoteObjectToString 43`] = `"WeakSet(3) [{a: 1}, {b: 2}, {c: 3}]"`;
-
-exports[`remoteObjectToString 44`] = `"Map(0)"`;
-
-exports[`remoteObjectToString 45`] = `"Map(3) {"a" => 1, "b" => 2, "c" => 3}"`;
-
-exports[`remoteObjectToString 46`] = `"WeakMap(0)"`;
-
-exports[`remoteObjectToString 47`] = `"WeakMap(3) {{a: 1} => 1, {b: 2} => 2, {c: 3} => 3}"`;
-
-exports[`remoteObjectToString 48`] = `"Symbol()"`;
-
-exports[`remoteObjectToString 49`] = `"Symbol(namedSymbol)"`;
-
-exports[`remoteObjectToString 50`] = `"Error"`;
-
-exports[`remoteObjectToString 51`] = `"TypeError: This is a TypeError"`;
-
-exports[`remoteObjectToString 52`] = `"Headers {append: ƒ, delete: ƒ, get: ƒ, getAll: ƒ, has: ƒ, …}"`;
-
-exports[`remoteObjectToString 53`] = `"Headers {a: "1", append: ƒ, b: "2", delete: ƒ, get: ƒ, …}"`;
-
-exports[`remoteObjectToString 54`] = `"Request {arrayBuffer: ƒ, blob: ƒ, body: null, bodyUsed: false, cache: "default", …}"`;
-
-exports[`remoteObjectToString 55`] = `"Request {arrayBuffer: ƒ, blob: ƒ, body: ReadableStream, bodyUsed: false, cache: "default", …}"`;
-
-exports[`remoteObjectToString 56`] = `"Response {arrayBuffer: ƒ, blob: ƒ, body: null, bodyUsed: false, clone: ƒ, …}"`;
-
-exports[`remoteObjectToString 57`] = `"Response {arrayBuffer: ƒ, blob: ƒ, body: ReadableStream, bodyUsed: false, clone: ƒ, …}"`;
diff --git a/packages/bun-inspector-protocol/test/util/preview.js b/packages/bun-inspector-protocol/test/util/preview.js
deleted file mode 100644
index 15062240b..000000000
--- a/packages/bun-inspector-protocol/test/util/preview.js
+++ /dev/null
@@ -1,99 +0,0 @@
-console.log(
- undefined,
- null,
- true,
- false,
- 0,
- 1,
- Math.PI,
- -Math.E,
- NaN,
- Infinity,
- -Infinity,
- BigInt(0),
- BigInt(1),
- BigInt("10000000000000"),
- BigInt("-10000000000000"),
- "",
- " ",
- "Hello",
- "Hello World",
- [],
- [1, 2, 3],
- ["a", 1, null, undefined],
- [1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]],
- [[[[[]]]]],
- {},
- { a: 1 },
- { a: 1, b: 2, c: 3 },
- { a: { b: { c: { d: { e: { f: { g: { h: { i: { j: 10 } } } } } } } } } },
- function () {},
- function namedFunction() {},
- class {},
- class namedClass {},
- class namedClass {
- a() {}
- b = 1;
- c = [
- null,
- undefined,
- "a",
- {
- a: 1,
- b: 2,
- c: 3,
- },
- ];
- },
- new Date(0),
- new Date(NaN),
- new RegExp(),
- new RegExp("abc"),
- new RegExp("abc", "g"),
- /abc/,
- new Set(),
- new Set([1, 2, 3]),
- new WeakSet(),
- new WeakSet([{ a: 1 }, { b: 2 }, { c: 3 }]),
- new Map(),
- new Map([
- ["a", 1],
- ["b", 2],
- ["c", 3],
- ]),
- new WeakMap(),
- new WeakMap([
- [{ a: 1 }, 1],
- [{ b: 2 }, 2],
- [{ c: 3 }, 3],
- ]),
- Symbol(),
- Symbol("namedSymbol"),
- new Error(),
- new TypeError("This is a TypeError"),
- //"a".repeat(10000),
- //["a"].fill("a", 0, 10000),
- new Headers(),
- new Headers({
- a: "1",
- b: "2",
- }),
- new Request("https://example.com/"),
- new Request("https://example.com/", {
- method: "POST",
- headers: {
- a: "1",
- b: "2",
- },
- body: '{"example":true}',
- }),
- new Response(),
- new Response('{"example":true}', {
- status: 200,
- statusText: "OK",
- headers: {
- a: "1",
- b: "2",
- },
- }),
-);
diff --git a/packages/bun-inspector-protocol/test/util/preview.test.ts b/packages/bun-inspector-protocol/test/util/preview.test.ts
deleted file mode 100644
index 99214ef0e..000000000
--- a/packages/bun-inspector-protocol/test/util/preview.test.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { beforeAll, afterAll, test, expect } from "bun:test";
-import type { PipedSubprocess } from "bun";
-import { spawn } from "bun";
-import type { JSC } from "../..";
-import { WebSocketInspector, remoteObjectToString } from "../..";
-
-let subprocess: PipedSubprocess | undefined;
-let objects: JSC.Runtime.RemoteObject[] = [];
-
-beforeAll(async () => {
- subprocess = spawn({
- cwd: import.meta.dir,
- cmd: [process.argv0, "--inspect-wait=0", "preview.js"],
- stdout: "pipe",
- stderr: "pipe",
- stdin: "pipe",
- });
- const decoder = new TextDecoder();
- let url: URL;
- for await (const chunk of subprocess!.stdout) {
- const text = decoder.decode(chunk);
- if (text.includes("ws://")) {
- url = new URL(/(ws:\/\/.*)/.exec(text)![0]);
- break;
- }
- }
- objects = await new Promise((resolve, reject) => {
- const inspector = new WebSocketInspector({
- url,
- listener: {
- ["Inspector.connected"]: () => {
- inspector.send("Inspector.enable");
- inspector.send("Runtime.enable");
- inspector.send("Console.enable");
- inspector.send("Debugger.enable");
- inspector.send("Debugger.resume");
- inspector.send("Inspector.initialized");
- },
- ["Inspector.disconnected"]: error => {
- reject(error);
- },
- ["Console.messageAdded"]: ({ message }) => {
- const { parameters } = message;
- resolve(parameters!);
- inspector.close();
- },
- },
- });
- inspector.start();
- });
-});
-
-afterAll(() => {
- subprocess?.kill();
-});
-
-test("remoteObjectToString", () => {
- for (const object of objects) {
- expect(remoteObjectToString(object)).toMatchSnapshot();
- }
-});