CtrlK
BlogDocsLog inGet started
Tessl Logo

writing-bundler-tests

Guides writing bundler tests using itBundled/expectBundled in test/bundler/. Use when creating or modifying bundler, transpiler, or code transformation tests.

70

Quality

85%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Writing Bundler Tests

Bundler tests use itBundled() from test/bundler/expectBundled.ts to test Bun's bundler.

Basic Usage

import { describe } from "bun:test";
import { itBundled, dedent } from "./expectBundled";

describe("bundler", () => {
  itBundled("category/TestName", {
    files: {
      "index.js": `console.log("hello");`,
    },
    run: {
      stdout: "hello",
    },
  });
});

Test ID format: category/TestName (e.g., banner/CommentBanner, minify/Empty)

File Setup

{
  files: {
    "index.js": `console.log("test");`,
    "lib.ts": `export const foo = 123;`,
    "nested/file.js": `export default {};`,
  },
  entryPoints: ["index.js"],  // defaults to first file
  runtimeFiles: {             // written AFTER bundling
    "extra.js": `console.log("added later");`,
  },
}

Bundler Options

{
  outfile: "/out.js",
  outdir: "/out",
  format: "esm" | "cjs" | "iife",
  target: "bun" | "browser" | "node",

  // Minification
  minifyWhitespace: true,
  minifyIdentifiers: true,
  minifySyntax: true,

  // Code manipulation
  banner: "// copyright",
  footer: "// end",
  define: { "PROD": "true" },
  external: ["lodash"],

  // Advanced
  sourceMap: "inline" | "external",
  splitting: true,
  treeShaking: true,
  drop: ["console"],
}

Runtime Verification

{
  run: {
    stdout: "expected output",      // exact match
    stdout: /regex/,                // pattern match
    partialStdout: "contains this", // substring
    stderr: "error output",
    exitCode: 1,
    env: { NODE_ENV: "production" },
    runtime: "bun" | "node",

    // Runtime errors
    error: "ReferenceError: x is not defined",
  },
}

Bundle Errors/Warnings

{
  bundleErrors: {
    "/file.js": ["error message 1", "error message 2"],
  },
  bundleWarnings: {
    "/file.js": ["warning message"],
  },
}

Dead Code Elimination (DCE)

Add markers in source code:

// KEEP - this should survive
const used = 1;

// REMOVE - this should be eliminated
const unused = 2;
{
  dce: true,
  dceKeepMarkerCount: 5,  // expected KEEP markers
}

Capture Pattern

Verify exact transpilation with capture():

itBundled("string/Folding", {
  files: {
    "index.ts": `capture(\`\${1 + 1}\`);`,
  },
  capture: ['"2"'], // expected captured value
  minifySyntax: true,
});

Post-Bundle Assertions

{
  onAfterBundle(api) {
    api.expectFile("out.js").toContain("console.log");
    api.assertFileExists("out.js");

    const content = api.readFile("out.js");
    expect(content).toMatchSnapshot();

    const values = api.captureFile("out.js");
    expect(values).toEqual(["2"]);
  },
}

Common Patterns

Simple output verification:

itBundled("banner/Comment", {
  banner: "// copyright",
  files: { "a.js": `console.log("Hello")` },
  onAfterBundle(api) {
    api.expectFile("out.js").toContain("// copyright");
  },
});

Multi-file CJS/ESM interop:

itBundled("cjs/ImportSyntax", {
  files: {
    "entry.js": `import lib from './lib.cjs'; console.log(lib);`,
    "lib.cjs": `exports.foo = 'bar';`,
  },
  run: { stdout: '{"foo":"bar"}' },
});

Error handling:

itBundled("edgecase/InvalidLoader", {
  files: { "index.js": `...` },
  bundleErrors: {
    "index.js": ["Unsupported loader type"],
  },
});

Test Organization

test/bundler/
├── bundler_banner.test.ts
├── bundler_string.test.ts
├── bundler_minify.test.ts
├── bundler_cjs.test.ts
├── bundler_edgecase.test.ts
├── bundler_splitting.test.ts
├── css/
├── transpiler/
└── expectBundled.ts

Running Tests

bun bd test test/bundler/bundler_banner.test.ts
BUN_BUNDLER_TEST_FILTER="banner/Comment" bun bd test bundler_banner.test.ts
BUN_BUNDLER_TEST_DEBUG=1 bun bd test bundler_minify.test.ts

Key Points

  • Use dedent for readable multi-line code
  • File paths are relative (e.g., /index.js)
  • Use capture() to verify exact transpilation results
  • Use .toMatchSnapshot() for complex outputs
  • Pass array to run for multiple test scenarios
Repository
oven-sh/bun
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.