From fce146899eb584a37251e72b1ef436524ca2a4be Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 08:52:30 +0000 Subject: [PATCH 01/12] perf(tests): add virtual mode to itBundled for in-memory builds Add `virtual: true` option to itBundled that uses Bun.build's `files` API to run bundler tests entirely in memory without disk I/O: - Uses virtual files passed directly to Bun.build - Does not set outdir/outfile so outputs stay in memory - Reads output directly from BuildArtifact.text() - Same onAfterBundle API (api.expectFile(), etc.) Updated CSS WPT tests to use virtual mode: - color-computed-rgb.test.ts (94 tests) - color-computed.test.ts (14 tests) - background-computed.test.ts (25 tests) - relative_color_out_of_gamut.test.ts (27 tests) Co-Authored-By: Claude Opus 4.5 --- .../css/wpt/background-computed.test.ts | 5 +- .../css/wpt/color-computed-rgb.test.ts | 5 +- test/bundler/css/wpt/color-computed.test.ts | 5 +- .../wpt/relative_color_out_of_gamut.test.ts | 83 +++++--- test/bundler/expectBundled.ts | 182 ++++++++++++++++++ 5 files changed, 246 insertions(+), 34 deletions(-) diff --git a/test/bundler/css/wpt/background-computed.test.ts b/test/bundler/css/wpt/background-computed.test.ts index 21fc84cc3910..cd762d81b14b 100644 --- a/test/bundler/css/wpt/background-computed.test.ts +++ b/test/bundler/css/wpt/background-computed.test.ts @@ -4,6 +4,7 @@ import { itBundled } from "../../expectBundled"; const runTest = (property: string, input: string, expected: string) => { const testTitle = `${property}: ${input}`; itBundled(testTitle, { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -11,11 +12,11 @@ h1 { } `, }, - outfile: "out.css", + outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { ${property}: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed-rgb.test.ts b/test/bundler/css/wpt/color-computed-rgb.test.ts index 1611be65809e..61552d3feafb 100644 --- a/test/bundler/css/wpt/color-computed-rgb.test.ts +++ b/test/bundler/css/wpt/color-computed-rgb.test.ts @@ -4,6 +4,7 @@ import { itBundled } from "../../expectBundled"; const runTest = (testTitle: string, input: string, expected: string) => { testTitle = testTitle.length === 0 ? input : testTitle; itBundled(testTitle, { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -11,11 +12,11 @@ h1 { } `, }, - outfile: "out.css", + outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed.test.ts b/test/bundler/css/wpt/color-computed.test.ts index 4377deb91e62..b1a0731ee175 100644 --- a/test/bundler/css/wpt/color-computed.test.ts +++ b/test/bundler/css/wpt/color-computed.test.ts @@ -3,6 +3,7 @@ import { itBundled } from "../../expectBundled"; const runTest = (input: string, expected: string) => { itBundled(input, { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -10,11 +11,11 @@ h1 { } `, }, - outfile: "out.css", + outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts index fc734d383c8f..64669d3e18d9 100644 --- a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts +++ b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts @@ -5,6 +5,7 @@ let i = 0; const testname = () => `test-${i++}`; describe("relative_color_out_of_gamut", () => { itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -12,11 +13,11 @@ h1 { } `, }, - outfile: "out.css", + outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { color: #00f942; } @@ -25,6 +26,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -36,7 +38,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lab(100 104.3 -50.9) r g b); } @@ -45,6 +47,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -56,7 +59,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lab(0 104.3 -50.9) r g b); } @@ -65,6 +68,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -76,7 +80,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lch(100 116 334) r g b); } @@ -85,6 +89,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -96,7 +101,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lch(0 116 334) r g b); } @@ -105,6 +110,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -116,7 +122,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklab(1 .365 -.16) r g b); } @@ -125,6 +131,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -136,7 +143,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklab(0 .365 -.16) r g b); } @@ -145,6 +152,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -156,7 +164,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklch(1 .399 336.3) r g b); } @@ -165,6 +173,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -176,7 +185,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklch(0 .399 336.3) r g b); } @@ -185,6 +194,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -196,7 +206,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: #00f942; } @@ -205,6 +215,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -216,7 +227,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lab(100 104.3 -50.9) h s l); } @@ -225,6 +236,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -236,7 +248,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lab(0 104.3 -50.9) h s l); } @@ -245,6 +257,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -256,7 +269,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lch(100 116 334) h s l); } @@ -265,6 +278,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -276,7 +290,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lch(0 116 334) h s l); } @@ -285,6 +299,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -296,7 +311,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklab(1 .365 -.16) h s l); } @@ -305,6 +320,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -316,7 +332,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklab(0 .365 -.16) h s l); } @@ -325,6 +341,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -336,7 +353,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklch(1 .399 336.3) h s l); } @@ -345,6 +362,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -356,7 +374,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklch(0 .399 336.3) h s l); } @@ -365,6 +383,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -376,7 +395,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: #00f942; } @@ -385,6 +404,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -396,7 +416,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lab(100 104.3 -50.9) h w b); } @@ -405,6 +425,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -416,7 +437,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lab(0 104.3 -50.9) h w b); } @@ -425,6 +446,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -436,7 +458,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lch(100 116 334) h w b); } @@ -445,6 +467,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -456,7 +479,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lch(0 116 334) h w b); } @@ -465,6 +488,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -476,7 +500,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklab(1 .365 -.16) h w b); } @@ -485,6 +509,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -496,7 +521,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklab(0 .365 -.16) h w b); } @@ -505,6 +530,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -516,7 +542,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklch(1 .399 336.3) h w b); } @@ -525,6 +551,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -536,7 +563,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklch(0 .399 336.3) h w b); } diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 23f15e516ca8..f519a49fcf68 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -299,6 +299,13 @@ export interface BundlerTestInput { /** Run after the bun.build function is called with its output */ onAfterApiBundle?(build: BuildOutput): Promise | void; + + /** + * Run the build entirely in memory using Bun.build's `files` API. + * No temp directories or files are created. Outputs are read from BuildArtifact.text(). + * The `onAfterBundle` callback still works with the same API. + */ + virtual?: boolean; } export interface SourceMapTests { @@ -494,6 +501,7 @@ function expectBundled( generateOutput = true, onAfterApiBundle, throw: _throw = false, + virtual = false, ...unknownProps } = opts; @@ -580,6 +588,180 @@ function expectBundled( return testRef(id, opts); } + // Virtual mode: run entirely in memory without disk I/O + if (virtual) { + return (async () => { + // Prepare virtual files with dedent applied + const virtualFiles: Record = {}; + for (const [file, contents] of Object.entries(files)) { + virtualFiles[file] = typeof contents === "string" ? dedent(contents) : contents.toString(); + } + + entryPoints ??= [Object.keys(files)[0]]; + format ??= "esm"; + target ??= "browser"; + + const build = await Bun.build({ + entrypoints: entryPoints, + files: virtualFiles, + target, + format, + minify: { + whitespace: minifyWhitespace, + syntax: minifySyntax, + identifiers: minifyIdentifiers, + }, + external, + plugins: typeof plugins === "function" ? [{ name: "plugin", setup: plugins }] : plugins, + splitting, + treeShaking, + sourcemap: sourceMap, + publicPath, + banner, + footer, + packages, + loader, + jsx: jsx + ? { + runtime: jsx.runtime, + importSource: jsx.importSource, + factory: jsx.factory, + fragment: jsx.fragment, + sideEffects: jsx.sideEffects, + development: jsx.development, + } + : undefined, + }); + + if (!build.success) { + const errors = build.logs + .filter(x => x.level === "error") + .map(x => x.message) + .join("\n"); + + // Check if errors were expected + if (bundleErrors) { + const expectedErrors = Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error }))); + // For now, just check that we got errors as expected + if (expectedErrors.length > 0) { + return testRef(id, opts); + } + } + throw new Error(`Bundle failed:\n${errors}`); + } else if (bundleErrors) { + const expectedErrors = Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error }))); + if (expectedErrors.length > 0) { + throw new Error( + "Errors were expected while bundling:\n" + expectedErrors.map(e => `${e.file}: ${e.error}`).join("\n"), + ); + } + } + + // Build in-memory file cache from BuildArtifact outputs + const outputCache: Record = {}; + for (const output of build.outputs) { + // Normalize path: "./a.css" -> "/a.css" + let outputPath = output.path; + if (outputPath.startsWith("./")) outputPath = outputPath.slice(1); + if (!outputPath.startsWith("/")) outputPath = "/" + outputPath; + outputCache[outputPath] = await output.text(); + } + + // Determine the main output file path + const mainOutputPath = Object.keys(outputCache)[0] || "/out.js"; + const outfileVirtual = outfile ? (outfile.startsWith("/") ? outfile : "/" + outfile) : mainOutputPath; + + // Create API object that reads from in-memory cache + const readFile = (file: string): string => { + // Normalize the file path + let normalizedFile = file; + if (normalizedFile.startsWith("./")) normalizedFile = normalizedFile.slice(1); + if (!normalizedFile.startsWith("/")) normalizedFile = "/" + normalizedFile; + + // Try exact match first + if (outputCache[normalizedFile]) return outputCache[normalizedFile]; + + // Try matching by basename for /out.css -> /a.css case + const basename = normalizedFile.split("/").pop()!; + for (const [key, value] of Object.entries(outputCache)) { + if (key.endsWith("/" + basename) || key === "/" + basename) { + return value; + } + } + + // If looking for a specific extension and there's only one file with that extension, use it + const ext = basename.includes(".") ? basename.slice(basename.lastIndexOf(".")) : ""; + if (ext) { + const matchingFiles = Object.entries(outputCache).filter(([key]) => key.endsWith(ext)); + if (matchingFiles.length === 1) { + return matchingFiles[0][1]; + } + } + + throw new Error(`Virtual file not found: ${file}. Available: ${Object.keys(outputCache).join(", ")}`); + }; + + const api = { + root: "/virtual", + outfile: outfileVirtual, + outdir: "/virtual/out", + join: (...paths: string[]) => "/" + paths.join("/").replace(/^\/+/, ""), + readFile, + writeFile: (_file: string, _contents: string) => { + throw new Error("writeFile not supported in virtual mode"); + }, + expectFile: (file: string) => expect(readFile(file)), + prependFile: (_file: string, _contents: string) => { + throw new Error("prependFile not supported in virtual mode"); + }, + appendFile: (_file: string, _contents: string) => { + throw new Error("appendFile not supported in virtual mode"); + }, + assertFileExists: (file: string) => { + readFile(file); // Will throw if not found + }, + warnings: {} as Record, + options: opts, + captureFile: (file: string, fnName = "capture") => { + const fileContents = readFile(file); + let i = 0; + const length = fileContents.length; + const matches = []; + while (i < length) { + i = fileContents.indexOf(fnName, i); + if (i === -1) break; + const start = i; + let depth = 0; + while (i < length) { + const char = fileContents[i]; + if (char === "(") depth++; + else if (char === ")") { + depth--; + if (depth === 0) break; + } + i++; + } + if (depth !== 0) { + throw new Error(`Could not find closing paren for ${fnName} call in ${file}`); + } + matches.push(fileContents.slice(start + fnName.length + 1, i)); + i++; + } + if (matches.length === 0) { + throw new Error(`No ${fnName} calls found in ${file}`); + } + return matches; + }, + } satisfies BundlerTestBundleAPI; + + if (onAfterBundle) { + onAfterBundle(api); + } + + return testRef(id, opts); + })(); + } + return (async () => { if (!backend) { backend = From a22f00536526747ac43c948ea49bd34ca9201b3b Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 09:17:00 +0000 Subject: [PATCH 02/12] perf(tests): convert more CSS tests to virtual mode Convert 3 additional CSS test files to use virtual mode for faster execution: - css-modules.test.ts (first test) - is-selector-21169.test.ts - view-transition-23600.test.ts Co-Authored-By: Claude Opus 4.5 --- test/bundler/css/css-modules.test.ts | 10 +++++----- test/bundler/css/is-selector-21169.test.ts | 10 +++++----- test/bundler/css/view-transition-23600.test.ts | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/bundler/css/css-modules.test.ts b/test/bundler/css/css-modules.test.ts index 90ae337833ac..fcebae75b905 100644 --- a/test/bundler/css/css-modules.test.ts +++ b/test/bundler/css/css-modules.test.ts @@ -2,18 +2,18 @@ import { itBundled } from "../expectBundled"; describe("css", () => { itBundled("css-module/GlobalPseudoFunction", { + virtual: true, files: { - "index.module.css": /* css */ ` + "/index.module.css": /* css */ ` :global(.foo) { color: red; } `, }, - outdir: "/out", - entryPoints: ["/index.module.css"], + outfile: "/out.css", onAfterBundle(api) { - api.expectFile("/out/index.module.css").toEqualIgnoringWhitespace(` - /* index.module.css */ + api.expectFile("/out.css").toEqualIgnoringWhitespace(` + /* ../../index.module.css */ .foo { color: red; } diff --git a/test/bundler/css/is-selector-21169.test.ts b/test/bundler/css/is-selector-21169.test.ts index 48aba62c0e26..e3a7f21761e3 100644 --- a/test/bundler/css/is-selector-21169.test.ts +++ b/test/bundler/css/is-selector-21169.test.ts @@ -2,18 +2,18 @@ import { itBundled } from "../expectBundled"; describe("css", () => { itBundled("css/is-selector", { + virtual: true, files: { - "index.css": /* css */ ` + "/index.css": /* css */ ` .foo:is(input:checked) { color: red; } `, }, - outdir: "/out", - entryPoints: ["/index.css"], + outfile: "/out.css", onAfterBundle(api) { - api.expectFile("/out/index.css").toMatchInlineSnapshot(` - "/* index.css */ + api.expectFile("/out.css").toMatchInlineSnapshot(` + "/* ../../index.css */ .foo:-webkit-any(input:checked) { color: red; } diff --git a/test/bundler/css/view-transition-23600.test.ts b/test/bundler/css/view-transition-23600.test.ts index e29384fa9817..692a909287ef 100644 --- a/test/bundler/css/view-transition-23600.test.ts +++ b/test/bundler/css/view-transition-23600.test.ts @@ -2,8 +2,9 @@ import { itBundled } from "../expectBundled"; describe("css", () => { itBundled("css/view-transition-class-selector-23600", { + virtual: true, files: { - "index.css": /* css */ ` + "/index.css": /* css */ ` @keyframes slide-out { from { opacity: 1; @@ -33,11 +34,10 @@ describe("css", () => { } `, }, - outdir: "/out", - entryPoints: ["/index.css"], + outfile: "/out.css", onAfterBundle(api) { - api.expectFile("/out/index.css").toMatchInlineSnapshot(` - "/* index.css */ + api.expectFile("/out.css").toMatchInlineSnapshot(` + "/* ../../index.css */ @keyframes slide-out { from { opacity: 1; From 32cdb2cfd4fe75898daf872b2e855759dabb403a Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 09:18:35 +0000 Subject: [PATCH 03/12] perf(tests): convert 7 esbuild CSS tests to virtual mode Convert simple CSS tests in esbuild/css.test.ts to use virtual mode: - CSSEntryPoint - CSSEntryPointEmpty - CSSNesting - CSSAtImportSimple - CSSAtImportDiamond - CSSAtImportCycle Note: CSSAtImportMissing cannot use virtual mode because Bun.build throws on resolution errors instead of returning { success: false }. Co-Authored-By: Claude Opus 4.5 --- test/bundler/esbuild/css.test.ts | 39 +++++++++++++++++++------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/test/bundler/esbuild/css.test.ts b/test/bundler/esbuild/css.test.ts index 8b4eb0311538..ec0f9871ad8e 100644 --- a/test/bundler/esbuild/css.test.ts +++ b/test/bundler/esbuild/css.test.ts @@ -9,6 +9,7 @@ import { itBundled } from "../expectBundled"; describe("bundler", () => { itBundled("css/CSSEntryPoint", { + virtual: true, files: { "/entry.css": /* css */ ` body { @@ -16,10 +17,10 @@ describe("bundler", () => { color: black } `, }, - outfile: "/out.js", + outfile: "/out.css", onAfterBundle(api) { - api.expectFile("/out.js").toEqualIgnoringWhitespace(` - /* entry.css */ + api.expectFile("/out.css").toEqualIgnoringWhitespace(` + /* ../../entry.css */ body { color: #000; background: #fff; @@ -28,17 +29,19 @@ describe("bundler", () => { }); itBundled("css/CSSEntryPointEmpty", { + virtual: true, files: { "/entry.css": /* css */ `\n`, }, - outfile: "/out.js", + outfile: "/out.css", onAfterBundle(api) { - api.expectFile("/out.js").toEqualIgnoringWhitespace(` - /* entry.css */`); + api.expectFile("/out.css").toEqualIgnoringWhitespace(` + /* ../../entry.css */`); }, }); itBundled("css/CSSNesting", { + virtual: true, target: "bun", files: { "/entry.css": /* css */ ` @@ -48,10 +51,10 @@ describe("bundler", () => { } }`, }, - outfile: "/out.js", + outfile: "/out.css", onAfterBundle(api) { - api.expectFile("/out.js").toEqualIgnoringWhitespace(` - /* entry.css */ + api.expectFile("/out.css").toEqualIgnoringWhitespace(` + /* ../../entry.css */ body { &h1 { color: #fff; @@ -62,6 +65,7 @@ describe("bundler", () => { }); itBundled("css/CSSAtImportMissing", { + // Cannot use virtual mode for error tests - Bun.build throws instead of returning { success: false } files: { "/entry.css": `@import "./missing.css";`, }, @@ -71,6 +75,7 @@ describe("bundler", () => { }); itBundled("css/CSSAtImportSimple", { + virtual: true, // GENERATED files: { "/entry.css": /* css */ ` @@ -83,16 +88,17 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* internal.css */ + /* /internal.css */ .before { color: red; } - /* entry.css */ + /* ../../entry.css */ `); }, }); itBundled("css/CSSAtImportDiamond", { + virtual: true, // GENERATED files: { "/a.css": /* css */ ` @@ -115,19 +121,19 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* b.css */ + /* /b.css */ .first { color: red; } - /* d.css */ + /* /d.css */ .second { color: red; } - /* c.css */ + /* /c.css */ .third { color: red; } - /* a.css */ + /* ../../a.css */ .last { color: red; } @@ -136,6 +142,7 @@ describe("bundler", () => { }); itBundled("css/CSSAtImportCycle", { + virtual: true, files: { "/a.css": /* css */ ` @import "./a.css"; @@ -145,7 +152,7 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ .hehe { color: red; } From 07bdea0d0331cc0eb431c4588c6ca91ce273c072 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 09:42:42 +0000 Subject: [PATCH 04/12] fix(tests): address code review feedback for virtual mode - Add validation for unsupported options (runtimeFiles, run, dce, cjs2esm, matchesReference, snapshotSourceMap, expectExactFilesize, onAfterApiBundle, bundleWarnings, outdir) with descriptive error messages - Preserve binary file content (Buffer, Uint8Array, Blob) instead of converting to string with .toString() - Tighten readFile to require exact path matches instead of loose basename/extension fallbacks, only allowing outfile alias for single outputs Co-Authored-By: Claude Opus 4.5 --- test/bundler/expectBundled.ts | 42 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index f519a49fcf68..1a39adfbccca 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -590,11 +590,28 @@ function expectBundled( // Virtual mode: run entirely in memory without disk I/O if (virtual) { + // Validate that unsupported options are not set + const unsupportedOptions: string[] = []; + if (runtimeFiles && Object.keys(runtimeFiles).length > 0) unsupportedOptions.push("runtimeFiles"); + if (run) unsupportedOptions.push("run"); + if (dce) unsupportedOptions.push("dce"); + if (cjs2esm) unsupportedOptions.push("cjs2esm"); + if (matchesReference) unsupportedOptions.push("matchesReference"); + if (snapshotSourceMap) unsupportedOptions.push("snapshotSourceMap"); + if (expectExactFilesize) unsupportedOptions.push("expectExactFilesize"); + if (onAfterApiBundle) unsupportedOptions.push("onAfterApiBundle"); + if (bundleWarnings && Object.keys(bundleWarnings).length > 0) unsupportedOptions.push("bundleWarnings"); + if (outdir) unsupportedOptions.push("outdir (use outfile instead)"); + + if (unsupportedOptions.length > 0) { + throw new Error(`Virtual mode does not support the following options: ${unsupportedOptions.join(", ")}`); + } + return (async () => { - // Prepare virtual files with dedent applied - const virtualFiles: Record = {}; + // Prepare virtual files with dedent applied for strings, preserve binary content as-is + const virtualFiles: Record = {}; for (const [file, contents] of Object.entries(files)) { - virtualFiles[file] = typeof contents === "string" ? dedent(contents) : contents.toString(); + virtualFiles[file] = typeof contents === "string" ? dedent(contents) : contents; } entryPoints ??= [Object.keys(files)[0]]; @@ -681,21 +698,10 @@ function expectBundled( // Try exact match first if (outputCache[normalizedFile]) return outputCache[normalizedFile]; - // Try matching by basename for /out.css -> /a.css case - const basename = normalizedFile.split("/").pop()!; - for (const [key, value] of Object.entries(outputCache)) { - if (key.endsWith("/" + basename) || key === "/" + basename) { - return value; - } - } - - // If looking for a specific extension and there's only one file with that extension, use it - const ext = basename.includes(".") ? basename.slice(basename.lastIndexOf(".")) : ""; - if (ext) { - const matchingFiles = Object.entries(outputCache).filter(([key]) => key.endsWith(ext)); - if (matchingFiles.length === 1) { - return matchingFiles[0][1]; - } + // For single-output builds, allow accessing the output by the configured outfile path + const outputs = Object.keys(outputCache); + if (outputs.length === 1 && normalizedFile === outfileVirtual) { + return outputCache[outputs[0]]; } throw new Error(`Virtual file not found: ${file}. Available: ${Object.keys(outputCache).join(", ")}`); From 6dcd16657ece1c2bc1956da9f7b8dcf9dd8cb036 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 09:55:29 +0000 Subject: [PATCH 05/12] Address code review feedback for virtual mode - Change bundleWarnings check from key length check to truthy check - Add missing unsupported options: keepNames, emitDCEAnnotations, ignoreDCEAnnotations, bytecode, compile - Pass define, drop, conditions to Bun.build since they are supported - Fix readFile to use 'in' operator instead of truthy check (handles empty string outputs correctly) Co-Authored-By: Claude Opus 4.5 --- test/bundler/expectBundled.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 1a39adfbccca..3f0f4fccaf69 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -600,7 +600,12 @@ function expectBundled( if (snapshotSourceMap) unsupportedOptions.push("snapshotSourceMap"); if (expectExactFilesize) unsupportedOptions.push("expectExactFilesize"); if (onAfterApiBundle) unsupportedOptions.push("onAfterApiBundle"); - if (bundleWarnings && Object.keys(bundleWarnings).length > 0) unsupportedOptions.push("bundleWarnings"); + if (bundleWarnings) unsupportedOptions.push("bundleWarnings"); + if (keepNames) unsupportedOptions.push("keepNames"); + if (emitDCEAnnotations) unsupportedOptions.push("emitDCEAnnotations"); + if (ignoreDCEAnnotations) unsupportedOptions.push("ignoreDCEAnnotations"); + if (bytecode) unsupportedOptions.push("bytecode"); + if (compile) unsupportedOptions.push("compile"); if (outdir) unsupportedOptions.push("outdir (use outfile instead)"); if (unsupportedOptions.length > 0) { @@ -648,6 +653,9 @@ function expectBundled( development: jsx.development, } : undefined, + define, + drop, + conditions, }); if (!build.success) { @@ -696,7 +704,7 @@ function expectBundled( if (!normalizedFile.startsWith("/")) normalizedFile = "/" + normalizedFile; // Try exact match first - if (outputCache[normalizedFile]) return outputCache[normalizedFile]; + if (normalizedFile in outputCache) return outputCache[normalizedFile]; // For single-output builds, allow accessing the output by the configured outfile path const outputs = Object.keys(outputCache); From 19606f0c12bd6e87beae44bf59e22273691a4915 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 10:03:43 +0000 Subject: [PATCH 06/12] Address additional code review feedback - Add features to unsupported options validation - Remove redundant default assignments for entryPoints, format, target (already set earlier in the function) - Improve bundleErrors validation with proper file/message matching: - Check expected errors match actual errors by file path suffix and message substring - Report unexpected errors and missing expected errors separately - Extract duplicated captureFile logic into shared extractCaptures helper Co-Authored-By: Claude Opus 4.5 --- test/bundler/expectBundled.ts | 170 +++++++++++++++++----------------- 1 file changed, 84 insertions(+), 86 deletions(-) diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 3f0f4fccaf69..13d9764c95c3 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -415,6 +415,40 @@ function testRef(id: string, options: BundlerTestInput): BundlerTestRef { return { id, options }; } +/** + * Extract capture function calls from file contents. + * Finds all occurrences of fnName(...) and returns the argument contents. + */ +function extractCaptures(fileContents: string, file: string, fnName: string): string[] { + let i = 0; + const length = fileContents.length; + const matches: string[] = []; + while (i < length) { + i = fileContents.indexOf(fnName, i); + if (i === -1) break; + const start = i; + let depth = 0; + while (i < length) { + const char = fileContents[i]; + if (char === "(") depth++; + else if (char === ")") { + depth--; + if (depth === 0) break; + } + i++; + } + if (depth !== 0) { + throw new Error(`Could not find closing paren for ${fnName} call in ${file}`); + } + matches.push(fileContents.slice(start + fnName.length + 1, i)); + i++; + } + if (matches.length === 0) { + throw new Error(`No ${fnName} calls found in ${file}`); + } + return matches; +} + function expectBundled( id: string, opts: BundlerTestInput, @@ -606,6 +640,7 @@ function expectBundled( if (ignoreDCEAnnotations) unsupportedOptions.push("ignoreDCEAnnotations"); if (bytecode) unsupportedOptions.push("bytecode"); if (compile) unsupportedOptions.push("compile"); + if (features && features.length > 0) unsupportedOptions.push("features"); if (outdir) unsupportedOptions.push("outdir (use outfile instead)"); if (unsupportedOptions.length > 0) { @@ -619,10 +654,6 @@ function expectBundled( virtualFiles[file] = typeof contents === "string" ? dedent(contents) : contents; } - entryPoints ??= [Object.keys(files)[0]]; - format ??= "esm"; - target ??= "browser"; - const build = await Bun.build({ entrypoints: entryPoints, files: virtualFiles, @@ -658,28 +689,59 @@ function expectBundled( conditions, }); + const expectedErrors = bundleErrors + ? Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error }))) + : null; + if (!build.success) { - const errors = build.logs + // Collect actual errors from build logs + const actualErrors = build.logs .filter(x => x.level === "error") - .map(x => x.message) - .join("\n"); + .map(x => ({ + file: x.position?.file || "", + error: x.message, + })); // Check if errors were expected - if (bundleErrors) { - const expectedErrors = Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error }))); - // For now, just check that we got errors as expected - if (expectedErrors.length > 0) { - return testRef(id, opts); + if (expectedErrors && expectedErrors.length > 0) { + const errorsLeft = [...expectedErrors]; + const unexpectedErrors: typeof actualErrors = []; + + for (const error of actualErrors) { + const i = errorsLeft.findIndex(item => error.file.endsWith(item.file) && error.error.includes(item.error)); + if (i === -1) { + unexpectedErrors.push(error); + } else { + errorsLeft.splice(i, 1); + } } + + if (unexpectedErrors.length > 0) { + throw new Error( + "Unexpected errors reported while bundling:\n" + + unexpectedErrors.map(e => `${e.file}: ${e.error}`).join("\n") + + "\n\nExpected errors:\n" + + expectedErrors.map(e => `${e.file}: ${e.error}`).join("\n"), + ); + } + + if (errorsLeft.length > 0) { + throw new Error( + "Expected errors were not found while bundling:\n" + + errorsLeft.map(e => `${e.file}: ${e.error}`).join("\n") + + "\n\nActual errors:\n" + + actualErrors.map(e => `${e.file}: ${e.error}`).join("\n"), + ); + } + + return testRef(id, opts); } - throw new Error(`Bundle failed:\n${errors}`); - } else if (bundleErrors) { - const expectedErrors = Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error }))); - if (expectedErrors.length > 0) { - throw new Error( - "Errors were expected while bundling:\n" + expectedErrors.map(e => `${e.file}: ${e.error}`).join("\n"), - ); - } + + throw new Error(`Bundle failed:\n${actualErrors.map(e => `${e.file}: ${e.error}`).join("\n")}`); + } else if (expectedErrors && expectedErrors.length > 0) { + throw new Error( + "Errors were expected while bundling:\n" + expectedErrors.map(e => `${e.file}: ${e.error}`).join("\n"), + ); } // Build in-memory file cache from BuildArtifact outputs @@ -736,36 +798,7 @@ function expectBundled( }, warnings: {} as Record, options: opts, - captureFile: (file: string, fnName = "capture") => { - const fileContents = readFile(file); - let i = 0; - const length = fileContents.length; - const matches = []; - while (i < length) { - i = fileContents.indexOf(fnName, i); - if (i === -1) break; - const start = i; - let depth = 0; - while (i < length) { - const char = fileContents[i]; - if (char === "(") depth++; - else if (char === ")") { - depth--; - if (depth === 0) break; - } - i++; - } - if (depth !== 0) { - throw new Error(`Could not find closing paren for ${fnName} call in ${file}`); - } - matches.push(fileContents.slice(start + fnName.length + 1, i)); - i++; - } - if (matches.length === 0) { - throw new Error(`No ${fnName} calls found in ${file}`); - } - return matches; - }, + captureFile: (file: string, fnName = "capture") => extractCaptures(readFile(file), file, fnName), } satisfies BundlerTestBundleAPI; if (onAfterBundle) { @@ -1517,42 +1550,7 @@ for (const [key, blob] of build.outputs) { }, warnings: warningReference, options: opts, - captureFile: (file, fnName = "capture") => { - const fileContents = readFile(file); - let i = 0; - const length = fileContents.length; - const matches = []; - while (i < length) { - i = fileContents.indexOf(fnName, i); - if (i === -1) { - break; - } - const start = i; - let depth = 0; - while (i < length) { - const char = fileContents[i]; - if (char === "(") { - depth++; - } else if (char === ")") { - depth--; - if (depth === 0) { - break; - } - } - i++; - } - if (depth !== 0) { - throw new Error(`Could not find closing paren for ${fnName} call in ${file}`); - } - matches.push(fileContents.slice(start + fnName.length + 1, i)); - i++; - } - - if (matches.length === 0) { - throw new Error(`No ${fnName} calls found in ${file}`); - } - return matches; - }, + captureFile: (file, fnName = "capture") => extractCaptures(readFile(file), file, fnName), } satisfies BundlerTestBundleAPI; // DCE keep scan From 85ca1a67cf081afd2b2515f98ebe54bddbb139bc Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 10:51:39 +0000 Subject: [PATCH 07/12] Revert esbuild/css.test.ts tests to non-virtual mode The virtual mode generates relative path comments that depend on the cwd depth. CI runs from a different directory structure than local, causing path mismatches (../../entry.css vs ../../../../entry.css). Revert these tests to non-virtual mode since they have hardcoded path expectations in the CSS comments. The WPT tests use simpler paths like /a.css that work consistently. Co-Authored-By: Claude Opus 4.5 --- test/bundler/esbuild/css.test.ts | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/test/bundler/esbuild/css.test.ts b/test/bundler/esbuild/css.test.ts index ec0f9871ad8e..b18eb22d8147 100644 --- a/test/bundler/esbuild/css.test.ts +++ b/test/bundler/esbuild/css.test.ts @@ -9,7 +9,7 @@ import { itBundled } from "../expectBundled"; describe("bundler", () => { itBundled("css/CSSEntryPoint", { - virtual: true, + // GENERATED files: { "/entry.css": /* css */ ` body { @@ -20,7 +20,7 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../entry.css */ + /* entry.css */ body { color: #000; background: #fff; @@ -29,19 +29,19 @@ describe("bundler", () => { }); itBundled("css/CSSEntryPointEmpty", { - virtual: true, + // GENERATED files: { "/entry.css": /* css */ `\n`, }, outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../entry.css */`); + /* entry.css */`); }, }); itBundled("css/CSSNesting", { - virtual: true, + // GENERATED target: "bun", files: { "/entry.css": /* css */ ` @@ -54,9 +54,9 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../entry.css */ + /* entry.css */ body { - &h1 { + & h1 { color: #fff; } } @@ -75,7 +75,6 @@ describe("bundler", () => { }); itBundled("css/CSSAtImportSimple", { - virtual: true, // GENERATED files: { "/entry.css": /* css */ ` @@ -88,17 +87,16 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* /internal.css */ + /* internal.css */ .before { color: red; } - /* ../../entry.css */ + /* entry.css */ `); }, }); itBundled("css/CSSAtImportDiamond", { - virtual: true, // GENERATED files: { "/a.css": /* css */ ` @@ -121,19 +119,19 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* /b.css */ + /* b.css */ .first { color: red; } - /* /d.css */ + /* d.css */ .second { color: red; } - /* /c.css */ + /* c.css */ .third { color: red; } - /* ../../a.css */ + /* a.css */ .last { color: red; } @@ -142,7 +140,7 @@ describe("bundler", () => { }); itBundled("css/CSSAtImportCycle", { - virtual: true, + // GENERATED files: { "/a.css": /* css */ ` @import "./a.css"; @@ -152,7 +150,7 @@ describe("bundler", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ .hehe { color: red; } From 44340bf7e71149a4b217a3286f745612fc0de49a Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 11:35:37 +0000 Subject: [PATCH 08/12] Revert all CSS tests with path-dependent expectations to non-virtual mode The virtual mode generates CSS comments with relative paths (../../) that depend on the cwd depth, causing test failures in CI where the directory structure differs from local development. Reverted all CSS tests to non-virtual mode and updated the expected comment paths from "/* ../../a.css */" to "/* a.css */". Co-Authored-By: Claude Opus 4.5 --- test/bundler/css/css-modules.test.ts | 3 +- test/bundler/css/is-selector-21169.test.ts | 3 +- .../bundler/css/view-transition-23600.test.ts | 3 +- .../css/wpt/background-computed.test.ts | 3 +- .../css/wpt/color-computed-rgb.test.ts | 3 +- test/bundler/css/wpt/color-computed.test.ts | 3 +- .../wpt/relative_color_out_of_gamut.test.ts | 81 +++++++------------ 7 files changed, 33 insertions(+), 66 deletions(-) diff --git a/test/bundler/css/css-modules.test.ts b/test/bundler/css/css-modules.test.ts index fcebae75b905..99624807a00e 100644 --- a/test/bundler/css/css-modules.test.ts +++ b/test/bundler/css/css-modules.test.ts @@ -2,7 +2,6 @@ import { itBundled } from "../expectBundled"; describe("css", () => { itBundled("css-module/GlobalPseudoFunction", { - virtual: true, files: { "/index.module.css": /* css */ ` :global(.foo) { @@ -13,7 +12,7 @@ describe("css", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../index.module.css */ + /* index.module.css */ .foo { color: red; } diff --git a/test/bundler/css/is-selector-21169.test.ts b/test/bundler/css/is-selector-21169.test.ts index e3a7f21761e3..f606f1d13750 100644 --- a/test/bundler/css/is-selector-21169.test.ts +++ b/test/bundler/css/is-selector-21169.test.ts @@ -2,7 +2,6 @@ import { itBundled } from "../expectBundled"; describe("css", () => { itBundled("css/is-selector", { - virtual: true, files: { "/index.css": /* css */ ` .foo:is(input:checked) { @@ -13,7 +12,7 @@ describe("css", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toMatchInlineSnapshot(` - "/* ../../index.css */ + "/* index.css */ .foo:-webkit-any(input:checked) { color: red; } diff --git a/test/bundler/css/view-transition-23600.test.ts b/test/bundler/css/view-transition-23600.test.ts index 692a909287ef..8d72c4bb261c 100644 --- a/test/bundler/css/view-transition-23600.test.ts +++ b/test/bundler/css/view-transition-23600.test.ts @@ -2,7 +2,6 @@ import { itBundled } from "../expectBundled"; describe("css", () => { itBundled("css/view-transition-class-selector-23600", { - virtual: true, files: { "/index.css": /* css */ ` @keyframes slide-out { @@ -37,7 +36,7 @@ describe("css", () => { outfile: "/out.css", onAfterBundle(api) { api.expectFile("/out.css").toMatchInlineSnapshot(` - "/* ../../index.css */ + "/* index.css */ @keyframes slide-out { from { opacity: 1; diff --git a/test/bundler/css/wpt/background-computed.test.ts b/test/bundler/css/wpt/background-computed.test.ts index cd762d81b14b..62d9785b3f2f 100644 --- a/test/bundler/css/wpt/background-computed.test.ts +++ b/test/bundler/css/wpt/background-computed.test.ts @@ -4,7 +4,6 @@ import { itBundled } from "../../expectBundled"; const runTest = (property: string, input: string, expected: string) => { const testTitle = `${property}: ${input}`; itBundled(testTitle, { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -16,7 +15,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { ${property}: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed-rgb.test.ts b/test/bundler/css/wpt/color-computed-rgb.test.ts index 61552d3feafb..34c17da4763a 100644 --- a/test/bundler/css/wpt/color-computed-rgb.test.ts +++ b/test/bundler/css/wpt/color-computed-rgb.test.ts @@ -4,7 +4,6 @@ import { itBundled } from "../../expectBundled"; const runTest = (testTitle: string, input: string, expected: string) => { testTitle = testTitle.length === 0 ? input : testTitle; itBundled(testTitle, { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -16,7 +15,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed.test.ts b/test/bundler/css/wpt/color-computed.test.ts index b1a0731ee175..be6ac1f76d73 100644 --- a/test/bundler/css/wpt/color-computed.test.ts +++ b/test/bundler/css/wpt/color-computed.test.ts @@ -3,7 +3,6 @@ import { itBundled } from "../../expectBundled"; const runTest = (input: string, expected: string) => { itBundled(input, { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -15,7 +14,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts index 64669d3e18d9..9f9af498bda1 100644 --- a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts +++ b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts @@ -5,7 +5,6 @@ let i = 0; const testname = () => `test-${i++}`; describe("relative_color_out_of_gamut", () => { itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -17,7 +16,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { color: #00f942; } @@ -26,7 +25,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -38,7 +36,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lab(100 104.3 -50.9) r g b); } @@ -47,7 +45,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -59,7 +56,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lab(0 104.3 -50.9) r g b); } @@ -68,7 +65,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -80,7 +76,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lch(100 116 334) r g b); } @@ -89,7 +85,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -101,7 +96,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lch(0 116 334) r g b); } @@ -110,7 +105,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -122,7 +116,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklab(1 .365 -.16) r g b); } @@ -131,7 +125,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -143,7 +136,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklab(0 .365 -.16) r g b); } @@ -152,7 +145,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -164,7 +156,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklch(1 .399 336.3) r g b); } @@ -173,7 +165,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -185,7 +176,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklch(0 .399 336.3) r g b); } @@ -194,7 +185,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -206,7 +196,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: #00f942; } @@ -215,7 +205,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -227,7 +216,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lab(100 104.3 -50.9) h s l); } @@ -236,7 +225,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -248,7 +236,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lab(0 104.3 -50.9) h s l); } @@ -257,7 +245,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -269,7 +256,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lch(100 116 334) h s l); } @@ -278,7 +265,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -290,7 +276,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lch(0 116 334) h s l); } @@ -299,7 +285,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -311,7 +296,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklab(1 .365 -.16) h s l); } @@ -320,7 +305,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -332,7 +316,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklab(0 .365 -.16) h s l); } @@ -341,7 +325,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -353,7 +336,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklch(1 .399 336.3) h s l); } @@ -362,7 +345,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -374,7 +356,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklch(0 .399 336.3) h s l); } @@ -383,7 +365,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -395,7 +376,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: #00f942; } @@ -404,7 +385,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -416,7 +396,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lab(100 104.3 -50.9) h w b); } @@ -425,7 +405,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -437,7 +416,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lab(0 104.3 -50.9) h w b); } @@ -446,7 +425,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -458,7 +436,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lch(100 116 334) h w b); } @@ -467,7 +445,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -479,7 +456,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lch(0 116 334) h w b); } @@ -488,7 +465,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -500,7 +476,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklab(1 .365 -.16) h w b); } @@ -509,7 +485,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -521,7 +496,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklab(0 .365 -.16) h w b); } @@ -530,7 +505,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -542,7 +516,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklch(1 .399 336.3) h w b); } @@ -551,7 +525,6 @@ h1 { }); itBundled(testname(), { - virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -563,7 +536,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklch(0 .399 336.3) h w b); } From 8695e45f59ce547283267c683bcb75e809dc328b Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 11:55:07 +0000 Subject: [PATCH 09/12] Retry CI build (infrastructure issue with SetupBuildkite.cmake) From 8bac1dd4f3488acf04e7c8a4bdd6b39de23286a4 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 21:29:27 +0000 Subject: [PATCH 10/12] Remove comments from esbuild/css.test.ts Co-Authored-By: Claude Opus 4.5 --- test/bundler/esbuild/css.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/bundler/esbuild/css.test.ts b/test/bundler/esbuild/css.test.ts index b18eb22d8147..38dee7aefb01 100644 --- a/test/bundler/esbuild/css.test.ts +++ b/test/bundler/esbuild/css.test.ts @@ -9,7 +9,6 @@ import { itBundled } from "../expectBundled"; describe("bundler", () => { itBundled("css/CSSEntryPoint", { - // GENERATED files: { "/entry.css": /* css */ ` body { @@ -29,7 +28,6 @@ describe("bundler", () => { }); itBundled("css/CSSEntryPointEmpty", { - // GENERATED files: { "/entry.css": /* css */ `\n`, }, @@ -41,7 +39,6 @@ describe("bundler", () => { }); itBundled("css/CSSNesting", { - // GENERATED target: "bun", files: { "/entry.css": /* css */ ` @@ -65,7 +62,6 @@ describe("bundler", () => { }); itBundled("css/CSSAtImportMissing", { - // Cannot use virtual mode for error tests - Bun.build throws instead of returning { success: false } files: { "/entry.css": `@import "./missing.css";`, }, @@ -140,7 +136,6 @@ describe("bundler", () => { }); itBundled("css/CSSAtImportCycle", { - // GENERATED files: { "/a.css": /* css */ ` @import "./a.css"; From c04ee2889207528c8abe31616b523f6225bfd699 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 21:50:18 +0000 Subject: [PATCH 11/12] Add virtual: true to WPT CSS tests Use in-memory bundling for WPT CSS tests for faster execution. Update path comments to match virtual mode output. Co-Authored-By: Claude Opus 4.5 --- .../css/wpt/background-computed.test.ts | 3 +- .../css/wpt/color-computed-rgb.test.ts | 3 +- test/bundler/css/wpt/color-computed.test.ts | 3 +- .../wpt/relative_color_out_of_gamut.test.ts | 81 ++++++++++++------- 4 files changed, 60 insertions(+), 30 deletions(-) diff --git a/test/bundler/css/wpt/background-computed.test.ts b/test/bundler/css/wpt/background-computed.test.ts index 62d9785b3f2f..cd762d81b14b 100644 --- a/test/bundler/css/wpt/background-computed.test.ts +++ b/test/bundler/css/wpt/background-computed.test.ts @@ -4,6 +4,7 @@ import { itBundled } from "../../expectBundled"; const runTest = (property: string, input: string, expected: string) => { const testTitle = `${property}: ${input}`; itBundled(testTitle, { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -15,7 +16,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { ${property}: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed-rgb.test.ts b/test/bundler/css/wpt/color-computed-rgb.test.ts index 34c17da4763a..61552d3feafb 100644 --- a/test/bundler/css/wpt/color-computed-rgb.test.ts +++ b/test/bundler/css/wpt/color-computed-rgb.test.ts @@ -4,6 +4,7 @@ import { itBundled } from "../../expectBundled"; const runTest = (testTitle: string, input: string, expected: string) => { testTitle = testTitle.length === 0 ? input : testTitle; itBundled(testTitle, { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -15,7 +16,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed.test.ts b/test/bundler/css/wpt/color-computed.test.ts index be6ac1f76d73..b1a0731ee175 100644 --- a/test/bundler/css/wpt/color-computed.test.ts +++ b/test/bundler/css/wpt/color-computed.test.ts @@ -3,6 +3,7 @@ import { itBundled } from "../../expectBundled"; const runTest = (input: string, expected: string) => { itBundled(input, { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -14,7 +15,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts index 9f9af498bda1..64669d3e18d9 100644 --- a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts +++ b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts @@ -5,6 +5,7 @@ let i = 0; const testname = () => `test-${i++}`; describe("relative_color_out_of_gamut", () => { itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -16,7 +17,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* a.css */ +/* ../../a.css */ h1 { color: #00f942; } @@ -25,6 +26,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -36,7 +38,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lab(100 104.3 -50.9) r g b); } @@ -45,6 +47,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -56,7 +59,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lab(0 104.3 -50.9) r g b); } @@ -65,6 +68,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -76,7 +80,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lch(100 116 334) r g b); } @@ -85,6 +89,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -96,7 +101,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from lch(0 116 334) r g b); } @@ -105,6 +110,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -116,7 +122,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklab(1 .365 -.16) r g b); } @@ -125,6 +131,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -136,7 +143,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklab(0 .365 -.16) r g b); } @@ -145,6 +152,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -156,7 +164,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklch(1 .399 336.3) r g b); } @@ -165,6 +173,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -176,7 +185,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: rgb(from oklch(0 .399 336.3) r g b); } @@ -185,6 +194,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -196,7 +206,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: #00f942; } @@ -205,6 +215,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -216,7 +227,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lab(100 104.3 -50.9) h s l); } @@ -225,6 +236,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -236,7 +248,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lab(0 104.3 -50.9) h s l); } @@ -245,6 +257,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -256,7 +269,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lch(100 116 334) h s l); } @@ -265,6 +278,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -276,7 +290,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from lch(0 116 334) h s l); } @@ -285,6 +299,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -296,7 +311,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklab(1 .365 -.16) h s l); } @@ -305,6 +320,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -316,7 +332,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklab(0 .365 -.16) h s l); } @@ -325,6 +341,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -336,7 +353,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklch(1 .399 336.3) h s l); } @@ -345,6 +362,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -356,7 +374,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hsl(from oklch(0 .399 336.3) h s l); } @@ -365,6 +383,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -376,7 +395,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: #00f942; } @@ -385,6 +404,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -396,7 +416,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lab(100 104.3 -50.9) h w b); } @@ -405,6 +425,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -416,7 +437,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lab(0 104.3 -50.9) h w b); } @@ -425,6 +446,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -436,7 +458,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lch(100 116 334) h w b); } @@ -445,6 +467,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -456,7 +479,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from lch(0 116 334) h w b); } @@ -465,6 +488,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -476,7 +500,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklab(1 .365 -.16) h w b); } @@ -485,6 +509,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -496,7 +521,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklab(0 .365 -.16) h w b); } @@ -505,6 +530,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -516,7 +542,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklch(1 .399 336.3) h w b); } @@ -525,6 +551,7 @@ h1 { }); itBundled(testname(), { + virtual: true, files: { "/a.css": /* css */ ` h1 { @@ -536,7 +563,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* a.css */ + /* ../../a.css */ h1 { color: hwb(from oklch(0 .399 336.3) h w b); } From 18322da1e9b32e730c4c6826bbf10f598a37f2da Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sun, 18 Jan 2026 22:44:31 +0000 Subject: [PATCH 12/12] Fix virtual mode path comments by using relative paths Use relative paths (strip leading /) for virtual files to get consistent path comments in CSS output regardless of working directory. Co-Authored-By: Claude Opus 4.5 --- .../css/wpt/background-computed.test.ts | 2 +- .../css/wpt/color-computed-rgb.test.ts | 2 +- test/bundler/css/wpt/color-computed.test.ts | 2 +- .../wpt/relative_color_out_of_gamut.test.ts | 54 +++++++++---------- test/bundler/expectBundled.ts | 9 +++- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/test/bundler/css/wpt/background-computed.test.ts b/test/bundler/css/wpt/background-computed.test.ts index cd762d81b14b..78cf1c35b7b3 100644 --- a/test/bundler/css/wpt/background-computed.test.ts +++ b/test/bundler/css/wpt/background-computed.test.ts @@ -16,7 +16,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { ${property}: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed-rgb.test.ts b/test/bundler/css/wpt/color-computed-rgb.test.ts index 61552d3feafb..4743bb4ccdc0 100644 --- a/test/bundler/css/wpt/color-computed-rgb.test.ts +++ b/test/bundler/css/wpt/color-computed-rgb.test.ts @@ -16,7 +16,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/color-computed.test.ts b/test/bundler/css/wpt/color-computed.test.ts index b1a0731ee175..d71e647fefe7 100644 --- a/test/bundler/css/wpt/color-computed.test.ts +++ b/test/bundler/css/wpt/color-computed.test.ts @@ -15,7 +15,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { color: ${expected}; } diff --git a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts index 64669d3e18d9..18c5e65d2d24 100644 --- a/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts +++ b/test/bundler/css/wpt/relative_color_out_of_gamut.test.ts @@ -17,7 +17,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` -/* ../../a.css */ +/* a.css */ h1 { color: #00f942; } @@ -38,7 +38,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lab(100 104.3 -50.9) r g b); } @@ -59,7 +59,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lab(0 104.3 -50.9) r g b); } @@ -80,7 +80,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lch(100 116 334) r g b); } @@ -101,7 +101,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from lch(0 116 334) r g b); } @@ -122,7 +122,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklab(1 .365 -.16) r g b); } @@ -143,7 +143,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklab(0 .365 -.16) r g b); } @@ -164,7 +164,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklch(1 .399 336.3) r g b); } @@ -185,7 +185,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: rgb(from oklch(0 .399 336.3) r g b); } @@ -206,7 +206,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: #00f942; } @@ -227,7 +227,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lab(100 104.3 -50.9) h s l); } @@ -248,7 +248,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lab(0 104.3 -50.9) h s l); } @@ -269,7 +269,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lch(100 116 334) h s l); } @@ -290,7 +290,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from lch(0 116 334) h s l); } @@ -311,7 +311,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklab(1 .365 -.16) h s l); } @@ -332,7 +332,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklab(0 .365 -.16) h s l); } @@ -353,7 +353,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklch(1 .399 336.3) h s l); } @@ -374,7 +374,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hsl(from oklch(0 .399 336.3) h s l); } @@ -395,7 +395,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: #00f942; } @@ -416,7 +416,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lab(100 104.3 -50.9) h w b); } @@ -437,7 +437,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lab(0 104.3 -50.9) h w b); } @@ -458,7 +458,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lch(100 116 334) h w b); } @@ -479,7 +479,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from lch(0 116 334) h w b); } @@ -500,7 +500,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklab(1 .365 -.16) h w b); } @@ -521,7 +521,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklab(0 .365 -.16) h w b); } @@ -542,7 +542,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklch(1 .399 336.3) h w b); } @@ -563,7 +563,7 @@ h1 { onAfterBundle(api) { api.expectFile("/out.css").toEqualIgnoringWhitespace(` - /* ../../a.css */ + /* a.css */ h1 { color: hwb(from oklch(0 .399 336.3) h w b); } diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 13d9764c95c3..52a831568f65 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -649,13 +649,18 @@ function expectBundled( return (async () => { // Prepare virtual files with dedent applied for strings, preserve binary content as-is + // Use relative paths (strip leading /) to get consistent path comments in CSS output const virtualFiles: Record = {}; for (const [file, contents] of Object.entries(files)) { - virtualFiles[file] = typeof contents === "string" ? dedent(contents) : contents; + const relativePath = file.startsWith("/") ? file.slice(1) : file; + virtualFiles[relativePath] = typeof contents === "string" ? dedent(contents) : contents; } + // Convert entrypoints to relative paths too + const relativeEntryPoints = entryPoints.map(ep => (ep.startsWith("/") ? ep.slice(1) : ep)); + const build = await Bun.build({ - entrypoints: entryPoints, + entrypoints: relativeEntryPoints, files: virtualFiles, target, format,