/** * Tests for the pure builders and guards behind the shared edge-bundle * pipeline (`scripts/edge-bundle-modules.ts`). These produce the source text * esbuild inlines in place of the dev/test modules that read from disk, and the * post-build assertions on the finished bundle. The IO shell that drives * esbuild (`edge-bundle-lib.ts`) is exercised by `deno task build:edge`; the * branch-carrying logic lives here and is unit-tested directly. */ import { assert, assertStringIncludes } from "@std/assert"; import { expect } from "@std/expect"; import { describe, it as test } from "@std/testing/bdd"; import { type AssetDef, buildAssetPathsModule, buildAssetsModule, buildBuildInfoModule, bundleSizeGuard, nativeLibsqlGuard, reactRuntimeGuard, renameSourceMapLink, SENTRY_BUILD_DEFINES, sentryTreeShakingGuard, } from "#scripts/edge-bundle-modules.ts"; import { expectIncludesAll } from "#test-utils/assertions.ts"; describe("buildBuildInfoModule", () => { test("emits both constants with the given timestamp and commit", () => { expect(buildBuildInfoModule("2026-07-04T00:00:00.000Z", "abc123")).toBe( [ `export const BUILD_TIMESTAMP = "2026-07-04T00:00:00.000Z";`, `export const BUILD_COMMIT = "abc123";`, ].join("\n"), ); }); test("JSON-encodes an empty commit rather than emitting a bare token", () => { assertStringIncludes( buildBuildInfoModule("2026-01-01T00:00:00.000Z", ""), `export const BUILD_COMMIT = "";`, ); }); test("escapes values through JSON.stringify", () => { // A quote in the value must be escaped, not emitted raw, or the module // would be syntactically broken. assertStringIncludes( buildBuildInfoModule("2026", 'a"b'), `export const BUILD_COMMIT = "a\\"b";`, ); }); }); const PATH_DEFS: AssetDef[] = [ ["favicon.svg", "handleFavicon", "image/svg+xml", ""], ["style.css", "handleStyleCss", "text/css", "CSS_PATH"], ["embed.js", "handleEmbedJs", "application/javascript", "EMBED_JS_PATH"], ]; describe("buildAssetPathsModule", () => { test("emits a const only for defs that carry a path constant", () => { const out = buildAssetPathsModule(PATH_DEFS, 1234); // favicon.svg has no path constant, so it is filtered out entirely. assert(!out.includes("favicon")); expectIncludesAll(out, ["CSS_PATH", "EMBED_JS_PATH"]); }); test("cache-busts normal assets with the build timestamp", () => { assertStringIncludes( buildAssetPathsModule(PATH_DEFS, 1234), `export const CSS_PATH = "/style.css?ts=1234";`, ); }); test("never cache-busts the embed script (must always serve latest)", () => { assertStringIncludes( buildAssetPathsModule(PATH_DEFS, 1234), `export const EMBED_JS_PATH = "/embed.js";`, ); }); test("produces exactly the path consts, newline-joined", () => { expect(buildAssetPathsModule(PATH_DEFS, 1234)).toBe( [ `export const CSS_PATH = "/style.css?ts=1234";`, `export const EMBED_JS_PATH = "/embed.js";`, "export const ASSET_CDN_ORIGIN = null;", ].join("\n"), ); }); test("bakes published CDN URLs and origin into the bundle", () => { const paths = buildAssetPathsModule(PATH_DEFS, 1234, { origin: "https://assets.example.com", urls: { "style.css": "https://assets.example.com/assets/release/style.css", }, }); expectIncludesAll(paths, [ `export const CSS_PATH = "https://assets.example.com/assets/release/style.css";`, `export const EMBED_JS_PATH = "/embed.js";`, `export const ASSET_CDN_ORIGIN = "https://assets.example.com";`, ]); }); }); const ASSET_DEFS: AssetDef[] = [ ["favicon.svg", "handleFavicon", "image/svg+xml", ""], ["admin.js", "handleAdminJs", "application/javascript", "JS_PATH"], ]; const STATIC_ASSETS = { "admin.js": "console.log(1)", "favicon.svg": "", "order.js": "widget-source", }; const CDN_ASSETS = { origin: "https://assets.example.com", urls: { "admin.js": "https://assets.example.com/assets/release/admin.js", }, }; /** Import one generated module, typed by the caller's claim about its * exports: the data import itself carries no types. */ const importAssetsModule = >( source: string, ): Promise => import( `data:text/javascript;charset=utf-8,${encodeURIComponent(source)}#${crypto.randomUUID()}` ) as Promise; describe("buildAssetsModule", () => { test("declares a variable per def carrying the pre-read content", () => { const out = buildAssetsModule(ASSET_DEFS, STATIC_ASSETS); expectIncludesAll(out, [ `const v0 = "";`, `const v1 = "console.log(1)";`, ]); }); test("emits a handler wiring each export name to its content-type and var", () => { const out = buildAssetsModule(ASSET_DEFS, STATIC_ASSETS); expectIncludesAll(out, [ `export const handleFavicon = () => new Response(v0, { headers: { "content-type": "image/svg+xml", ...CACHE_HEADERS } });`, `export const handleAdminJs = () => new Response(v1, { headers: { "content-type": "application/javascript", ...CACHE_HEADERS } });`, ]); }); test("declares the immutable cache header once", () => { assertStringIncludes( buildAssetsModule(ASSET_DEFS, STATIC_ASSETS), `const CACHE_HEADERS = { "cache-control": "public, max-age=31536000, immutable" };`, ); }); test("wires a fresh-revalidation asset to FRESH_HEADERS and serves it", async () => { const out = buildAssetsModule( [ [ "scanner-sw.js", "handleScannerSwJs", "application/javascript", "", false, true, ], ], { "scanner-sw.js": "worker-source" }, ); assertStringIncludes( out, `export const handleScannerSwJs = () => new Response(v0, { headers: { "content-type": "application/javascript", ...FRESH_HEADERS } });`, ); const generated = await importAssetsModule<{ handleScannerSwJs: () => Response; }>(out); expect(generated.handleScannerSwJs().headers.get("cache-control")).toBe( "no-cache", ); }); test("mirrors assets.ts's orderWidgetBody from the inlined order.js", () => { const out = buildAssetsModule(ASSET_DEFS, STATIC_ASSETS); expectIncludesAll(out, [ `const orderJsBody = "widget-source";`, "export const orderWidgetBody = () => orderJsBody;", ]); }); test("redirects published assets without embedding their bodies", () => { const out = buildAssetsModule(ASSET_DEFS, STATIC_ASSETS, CDN_ASSETS); assert(!out.includes("console.log(1)")); expectIncludesAll(out, [ `export const handleAdminJs = () => new Response(null, { status: 302, headers: { location: "https://assets.example.com/assets/release/admin.js" } });`, `const v0 = "";`, ]); }); test("returns a CDN redirect whose security headers remain mutable", async () => { const generated = await importAssetsModule<{ handleAdminJs: () => Response; }>(buildAssetsModule(ASSET_DEFS, STATIC_ASSETS, CDN_ASSETS)); const response = generated.handleAdminJs(); response.headers.set("x-content-type-options", "nosniff"); expect(response.status).toBe(302); expect(response.headers.get("location")).toBe( "https://assets.example.com/assets/release/admin.js", ); expect(response.headers.get("x-content-type-options")).toBe("nosniff"); }); test("produces exactly the vars, cache header, handlers, and widget, newline-joined", () => { expect(buildAssetsModule(ASSET_DEFS, STATIC_ASSETS)).toBe( [ `const v0 = "";`, `const v1 = "console.log(1)";`, `const CACHE_HEADERS = { "cache-control": "public, max-age=31536000, immutable" };`, `const FRESH_HEADERS = { "cache-control": "no-cache" };`, `export const handleFavicon = () => new Response(v0, { headers: { "content-type": "image/svg+xml", ...CACHE_HEADERS } });`, `export const handleAdminJs = () => new Response(v1, { headers: { "content-type": "application/javascript", ...CACHE_HEADERS } });`, `const orderJsBody = "widget-source";`, "export const orderWidgetBody = () => orderJsBody;", ].join("\n"), ); }); }); describe("renameSourceMapLink", () => { test("re-points the sourceMappingURL comment at the new filename", () => { expect( renameSourceMapLink( "code;\n//# sourceMappingURL=edge.js.map", "edge.js.map", "bunny-script.ts.map", ), ).toBe("code;\n//# sourceMappingURL=bunny-script.ts.map"); }); test("leaves content untouched when the link is absent", () => { expect(renameSourceMapLink("no map here", "edge.js.map", "x.map")).toBe( "no map here", ); }); }); describe("reactRuntimeGuard", () => { test("trips when the bundle references React.createElement", () => { expect( reactRuntimeGuard("Edge").test("var x = React.createElement()"), ).toBe(true); }); test("passes a bundle using the automatic JSX runtime", () => { expect(reactRuntimeGuard("Edge").test("import { jsx } from '#jsx'")).toBe( false, ); }); test("labels the message with the given build name", () => { assertStringIncludes(reactRuntimeGuard("Deploy").message, "Deploy bundle"); }); }); describe("Sentry tree shaking", () => { test("compiles out debug and tracing code", () => { expect(SENTRY_BUILD_DEFINES).toEqual({ __SENTRY_DEBUG__: "false", __SENTRY_TRACING__: "false", }); }); test("rejects a bundle that retains a Sentry compile-time flag", () => { expect(sentryTreeShakingGuard.test("if (__SENTRY_DEBUG__) log()")).toBe( true, ); }); test("accepts a bundle with Sentry's optional paths compiled away", () => { expect(sentryTreeShakingGuard.test("captureException(error)")).toBe(false); }); test("explains which Sentry paths remain", () => { expect(sentryTreeShakingGuard.message).toBe( "Bundle retains a Sentry compile-time flag — expected debug and tracing code to be tree-shaken", ); }); }); describe("bundleSizeGuard", () => { test("trips when the bundle exceeds the limit", () => { expect(bundleSizeGuard(3).test("abcd")).toBe(true); }); test("passes a bundle exactly at the limit", () => { // Boundary: `> max`, so an exactly-max bundle is allowed. expect(bundleSizeGuard(4).test("abcd")).toBe(false); }); test("names the byte limit in its message", () => { assertStringIncludes(bundleSizeGuard(10_000_000).message, "10000000"); }); }); describe("nativeLibsqlGuard", () => { test('trips on a native ".node" binding reference', () => { expect(nativeLibsqlGuard.test('require("foo.node")')).toBe(true); }); test("trips on a native libsql client path reference", () => { expect(nativeLibsqlGuard.test("libsql/client/.")).toBe(true); }); test("passes the pure-JS web client bundle", () => { expect(nativeLibsqlGuard.test("libsql/client/web")).toBe(false); }); test("explains the native-binding failure in its message", () => { expect(nativeLibsqlGuard.message).toBe( "Deploy bundle references a native libsql binding — expected the pure-JS web client via platform: 'browser'", ); }); });