oven-sh/bun

writing-bundler-tests

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

First seen Jan 22, 2026

Installation

$ npx skills add oven-sh/bun --skill writing-bundler-tests

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from oven-sh/bun.

npx skills add oven-sh/bun

Browse all from oven-sh/bun

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 95.9K
License LICENSE.md
Default branch main
Open issues 3,430
Status Active

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,455 B
  • docs SUMMARY.md 187 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 98 installs

SKILL.md

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