import { mkdtempSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, it } from "@suaveplan/testing/runner"; import { bundleTs, extractBannedSpecifier } from "./bundle.js"; describe("bundleTs", () => { it("bundles a trivial TS entry into ESM", { timeout: 30000 }, async () => { const dir = mkdtempSync(join(tmpdir(), "bundle-trivial-")); const entry = join(dir, "src.ts"); writeFileSync( entry, "const x = 42; export const plugin = { x } as const;\n" ); const { js } = await bundleTs({ entry }); expect(js.includes("plugin")).toBe(true); expect(js.includes("42")).toBe(true); }); it("rejects a node:fs import with BROWSER_INCOMPAT_DEPENDENCY", { timeout: 30000, }, async () => { const dir = mkdtempSync(join(tmpdir(), "bundle-node-fs-")); const entry = join(dir, "src.ts"); writeFileSync( entry, "import * as fs from 'node:fs'; export const plugin = fs;\n" ); let caught: unknown; try { await bundleTs({ entry }); } catch (err) { caught = err; } expect(caught).toBeDefined(); expect((caught as { code?: string }).code).toBe( "WASM_COMPILER.BROWSER_INCOMPAT_DEPENDENCY" ); expect( (caught as { context?: { specifier?: string } }).context?.specifier ).toBe("node:fs"); }); it("passes inline-sourcemap flag through", { timeout: 30000 }, async () => { const dir = mkdtempSync(join(tmpdir(), "bundle-sm-")); const entry = join(dir, "src.ts"); writeFileSync(entry, "export const plugin = { ok: true } as const;\n"); const { js } = await bundleTs({ entry, sourcemaps: true }); expect(js.length).toBeGreaterThan(0); }); }); describe("extractBannedSpecifier", () => { it("captures node:* tokens", { timeout: 5000 }, () => { expect(extractBannedSpecifier("Could not resolve 'node:fs'")).toBe( "node:fs" ); expect( extractBannedSpecifier("error importing node:child_process here") ).toBe("node:child_process"); }); it("returns null on non-banned messages", { timeout: 5000 }, () => { expect(extractBannedSpecifier("nothing here")).toBe(null); expect( extractBannedSpecifier("node alone (no colon) should not trip") ).toBe(null); }); });