RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/oven-sh-bun-test-claude ↔ oven-sh-bun-github-workflows-claude

Comparison

A · CLAUDE.md · oven-sh/bunB · CLAUDE.md · oven-sh/bun
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections012130%
Commands0530%
Section tags13511%

What each file covers

Sections

0 shared · 12 only in A · 13 only in B
  • − Testing style
  • − Spawning processes
  • − No timeouts
  • − Use port 0 to get a random port
  • − Creating temporary files
  • − Strings
  • − Test Organization
  • − Nested/complex object equality
  • − Common Imports from `harness`
  • − Error Testing
  • − Avoid dynamic import & require
  • − Test Utilities
  • + GitHub Actions Workflow Maintenance Guide
  • + format.yml Workflow
  • + Overview
  • + Key Components
  • + Updating the Workflow
  • + Performance Optimizations
  • + Troubleshooting
  • + Testing Changes Locally
  • + Test the clang-format script
  • + Test with check mode (no modifications)
  • + Test specific file exclusions
  • + Should return nothing if exclusions work correctly
  • + Important Notes

Commands

0 shared · 5 only in A · 3 only in B
  • − bun bd test <...test file>
  • − bun bd <...cmd>
  • − bun:test
  • − bun bd <file>
  • − bun bd test <file>
  • + cargo fmt
  • + bun scripts/glob-sources.ts cxx
  • + cargo fmt --all

Section tags

1 shared · 3 only in A · 5 only in B
  • − code-style
  • − testing-strategy
  • − do-not
  • + lint-format
  • + architecture
  • + git-pr
  • + performance
  • + agent-behaviour
  •   test

Line diff

+75 added−207 removed41 unchanged16.5% identical
oven-sh/bun · test/CLAUDE.md
@@ −1 @@
1To run tests:
2 
3```sh
4bun bd test <...test file>
5```
6 
7To run a command with your debug build of Bun:
8 
9```sh
10bun bd <...cmd>
11```
12 
13Note that compiling Bun may take up to 2.5 minutes. It is slow!
14 
15**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.
16 
17## Testing style
18 
19Use `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.
 
 
 
 
 
20 
21- **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.
23 
24### Spawning processes
 
 
 
 
 
25 
26#### Spawning Bun in tests
27 
28When 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.
29 
30##### Use `-e` for single-file tests
 
 
31 
32```ts
33import { bunEnv, bunExe, tempDir } from "harness";
34import { test, expect } from "bun:test";
35 
36test("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 });
41 
42 const [stdout, stderr, exitCode] = await Promise.all([
43 proc.stdout.text(),
44 proc.stderr.text(),
45 proc.exited,
46 ]);
47 
48 expect(stderr).toBe("");
49 expect(stdout).toBe("Hello, world!\n");
50 expect(exitCode).toBe(0);
51});
52```
53 
54##### When multi-file tests are required:
 
55 
56```ts
57import { bunEnv, bunExe, tempDir } from "harness";
58import { test, expect } from "bun:test";
59 
60test("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 });
73 
74 await using proc = Bun.spawn({
75 cmd: [bunExe(), "my.fixture.ts"],
76 env: bunEnv,
77 cwd: String(dir),
78 });
79 
80 const [stdout, stderr, exitCode] = await Promise.all([
81 
82 // 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(),
89 
90 proc.exitCode,
91 ]);
92 
93 expect(stdout).toBe("Hello, world!");
94 expect(stderr).toBe("");
95 expect(exitCode).toBe(0);
96```
97 
98When 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.
99 
100Generally, `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.
 
 
 
101 
102#### Async/await in tests
103 
104Prefer async/await over callbacks.
105 
106When 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.
 
107 
108```ts
109const ws = new WebSocket("ws://localhost:8080");
110const { promise, resolve, reject } = Promise.withResolvers<void>(); // Can specify any type here for resolution value
111ws.onopen = resolve;
112ws.onclose = reject;
113await promise;
114```
115 
116If it's several callbacks, it's okay to use callbacks. We aren't a stickler for this.
 
117 
118### No timeouts
119 
120**CRITICAL**: Do not set a timeout on tests. Bun already has timeouts.
 
 
121 
122### Use port 0 to get a random port
123 
124Most APIs in Bun support `port: 0` to get a random port. Never hardcode ports. Avoid using your own random port number function.
 
 
 
125 
126### Creating temporary files
 
127 
128Use `tempDirWithFiles` to create a temporary directory with files.
129 
130```ts
131import { tempDir } from "harness";
132import path from "node:path";
133 
134test("creates a temporary directory with files", () => {
135 using dir = tempDir("my-test-prefix", {
136 "file.txt": "Hello, world!",
137 });
138 
139 expect(await Bun.file(path.join(String(dir), "file.txt")).text()).toBe(
140 "Hello, world!",
141 );
142});
143```
144 
145### Strings
146 
147To create a repetitive string, use `Buffer.alloc(count, fill).toString()` instead of `"A".repeat(count)`. "".repeat is very slow in debug JavaScriptCore builds.
148 
149### Test Organization
150 
151- Use `describe` blocks for grouping related tests
152- **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/`
155 
156### Nested/complex object equality
157 
158Prefer usage of `.toEqual` rather than many `.toBe` assertions for nested or complex objects.
159 
160<example>
161 
162BAD (try to avoid doing this):
163 
164```ts
165expect(result).toHaveLength(3);
166expect(result[0].optional).toBe(null);
167expect(result[1].optional).toBe("middle-value"); // CRITICAL: middle item's value must be preserved
168expect(result[2].optional).toBe(null);
169```
170 
171**GOOD (always prefer this):**
172 
173```ts
174expect(result).toEqual([
175 { optional: null },
176 { optional: "middle-value" }, // CRITICAL: middle item's value must be preserved
177 { optional: null },
178]);
179```
180 
181</example>
182 
183### Common Imports from `harness`
184 
185```ts
186import {
187 bunExe, // Path to Bun executable
188 bunEnv, // Environment variables for Bun
189 tempDirWithFiles, // Create temporary test directories with files
190 tmpdirSync, // Create empty temporary directory
191 isMacOS, // Platform checks
192 isWindows,
193 isPosix,
194 gcTick, // Trigger garbage collection
195 withoutAggressiveGC, // Disable aggressive GC for performance tests
196} from "harness";
197```
198 
199### Error Testing
200 
201Always check exit codes and test error scenarios:
202 
203```ts
204test("handles errors", async () => {
205 await using proc = Bun.spawn({
206 cmd: [bunExe(), "run", "invalid.js"],
207 env: bunEnv,
208 });
209 
210 const exitCode = await proc.exited;
211 expect(exitCode).not.toBe(0);
212 
213 // For synchronous errors
214 expect(() => someFunction()).toThrow("Expected error message");
215});
216```
217 
218### Avoid dynamic import & require
219 
220**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**.
221 
222**BAD, do not do this**:
223 
224```ts
225test("foo", async () => {
226 // BAD: Unnecessary usage of dynamic import.
227 const { readFile } = await import("node:fs");
228 
229 expect(await readFile("ok.txt")).toBe("");
230});
231```
232 
233**GOOD, do this:**
234 
235```ts
236import { readFile } from "node:fs";
237test("foo", async () => {
238 expect(await readFile("ok.txt")).toBe("");
239});
240```
241 
242### Test Utilities
243 
244- Use `describe.each()` for parameterized tests
245- Use `toMatchSnapshot()` for snapshot testing
246- Use `beforeAll()`, `afterEach()`, `beforeEach()` for setup/teardown
247- Track resources (servers, clients) in arrays for cleanup in `afterEach()`
248 
oven-sh/bun · .github/workflows/CLAUDE.md
@@ +1 @@
1# GitHub Actions Workflow Maintenance Guide
2 
3This document provides guidance for maintaining the GitHub Actions workflows in this repository.
 
 
4 
5## format.yml Workflow
6 
7### Overview
 
 
8 
9The `format.yml` workflow runs code formatters (Prettier, clang-format, and `cargo fmt`) on pull requests and pushes to main. It's optimized for speed by running all formatters in parallel.
10 
11### Key Components
12 
13#### 1. Clang-format Script (`scripts/run-clang-format.sh`)
14 
15- **Purpose**: Formats C++ source and header files
16- **What it does**:
17 - Globs C++ files via `bun scripts/glob-sources.ts cxx`
18 - Finds all header files in `src/` and `packages/`
19 - Excludes third-party directories (libuv, napi, deps, vendor, sqlite, etc.)
20 - Requires specific clang-format version (no fallbacks)
21 
22**Important exclusions**:
 
23 
24- `src/runtime/napi/` - Node API headers (third-party)
25- `src/jsc/bindings/libuv/` - libuv headers (third-party)
26- `src/jsc/bindings/sqlite/` - SQLite headers (third-party)
27- `src/runtime/ffi/ffi-*.h` - FFI headers (generated/third-party)
28- `src/deps/` - Dependencies (third-party)
29- Files in `vendor/`, `third_party/`, `generated/` directories
30 
31#### 2. Parallel Execution
32 
33The workflow runs all three formatters simultaneously:
34 
35- Each formatter outputs with a prefix (`[prettier]`, `[clang-format]`, `[rustfmt]`)
36- Output is streamed in real-time without blocking
37- Uses GitHub Actions groups (`::group::`) for collapsible sections
38 
39#### 3. Tool Installation
 
 
40 
41##### Clang-format-21
 
 
 
 
42 
43- Installs ONLY `clang-format-21` package (not the entire LLVM toolchain)
44- Uses `--no-install-recommends --no-install-suggests` to skip unnecessary packages
45- Quiet installation with `-qq` and `-o=Dpkg::Use-Pty=0`
 
 
46 
47##### Rustfmt
 
 
 
 
48 
49- The pinned nightly is set via `RUSTUP_TOOLCHAIN` in the step `env:` (kept in sync with `channel` in `rust-toolchain.toml`); `cargo fmt --all` runs against the workspace at the repo root.
50- `RUSTUP_TOOLCHAIN` makes rustup ignore `rust-toolchain.toml` entirely, so the workflow installs only the host toolchain + `rustfmt` (`rustup toolchain install --profile minimal --component rustfmt`) rather than the file's full cross-target list.
51 
52### Updating the Workflow
 
 
53 
54#### To update the Rust toolchain:
 
 
 
 
 
 
 
 
 
 
 
 
55 
561. Bump `channel` in `rust-toolchain.toml` (and `Dockerfile`/`bootstrap.sh` to match).
572. Bump `RUSTUP_TOOLCHAIN` in the `Format Code` step's `env:` block in `format.yml` to the same value.
583. Bump `RUSTUP_TOOLCHAIN` in the workflow-level `env:` block in `clippy.yml`, `miri.yml`, and `lolhtml.yml` to the same value.
594. `cargo fmt` formatting can change between nightlies; run `cargo fmt --all` locally on the new toolchain and include the resulting diff in the same PR.
 
60 
61#### To update clang-format version:
62 
631. Update `LLVM_VERSION_MAJOR` environment variable at the top of format.yml
642. Update the version check in `scripts/run-clang-format.sh`
 
 
 
 
 
65 
66#### To add/remove file exclusions:
 
67 
681. Edit the exclusion patterns in `scripts/run-clang-format.sh` (lines 34-39)
692. Test locally to ensure the right files are being formatted
 
 
70 
71### Performance Optimizations
72 
731. **Parallel execution**: All formatters run simultaneously
742. **Minimal installations**: Only required packages, no extras
753. **Streaming output**: Real-time feedback without buffering
764. **Early start**: Formatting begins immediately after each tool is ready
77 
78### Troubleshooting
79 
80**If formatters appear to run sequentially:**
81 
82- Check if output is being buffered (should use `sed` for line prefixing)
83- Ensure background processes use `&` and proper wait commands
84 
85**If third-party files are being formatted:**
 
 
 
 
 
 
86 
87- Review exclusion patterns in `scripts/run-clang-format.sh`
88- Check if new third-party directories were added that need exclusion
89 
90**If clang-format installation is slow:**
91 
92- Ensure using minimal package installation flags
93- Check if apt cache needs updating
94- Consider caching the clang-format binary between runs
95 
96### Testing Changes Locally
97 
98```bash
99# Test the clang-format script
100export LLVM_VERSION_MAJOR=19
101./scripts/run-clang-format.sh format
102 
103# Test with check mode (no modifications)
104./scripts/run-clang-format.sh check
105 
106# Test specific file exclusions
107./scripts/run-clang-format.sh format 2>&1 | grep -E "(libuv|napi|deps)"
108# Should return nothing if exclusions work correctly
 
 
 
 
 
 
 
 
 
 
 
 
109```
110 
111### Important Notes
112 
113- The script defaults to **format** mode (modifies files)
114- Always test locally before pushing workflow changes
115- Keep the exclusion list updated as new third-party code is added
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116 
@@ −1 +1 @@
1−To run tests:
1+# GitHub Actions Workflow Maintenance Guide
22  
3−```sh
4−bun bd test <...test file>
5−```
3+This document provides guidance for maintaining the GitHub Actions workflows in this repository.
64  
7−To run a command with your debug build of Bun:
5+## format.yml Workflow
86  
9−```sh
10−bun bd <...cmd>
11−```
7+### Overview
128  
13−Note that compiling Bun may take up to 2.5 minutes. It is slow!
9+The `format.yml` workflow runs code formatters (Prettier, clang-format, and `cargo fmt`) on pull requests and pushes to main. It's optimized for speed by running all formatters in parallel.
1410  
15−**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.
11+### Key Components
1612  
17−## Testing style
13+#### 1. Clang-format Script (`scripts/run-clang-format.sh`)
1814  
19−Use `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.
15+- **Purpose**: Formats C++ source and header files
16+- **What it does**:
17+ - Globs C++ files via `bun scripts/glob-sources.ts cxx`
18+ - Finds all header files in `src/` and `packages/`
19+ - Excludes third-party directories (libuv, napi, deps, vendor, sqlite, etc.)
20+ - Requires specific clang-format version (no fallbacks)
2021  
21−- **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.
22+**Important exclusions**:
2323  
24−### Spawning processes
24+- `src/runtime/napi/` - Node API headers (third-party)
25+- `src/jsc/bindings/libuv/` - libuv headers (third-party)
26+- `src/jsc/bindings/sqlite/` - SQLite headers (third-party)
27+- `src/runtime/ffi/ffi-*.h` - FFI headers (generated/third-party)
28+- `src/deps/` - Dependencies (third-party)
29+- Files in `vendor/`, `third_party/`, `generated/` directories
2530  
26−#### Spawning Bun in tests
31+#### 2. Parallel Execution
2732  
28−When 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.
33+The workflow runs all three formatters simultaneously:
2934  
30−##### Use `-e` for single-file tests
35+- Each formatter outputs with a prefix (`[prettier]`, `[clang-format]`, `[rustfmt]`)
36+- Output is streamed in real-time without blocking
37+- Uses GitHub Actions groups (`::group::`) for collapsible sections
3138  
32−```ts
33−import { bunEnv, bunExe, tempDir } from "harness";
34−import { test, expect } from "bun:test";
39+#### 3. Tool Installation
3540  
36−test("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− });
41+##### Clang-format-21
4142  
42− const [stdout, stderr, exitCode] = await Promise.all([
43− proc.stdout.text(),
44− proc.stderr.text(),
45− proc.exited,
46− ]);
43+- Installs ONLY `clang-format-21` package (not the entire LLVM toolchain)
44+- Uses `--no-install-recommends --no-install-suggests` to skip unnecessary packages
45+- Quiet installation with `-qq` and `-o=Dpkg::Use-Pty=0`
4746  
48− expect(stderr).toBe("");
49− expect(stdout).toBe("Hello, world!\n");
50− expect(exitCode).toBe(0);
51−});
52−```
47+##### Rustfmt
5348  
54−##### When multi-file tests are required:
49+- The pinned nightly is set via `RUSTUP_TOOLCHAIN` in the step `env:` (kept in sync with `channel` in `rust-toolchain.toml`); `cargo fmt --all` runs against the workspace at the repo root.
50+- `RUSTUP_TOOLCHAIN` makes rustup ignore `rust-toolchain.toml` entirely, so the workflow installs only the host toolchain + `rustfmt` (`rustup toolchain install --profile minimal --component rustfmt`) rather than the file's full cross-target list.
5551  
56−```ts
57−import { bunEnv, bunExe, tempDir } from "harness";
58−import { test, expect } from "bun:test";
52+### Updating the Workflow
5953  
60−test("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− });
54+#### To update the Rust toolchain:
7355  
74− await using proc = Bun.spawn({
75− cmd: [bunExe(), "my.fixture.ts"],
76− env: bunEnv,
77− cwd: String(dir),
78− });
56+1. Bump `channel` in `rust-toolchain.toml` (and `Dockerfile`/`bootstrap.sh` to match).
57+2. Bump `RUSTUP_TOOLCHAIN` in the `Format Code` step's `env:` block in `format.yml` to the same value.
58+3. Bump `RUSTUP_TOOLCHAIN` in the workflow-level `env:` block in `clippy.yml`, `miri.yml`, and `lolhtml.yml` to the same value.
59+4. `cargo fmt` formatting can change between nightlies; run `cargo fmt --all` locally on the new toolchain and include the resulting diff in the same PR.
7960  
80− const [stdout, stderr, exitCode] = await Promise.all([
61+#### To update clang-format version:
8162  
82− // 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(),
63+1. Update `LLVM_VERSION_MAJOR` environment variable at the top of format.yml
64+2. Update the version check in `scripts/run-clang-format.sh`
8965  
90− proc.exitCode,
91− ]);
66+#### To add/remove file exclusions:
9267  
93− expect(stdout).toBe("Hello, world!");
94− expect(stderr).toBe("");
95− expect(exitCode).toBe(0);
96−```
68+1. Edit the exclusion patterns in `scripts/run-clang-format.sh` (lines 34-39)
69+2. Test locally to ensure the right files are being formatted
9770  
98−When 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.
71+### Performance Optimizations
9972  
100−Generally, `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.
73+1. **Parallel execution**: All formatters run simultaneously
74+2. **Minimal installations**: Only required packages, no extras
75+3. **Streaming output**: Real-time feedback without buffering
76+4. **Early start**: Formatting begins immediately after each tool is ready
10177  
102−#### Async/await in tests
78+### Troubleshooting
10379  
104−Prefer async/await over callbacks.
80+**If formatters appear to run sequentially:**
10581  
106−When 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.
82+- Check if output is being buffered (should use `sed` for line prefixing)
83+- Ensure background processes use `&` and proper wait commands
10784  
108−```ts
109−const ws = new WebSocket("ws://localhost:8080");
110−const { promise, resolve, reject } = Promise.withResolvers<void>(); // Can specify any type here for resolution value
111−ws.onopen = resolve;
112−ws.onclose = reject;
113−await promise;
114−```
85+**If third-party files are being formatted:**
11586  
116−If it's several callbacks, it's okay to use callbacks. We aren't a stickler for this.
87+- Review exclusion patterns in `scripts/run-clang-format.sh`
88+- Check if new third-party directories were added that need exclusion
11789  
118−### No timeouts
90+**If clang-format installation is slow:**
11991  
120−**CRITICAL**: Do not set a timeout on tests. Bun already has timeouts.
92+- Ensure using minimal package installation flags
93+- Check if apt cache needs updating
94+- Consider caching the clang-format binary between runs
12195  
122−### Use port 0 to get a random port
96+### Testing Changes Locally
12397  
124−Most APIs in Bun support `port: 0` to get a random port. Never hardcode ports. Avoid using your own random port number function.
98+```bash
99+# Test the clang-format script
100+export LLVM_VERSION_MAJOR=19
101+./scripts/run-clang-format.sh format
125102  
126−### Creating temporary files
103+# Test with check mode (no modifications)
104+./scripts/run-clang-format.sh check
127105  
128−Use `tempDirWithFiles` to create a temporary directory with files.
129− 
130−```ts
131−import { tempDir } from "harness";
132−import path from "node:path";
133− 
134−test("creates a temporary directory with files", () => {
135− using dir = tempDir("my-test-prefix", {
136− "file.txt": "Hello, world!",
137− });
138− 
139− expect(await Bun.file(path.join(String(dir), "file.txt")).text()).toBe(
140− "Hello, world!",
141− );
142−});
106+# Test specific file exclusions
107+./scripts/run-clang-format.sh format 2>&1 | grep -E "(libuv|napi|deps)"
108+# Should return nothing if exclusions work correctly
143109 ```
144110  
145−### Strings
111+### Important Notes
146112  
147−To create a repetitive string, use `Buffer.alloc(count, fill).toString()` instead of `"A".repeat(count)`. "".repeat is very slow in debug JavaScriptCore builds.
148− 
149−### Test Organization
150− 
151−- Use `describe` blocks for grouping related tests
152−- **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/`
155− 
156−### Nested/complex object equality
157− 
158−Prefer usage of `.toEqual` rather than many `.toBe` assertions for nested or complex objects.
159− 
160−<example>
161− 
162−BAD (try to avoid doing this):
163− 
164−```ts
165−expect(result).toHaveLength(3);
166−expect(result[0].optional).toBe(null);
167−expect(result[1].optional).toBe("middle-value"); // CRITICAL: middle item's value must be preserved
168−expect(result[2].optional).toBe(null);
169−```
170− 
171−**GOOD (always prefer this):**
172− 
173−```ts
174−expect(result).toEqual([
175− { optional: null },
176− { optional: "middle-value" }, // CRITICAL: middle item's value must be preserved
177− { optional: null },
178−]);
179−```
180− 
181−</example>
182− 
183−### Common Imports from `harness`
184− 
185−```ts
186−import {
187− bunExe, // Path to Bun executable
188− bunEnv, // Environment variables for Bun
189− tempDirWithFiles, // Create temporary test directories with files
190− tmpdirSync, // Create empty temporary directory
191− isMacOS, // Platform checks
192− isWindows,
193− isPosix,
194− gcTick, // Trigger garbage collection
195− withoutAggressiveGC, // Disable aggressive GC for performance tests
196−} from "harness";
197−```
198− 
199−### Error Testing
200− 
201−Always check exit codes and test error scenarios:
202− 
203−```ts
204−test("handles errors", async () => {
205− await using proc = Bun.spawn({
206− cmd: [bunExe(), "run", "invalid.js"],
207− env: bunEnv,
208− });
209− 
210− const exitCode = await proc.exited;
211− expect(exitCode).not.toBe(0);
212− 
213− // For synchronous errors
214− expect(() => someFunction()).toThrow("Expected error message");
215−});
216−```
217− 
218−### Avoid dynamic import & require
219− 
220−**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**.
221− 
222−**BAD, do not do this**:
223− 
224−```ts
225−test("foo", async () => {
226− // BAD: Unnecessary usage of dynamic import.
227− const { readFile } = await import("node:fs");
228− 
229− expect(await readFile("ok.txt")).toBe("");
230−});
231−```
232− 
233−**GOOD, do this:**
234− 
235−```ts
236−import { readFile } from "node:fs";
237−test("foo", async () => {
238− expect(await readFile("ok.txt")).toBe("");
239−});
240−```
241− 
242−### Test Utilities
243− 
244−- Use `describe.each()` for parameterized tests
245−- Use `toMatchSnapshot()` for snapshot testing
246−- Use `beforeAll()`, `afterEach()`, `beforeEach()` for setup/teardown
247−- Track resources (servers, clients) in arrays for cleanup in `afterEach()`
113+- The script defaults to **format** mode (modifies files)
114+- Always test locally before pushing workflow changes
115+- Keep the exclusion list updated as new third-party code is added
248116  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack