import { DataViewReader } from "bake/data-view"; import { decodeSerializedError } from "bake/error-serialization.ts"; import { Subprocess, spawn } from "bun"; import { afterAll, beforeAll, describe, expect, test } from "bun:test"; import fs from "fs"; import { bunExe, bunEnv as env, isPosix, tmpdirSync } from "harness"; import path, { join } from "node:path"; import { InspectorSession, connect } from "./junit-reporter"; import { SocketFramer } from "./socket-framer"; const bunEnv = { ...env, NODE_ENV: "development" }; class BunFrontendDevServerSession extends InspectorSession { constructor() { super(); } async enable(): Promise { this.send("Inspector.enable"); this.send("Console.enable"); this.send("Runtime.enable"); this.send("BunFrontendDevServer.enable"); this.send("LifecycleReporter.enable"); await this.sendAndWait("Inspector.initialized"); } async disable(): Promise { await this.sendAndWait("BunFrontendDevServer.disable"); } // Helper to send a message and wait for its response async sendAndWait(method: string, params: any = {}): Promise { if (!this.framer) throw new Error("Socket not connected"); const id = this.nextId++; const message = { id, method, params }; const responsePromise = new Promise(resolve => { this.messageCallbacks.set(id, resolve); }); this.framer.send(this.socket as any, JSON.stringify(message)); const response = await responsePromise; if (response.error) { throw new Error(`Inspector error: ${response.error.message || JSON.stringify(response.error)}`); } return response; } unref() { this.socket?.unref(); } ref() { this.socket?.ref(); } // Waits for a specific event to be fired waitForEvent(eventName: string, timeout = 5000): Promise { this.ref(); return new Promise((resolve, reject) => { const timer = setTimeout(() => { reject(new Error(`Timeout waiting for event: ${eventName}`)); }, timeout); const listener = (params: any) => { clearTimeout(timer); resolve(params); }; this.addEventListener(eventName, listener); }); } } describe.if(isPosix)("BunFrontendDevServer inspector protocol", () => { let devServerProcess: Subprocess; let serverUrl: URL; let session: BunFrontendDevServerSession; let tempdir: string; let socketPath: string; beforeAll(async () => { tempdir = tmpdirSync("bun-frontend-dev-server-test"); // Create a simple app for testing without dependencies fs.writeFileSync( join(tempdir, "index.html"), ` Dev Server Test
`, ); fs.writeFileSync( join(tempdir, "styles.css"), ` body { background-color: #f0f0f0; color: #333; font-family: sans-serif; } `, ); fs.writeFileSync( join(tempdir, "utils.ts"), ` // Utility module to test dependencies export function greet(name: string) { return \`Hello, \${name}!\`; } `, ); fs.writeFileSync( join(tempdir, "main.ts"), ` import { greet } from './utils'; // No dependencies needed document.addEventListener('DOMContentLoaded', () => { const app = document.getElementById('app'); if (app) { app.innerHTML = \`

\${greet('Dev Server')}

This is a test page for the bundler

\`; } }); `, ); // Create a second page to navigate to fs.writeFileSync( join(tempdir, "second.html"), ` Second Page