CLAUDE.md
test/CLAUDE.mdCLAUDE.md
Quality
97/100
Scores the file, not the repository.Length
1,041 words
16 headings · 12 code blocksRepository
95k
— · pushed 0 days agoLast changed
3 days ago
First indexed 3 days ago.1To run tests:23```sh4bun bd test <...test file>5```67To run a command with your debug build of Bun:89```sh10bun bd <...cmd>11```1213Note that compiling Bun may take up to 2.5 minutes. It is slow!1415**CRITICAL**: Do not use `bun test` to run tests. It will not have your changes. `bun bd test <...test file>` is the correct command, which compiles your code automatically.1617## Testing style1819Use `bun:test` with files that end in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. If it's a test/js/node/test/{parallel,sequential}/\*.js without a .test.extension, use `bun bd <file>` instead of `bun bd test <file>` since those expect exit code 0 and don't use bun's test runner.2021- **Do not write flaky tests**. Unless explicitly asked, **never wait for time to pass in tests**. Always wait for the condition to be met instead of waiting for an arbitrary amount of time. **Never use hardcoded port numbers**. Always use `port: 0` to get a random port.22- **Prefer concurrent tests over sequential tests**: When multiple tests in the same file spawn processes or write files, make them concurrent with `test.concurrent` or `describe.concurrent` unless it's very difficult to make them concurrent.2324### Spawning processes2526#### Spawning Bun in tests2728When spawning Bun processes, use `bunExe` and `bunEnv` from `harness`. This ensures the same build of Bun is used to run the test and ensures debug logging is silenced.2930##### Use `-e` for single-file tests3132```ts33import { bunEnv, bunExe, tempDir } from "harness";34import { test, expect } from "bun:test";3536test("single-file test spawns a Bun process", async () => {37 await using proc = Bun.spawn({38 cmd: [bunExe(), "-e", "console.log('Hello, world!')"],39 env: bunEnv,40 });4142 const [stdout, stderr, exitCode] = await Promise.all([43 proc.stdout.text(),44 proc.stderr.text(),45 proc.exited,46 ]);4748 expect(stderr).toBe("");49 expect(stdout).toBe("Hello, world!\n");50 expect(exitCode).toBe(0);51});52```5354##### When multi-file tests are required:5556```ts57import { bunEnv, bunExe, tempDir } from "harness";58import { test, expect } from "bun:test";5960test("multi-file test spawns a Bun process", async () => {61 // If a test MUST use multiple files:62 using dir = tempDir("my-test-prefix", {63 "my.fixture.ts": `64 import { foo } from "./foo.ts";65 foo();66 `,67 "foo.ts": `68 export function foo() {69 console.log("Hello, world!");70 }71 `,72 });7374 await using proc = Bun.spawn({75 cmd: [bunExe(), "my.fixture.ts"],76 env: bunEnv,77 cwd: String(dir),78 });7980 const [stdout, stderr, exitCode] = await Promise.all([8182 // ReadableStream in Bun supports:83 // - `await stream.text()`84 // - `await stream.json()`85 // - `await stream.bytes()`86 // - `await stream.blob()`87 proc.stdout.text(),88 proc.stderr.text(),8990 proc.exitCode,91 ]);9293 expect(stdout).toBe("Hello, world!");94 expect(stderr).toBe("");95 expect(exitCode).toBe(0);96```9798When a test file spawns a Bun process, we like for that file to end in `*-fixture.ts`. This is a convention that helps us identify the file as a test fixture and not a test itself.99100Generally, `await using` or `using` is a good idea to ensure proper resource cleanup. This works in most Bun APIs like Bun.listen, Bun.connect, Bun.spawn, Bun.serve, etc.101102#### Async/await in tests103104Prefer async/await over callbacks.105106When callbacks must be used and it's just a single callback, use `Promise.withResolvers` to create a promise that can be resolved or rejected from a callback.107108```ts109const ws = new WebSocket("ws://localhost:8080");110const { promise, resolve, reject } = Promise.withResolvers<void>(); // Can specify any type here for resolution value111ws.onopen = resolve;112ws.onclose = reject;113await promise;114```115116If it's several callbacks, it's okay to use callbacks. We aren't a stickler for this.117118### No timeouts119120**CRITICAL**: Do not set a timeout on tests. Bun already has timeouts.121122### Use port 0 to get a random port123124Most APIs in Bun support `port: 0` to get a random port. Never hardcode ports. Avoid using your own random port number function.125126### Creating temporary files127128Use `tempDirWithFiles` to create a temporary directory with files.129130```ts131import { tempDir } from "harness";132import path from "node:path";133134test("creates a temporary directory with files", () => {135 using dir = tempDir("my-test-prefix", {136 "file.txt": "Hello, world!",137 });138139 expect(await Bun.file(path.join(String(dir), "file.txt")).text()).toBe(140 "Hello, world!",141 );142});143```144145### Strings146147To create a repetitive string, use `Buffer.alloc(count, fill).toString()` instead of `"A".repeat(count)`. "".repeat is very slow in debug JavaScriptCore builds.148149### Test Organization150151- Use `describe` blocks for grouping related tests152- **Add tests to the existing test file for the code you're changing** — do not create a new file. Tests are organized by module (e.g., `/test/js/bun/`, `/test/js/node/`, `/test/js/web/`).153- `/test/regression/issue/${issueNumber}.test.ts` is **only** for bugs that have a GitHub issue number **and** are true regressions (worked in a previous release, then broke). An issue number alone does not qualify — if it was never correct, put the test in the module's existing test file instead.154- Integration tests are in `/test/integration/`155156### Nested/complex object equality157158Prefer usage of `.toEqual` rather than many `.toBe` assertions for nested or complex objects.159160<example>161162BAD (try to avoid doing this):163164```ts165expect(result).toHaveLength(3);166expect(result[0].optional).toBe(null);167expect(result[1].optional).toBe("middle-value"); // CRITICAL: middle item's value must be preserved168expect(result[2].optional).toBe(null);169```170171**GOOD (always prefer this):**172173```ts174expect(result).toEqual([175 { optional: null },176 { optional: "middle-value" }, // CRITICAL: middle item's value must be preserved177 { optional: null },178]);179```180181</example>182183### Common Imports from `harness`184185```ts186import {187 bunExe, // Path to Bun executable188 bunEnv, // Environment variables for Bun189 tempDirWithFiles, // Create temporary test directories with files190 tmpdirSync, // Create empty temporary directory191 isMacOS, // Platform checks192 isWindows,193 isPosix,194 gcTick, // Trigger garbage collection195 withoutAggressiveGC, // Disable aggressive GC for performance tests196} from "harness";197```198199### Error Testing200201Always check exit codes and test error scenarios:202203```ts204test("handles errors", async () => {205 await using proc = Bun.spawn({206 cmd: [bunExe(), "run", "invalid.js"],207 env: bunEnv,208 });209210 const exitCode = await proc.exited;211 expect(exitCode).not.toBe(0);212213 // For synchronous errors214 expect(() => someFunction()).toThrow("Expected error message");215});216```217218### Avoid dynamic import & require219220**Only** use dynamic import or require when the test is specifically testing something relataed to dynamic import or require. Otherwise, **always use module-scope import statements**.221222**BAD, do not do this**:223224```ts225test("foo", async () => {226 // BAD: Unnecessary usage of dynamic import.227 const { readFile } = await import("node:fs");228229 expect(await readFile("ok.txt")).toBe("");230});231```232233**GOOD, do this:**234235```ts236import { readFile } from "node:fs";237test("foo", async () => {238 expect(await readFile("ok.txt")).toBe("");239});240```241242### Test Utilities243244- Use `describe.each()` for parameterized tests245- Use `toMatchSnapshot()` for snapshot testing246- Use `beforeAll()`, `afterEach()`, `beforeEach()` for setup/teardown247- Track resources (servers, clients) in arrays for cleanup in `afterEach()`248
Also in oven-sh/bun
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| oven-sh/bun.github/workflows/CLAUDE.md · 95k | CLAUDE.md | testlint-formatarchgit+2 | 81/100 | yesterday | |
| oven-sh/bunCLAUDE.md · 95k | CLAUDE.md | buildteststylearch+3 | 96/100 | 3 days ago | |
| oven-sh/bunscripts/verify-baseline-static/CLAUDE.md · 95k | CLAUDE.md | buildtesting-strategy | 65/100 | 3 days ago | |
| oven-sh/bunsrc/CLAUDE.md · 95k | CLAUDE.md | setupbuildstyletypes+2 | 76/100 | 3 days ago | |
| oven-sh/bunsrc/js/CLAUDE.md · 95k | CLAUDE.md | buildarchdo-not | 85/100 | 3 days ago | |
| oven-sh/bunsrc/jsc/bindings/v8/AGENTS.md · 95k | AGENTS.md | buildtestarchtesting-strategy+4 | 81/100 | 3 days ago | |
| oven-sh/bunsrc/jsc/bindings/v8/CLAUDE.md · 95k | CLAUDE.md | buildtestarchtesting-strategy+4 | 81/100 | 3 days ago | |
| oven-sh/buntest/js/node/test/parallel/CLAUDE.md · 95k | CLAUDE.md | test | 43/100 | 3 days ago |
Diff against .github/workflows/CLAUDE.md Diff against CLAUDE.md Diff against scripts/verify-baseline-static/CLAUDE.md Diff against src/CLAUDE.md Diff against src/js/CLAUDE.md Diff against src/jsc/bindings/v8/AGENTS.md Diff against src/jsc/bindings/v8/CLAUDE.md Diff against test/js/node/test/parallel/CLAUDE.md
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| livewire/livewireCLAUDE.md · 24k | CLAUDE.md | setupbuildteststyle+4 | 100/100 | 3 days ago | |
| bagisto/bagistoCLAUDE.md · 28k | CLAUDE.md | setupbuildteststyle+5 | 100/100 | 3 days ago | |
| nimbalyst/nimbalystpackages/android/CLAUDE.md · 1.4k | CLAUDE.md | setupbuildstylearch+2 | 100/100 | 3 days ago | |
| dotCMS/corecore-web/CLAUDE.md · 950 | CLAUDE.md | teststylearchtesting-strategy+3 | 100/100 | 3 days ago | |
| Adit-Jain-srm/NightmareNetCLAUDE.md · 45 | CLAUDE.md | buildtestlint-formatstyle+6 | 100/100 | 3 days ago | |
| filamentphp/filamentCLAUDE.md · 32k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 3 days ago | |
| microsoft/playwrightCLAUDE.md · 94k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 3 days ago | |
| dotCMS/coreCLAUDE.md · 950 | CLAUDE.md | setupbuildteststyle+7 | 99/100 | 3 days ago |
