Files
bun-src/test/cli/inspect/inspect-inline-sourcemap.test.ts
2026-08-27 21:09:14 +00:00

93 lines
3.2 KiB
TypeScript

import { spawn } from "bun";
import { expect, test } from "bun:test";
import fs from "fs";
import { bunEnv, bunExe, tempDir } from "harness";
import { join } from "node:path";
import { WebSocket } from "ws";
test("--inspect inline sourcemap sources[0] is a valid path under cwd", async () => {
// VT (0x0B) / BEL (0x07) in the source exercise quote_for_json's RFC 8259
// escape handling for sourcesContent.
const source = "// comment [\x0b\x07]\nsetInterval(() => {}, 200);\n";
using dir = tempDir("inspect-sourcemap", {
"sub/target.mjs": source,
});
const cwd = fs.realpathSync(String(dir));
await using proc = spawn({
cmd: [bunExe(), "--inspect-wait=127.0.0.1:0", join("sub", "target.mjs")],
env: bunEnv,
cwd,
stdout: "ignore",
stderr: "pipe",
});
let url: URL | undefined;
let stderr = "";
const decoder = new TextDecoder();
for await (const chunk of proc.stderr as ReadableStream) {
stderr += decoder.decode(chunk);
for (const line of stderr.split("\n")) {
try {
url = new URL(line);
} catch {}
if (url?.protocol.includes("ws")) break;
}
if (stderr.includes("Listening:")) break;
}
if (!url) {
process.stderr.write(stderr);
throw new Error("Unable to find listening URL");
}
const ws = new WebSocket(url);
try {
const failed = new Promise<never>((_, reject) => {
ws.addEventListener("error", cause => reject(new Error("WebSocket error", { cause })));
ws.addEventListener("close", cause => reject(new Error("WebSocket closed", { cause })));
proc.exited.then(code => reject(new Error(`inspectee exited (${code})`)));
});
failed.catch(() => {});
await Promise.race([new Promise<void>(resolve => ws.addEventListener("open", () => resolve())), failed]);
const pending = new Map<number, (v: any) => void>();
const scriptParsed = new Promise<any>(resolve => {
ws.addEventListener("message", ({ data }) => {
const msg = JSON.parse(data.toString());
if (typeof msg.id === "number" && pending.has(msg.id)) {
pending.get(msg.id)!(msg);
pending.delete(msg.id);
} else if (msg.method === "Debugger.scriptParsed" && String(msg.params?.url ?? "").endsWith("target.mjs")) {
resolve(msg.params);
}
});
});
let nextId = 0;
const send = (method: string, params: Record<string, unknown> = {}) =>
Promise.race([
new Promise<any>(resolve => {
const id = ++nextId;
pending.set(id, resolve);
ws.send(JSON.stringify({ id, method, params }));
}),
failed,
]);
await Promise.all([send("Inspector.enable"), send("Debugger.enable")]);
send("Inspector.initialized").catch(() => {});
const params = await Promise.race([scriptParsed, failed]);
const m = String(params.sourceMapURL ?? "").match(/base64,([A-Za-z0-9+/=]+)/);
expect(m).not.toBeNull();
const raw = Buffer.from(m![1], "base64").toString();
expect(raw).not.toMatch(/\\v|\\x[0-9A-Fa-f]{2}/);
const map = JSON.parse(raw);
expect(map.sources[0]).toBe("/sub/target.mjs");
expect(map.sourcesContent[0]).toBe(source);
} finally {
ws.close();
}
});