-
Notifications
You must be signed in to change notification settings - Fork 3.8k
feat(test): export assert from bun:test #25130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Re-export node:assert as "assert" from bun:test for vitest
compatibility. This allows users to import { assert } from "bun:test"
and use Node.js assertion methods alongside Jest-style expect().
The assert function also works as a TypeScript type guard for type
narrowing, making it useful for refining union types in tests.
Add TypeScript type definition for the new assert export in bun:test. The type is a re-export of node:assert, providing full type support for all assertion methods including the type guard behaviour.
Add comprehensive tests verifying that all node:assert methods work correctly when imported from bun:test. Tests cover: - Basic assert() function - Equality methods (strictEqual, deepStrictEqual, etc.) - Error handling (throws, doesNotThrow, rejects, doesNotReject) - String matching (match, doesNotMatch) - Utility methods (fail, ifError, ok)
Add documentation explaining how to use the assert export from bun:test. Covers basic usage, type narrowing with TypeScript, available methods, and integration with expect().
WalkthroughAdds support for Node.js Changes
Suggested reviewers
Pre-merge checks❌ Failed checks (1 inconclusive)
✅ Passed checks (1 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
docs/guides/test/assert.mdx(1 hunks)packages/bun-types/test.d.ts(1 hunks)src/bun.js/bindings/ZigGlobalObject.cpp(1 hunks)test/js/bun/test/assert-export.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.{cpp,zig}
📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)
src/**/*.{cpp,zig}: Usebun bdorbun run build:debugto build debug versions for C++ and Zig source files; creates debug build at./build/debug/bun-debug
Run tests usingbun bd test <test-file>with the debug build; never usebun testdirectly as it will not include your changes
Execute files usingbun bd <file> <...args>; never usebun <file>directly as it will not include your changes
Enable debug logs for specific scopes usingBUN_DEBUG_$(SCOPE)=1environment variable
Code generation happens automatically as part of the build process; no manual code generation commands are required
Files:
src/bun.js/bindings/ZigGlobalObject.cpp
src/bun.js/bindings/**/*.cpp
📄 CodeRabbit inference engine (CLAUDE.md)
src/bun.js/bindings/**/*.cpp: C++ code for JavaScriptCore bindings and Web APIs should be placed insrc/bun.js/bindings/*.cpp
When implementing JavaScript classes in C++, create three classes if there's a public constructor:class Foo : public JSC::JSDestructibleObject,class FooPrototype : public JSC::JSNonFinalObject, andclass FooConstructor : public JSC::InternalFunction
When implementing JavaScript classes in C++, define properties using HashTableValue arrays and add iso subspaces for classes with C++ fields, caching structures in ZigGlobalObject
Files:
src/bun.js/bindings/ZigGlobalObject.cpp
src/**/*.{ts,zig,cpp}
📄 CodeRabbit inference engine (CLAUDE.md)
Always use absolute paths in file operations
Files:
src/bun.js/bindings/ZigGlobalObject.cpp
test/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)
test/**/*.{js,ts,jsx,tsx}: Write tests as JavaScript and TypeScript files using Jest-style APIs (test,describe,expect) and import frombun:test
Usetest.eachand data-driven tests to reduce boilerplate when testing multiple similar cases
Files:
test/js/bun/test/assert-export.test.ts
test/js/bun/**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
For Bun-specific API tests, use the
test/js/bun/directory (for http, crypto, ffi, shell, etc.)
Files:
test/js/bun/test/assert-export.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: For single-file tests, prefer using-eflag overtempDir
For multi-file tests, prefer usingtempDirfromharnessandBun.spawnover other temporary directory creation methods
Always useport: 0for network tests and do not hardcode ports or use custom random port number functions
UsenormalizeBunSnapshotto normalize snapshot output of tests
Never write tests that check for no 'panic' or 'uncaught exception' or similar in the test output - that is NOT a valid test
UsetempDirfromharnessto create temporary directories, do not usetmpdirSyncorfs.mkdtempSync
When spawning processes in tests, check stdout/stderr expectations BEFORE checking exit code to get more useful error messages on test failure
Do not write flaky tests - do not usesetTimeoutin tests, insteadawaitthe condition to be met as you are testing the CONDITION not the TIME PASSING
Verify your test fails withUSE_SYSTEM_BUN=1 bun test <file>and passes withbun bd test <file>- your test is NOT VALID if it passes withUSE_SYSTEM_BUN=1
Files:
test/js/bun/test/assert-export.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}
📄 CodeRabbit inference engine (test/CLAUDE.md)
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Usebun:testwith files that end in*.test.{ts,js,jsx,tsx,mjs,cjs}
Do not write flaky tests. Never wait for time to pass in tests; always wait for the condition to be met instead of using an arbitrary amount of time
Never use hardcoded port numbers in tests. Always useport: 0to get a random port
Prefer concurrent tests over sequential tests usingtest.concurrentordescribe.concurrentwhen multiple tests spawn processes or write files, unless it's very difficult to make them concurrent
When spawning Bun processes in tests, usebunExeandbunEnvfromharnessto ensure the same build of Bun is used and debug logging is silenced
Use-eflag for single-file tests when spawning Bun processes
UsetempDir()from harness to create temporary directories with files for multi-file tests instead of creating files manually
Prefer async/await over callbacks in tests
When callbacks must be used and it's just a single callback, usePromise.withResolversto create a promise that can be resolved or rejected from a callback
Do not set a timeout on tests. Bun already has timeouts
UseBuffer.alloc(count, fill).toString()instead of'A'.repeat(count)to create repetitive strings in tests, as ''.repeat is very slow in debug JavaScriptCore builds
Usedescribeblocks for grouping related tests
Always useawait usingorusingto ensure proper resource cleanup in tests for APIs like Bun.listen, Bun.connect, Bun.spawn, Bun.serve, etc
Always check exit codes and test error scenarios in error tests
Usedescribe.each()for parameterized tests
UsetoMatchSnapshot()for snapshot testing
UsebeforeAll(),afterEach(),beforeEach()for setup/teardown in tests
Track resources (servers, clients) in arrays for cleanup inafterEach()
Files:
test/js/bun/test/assert-export.test.ts
🧠 Learnings (32)
📓 Common learnings
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:50.422Z
Learning: Applies to test/**/*.{js,ts,jsx,tsx} : Write tests as JavaScript and TypeScript files using Jest-style APIs (`test`, `describe`, `expect`) and import from `bun:test`
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/registering-bun-modules.mdc:0-0
Timestamp: 2025-11-24T18:35:39.205Z
Learning: Add tests for new Bun runtime functionality
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to **/*.test.{ts,tsx} : Verify your test fails with `USE_SYSTEM_BUN=1 bun test <file>` and passes with `bun bd test <file>` - your test is NOT VALID if it passes with `USE_SYSTEM_BUN=1`
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to test/js/bun/**/*.test.{ts,tsx} : For Bun-specific API tests, use the `test/js/bun/` directory (for http, crypto, ffi, shell, etc.)
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` with files that end in `*.test.{ts,js,jsx,tsx,mjs,cjs}`
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use `$debug()` for debug logging and `$assert()` for assertions; both are stripped in release builds
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Unit tests for specific features are organized by module (e.g., `/test/js/bun/`, `/test/js/node/`)
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/dev-server-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:08.612Z
Learning: Applies to test/bake/**/*.test.ts : Assert console messages using `c.expectMessage()` with single or multiple arguments; any unasserted logs fail the test to catch unexpected re-evaluations or reloads
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : When spawning Bun processes in tests, use `bunExe` and `bunEnv` from `harness` to ensure the same build of Bun is used and debug logging is silenced
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:35:50.422Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:50.422Z
Learning: Applies to test/**/*.{js,ts,jsx,tsx} : Write tests as JavaScript and TypeScript files using Jest-style APIs (`test`, `describe`, `expect`) and import from `bun:test`
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to test/js/bun/**/*.test.{ts,tsx} : For Bun-specific API tests, use the `test/js/bun/` directory (for http, crypto, ffi, shell, etc.)
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:35:39.205Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/registering-bun-modules.mdc:0-0
Timestamp: 2025-11-24T18:35:39.205Z
Learning: Add tests for new Bun runtime functionality
Applied to files:
docs/guides/test/assert.mdx
📚 Learning: 2025-09-20T03:39:41.770Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: test/regression/issue/21830.fixture.ts:14-63
Timestamp: 2025-09-20T03:39:41.770Z
Learning: Bun's test runner supports async describe callbacks, unlike Jest/Vitest where describe callbacks must be synchronous. The syntax `describe("name", async () => { ... })` is valid in Bun.
Applied to files:
docs/guides/test/assert.mdx
📚 Learning: 2025-11-24T18:35:50.422Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:50.422Z
Learning: Applies to test/cli/**/*.{js,ts,jsx,tsx} : When testing Bun as a CLI, use the `spawn` API from `bun` with the `bunExe()` and `bunEnv` from `harness` to execute Bun commands and validate exit codes, stdout, and stderr
Applied to files:
docs/guides/test/assert.mdxtest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:35:08.612Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/dev-server-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:08.612Z
Learning: Applies to test/bake/**/*.test.ts : Assert console messages using `c.expectMessage()` with single or multiple arguments; any unasserted logs fail the test to catch unexpected re-evaluations or reloads
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use `$debug()` for debug logging and `$assert()` for assertions; both are stripped in release builds
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to **/*.test.{ts,tsx} : Verify your test fails with `USE_SYSTEM_BUN=1 bun test <file>` and passes with `bun bd test <file>` - your test is NOT VALID if it passes with `USE_SYSTEM_BUN=1`
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` with files that end in `*.test.{ts,js,jsx,tsx,mjs,cjs}`
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : When spawning Bun processes in tests, use `bunExe` and `bunEnv` from `harness` to ensure the same build of Bun is used and debug logging is silenced
Applied to files:
docs/guides/test/assert.mdxpackages/bun-types/test.d.tstest/js/bun/test/assert-export.test.ts
📚 Learning: 2025-10-19T02:52:37.412Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/tsconfig.json:1-15
Timestamp: 2025-10-19T02:52:37.412Z
Learning: In the Bun repository, packages under packages/ (e.g., bun-otel) can follow a TypeScript-first pattern where package.json exports point directly to .ts files (not compiled .js files). Bun natively runs TypeScript, so consumers import .ts sources directly and receive full type information without needing compiled .d.ts declaration files. For such packages, adding "declaration": true or "outDir" in tsconfig.json is unnecessary and would break the export structure.
<!-- [remove_learning]
ceedde95-980e-4898-a2c6-40ff73913664
Applied to files:
packages/bun-types/test.d.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object
Applied to files:
packages/bun-types/test.d.tssrc/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:35:50.422Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:50.422Z
Learning: See `test/harness.ts` for common test utilities and helpers
Applied to files:
packages/bun-types/test.d.ts
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to test/js/node/**/*.test.{ts,tsx} : For Node.js compatibility tests, use the `test/js/node/` directory
Applied to files:
packages/bun-types/test.d.ts
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : For classes, prototypes, and constructors: add `JSC::LazyClassStructure` to ZigGlobalObject.h, initialize in `GlobalObject::finishCreation()`, visit in `GlobalObject::visitChildrenImpl()`, and implement a setup function that creates prototype, constructor, and main class structures
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : For classes without Constructor, use `JSC::LazyProperty<JSGlobalObject, Structure>` instead of `JSC::LazyClassStructure` in ZigGlobalObject.h, initialize in `GlobalObject::finishCreation()`, and visit in `GlobalObject::visitChildrenImpl()`
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : When implementing JavaScript classes in C++, define properties using HashTableValue arrays and add iso subspaces for classes with C++ fields, caching structures in ZigGlobalObject
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to **/*.zig : Use consistent parameter name `globalObject` instead of `ctx` in Zig constructor and method implementations
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to **/*.zig : Use `JSC.markBinding(src())` in finalize methods for debugging purposes before calling `deinit()`
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to src/bun.js/bindings/generated_classes_list.zig : Include new class bindings in `src/bun.js/bindings/generated_classes_list.zig` to register them with the code generator
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : To create JavaScript objects from Zig, implement C++ functions following the `Bun__ClassName__toJS(Zig::GlobalObject*, NativeType*)` convention that construct and return the JavaScript object as an encoded JSValue
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : Expose C++ class constructors to Zig using `extern "C"` functions following the pattern `Bun__JSClassName(Zig::GlobalObject*)` that return the encoded JSValue constructor
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : When constructing JavaScript objects, retrieve the structure from the global object using `zigGlobalObject->m_JSX509CertificateClassStructure.get(zigGlobalObject)` or similar pattern
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Create test functions in test/v8/v8-module/main.cpp that take FunctionCallbackInfo<Value> parameter, use the test V8 API, print results for comparison with Node.js, and return Undefined
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to **/*.zig : Implement getter functions with naming pattern `get<PropertyName>` in Zig that accept `this` and `globalObject` parameters and return `JSC.JSValue`
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.
Applied to files:
src/bun.js/bindings/ZigGlobalObject.cpp
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Unit tests for specific features are organized by module (e.g., `/test/js/bun/`, `/test/js/node/`)
Applied to files:
test/js/bun/test/assert-export.test.ts
🧬 Code graph analysis (1)
src/bun.js/bindings/ZigGlobalObject.cpp (2)
src/bun.js/bindings/ZigGlobalObject.h (1)
globalObject(127-127)src/bun.js/bindings/ScriptExecutionContext.cpp (2)
globalObject(93-96)globalObject(93-93)
🔇 Additional comments (2)
packages/bun-types/test.d.ts (1)
2375-2391: Type-level re‑export ofassertfromnode:assertlooks correctThe ambient
export import assert = require("node:assert");cleanly tiesbun:test’sassertto the existing Node typings, so users get the properasserts-style type narrowing and full API surface without duplicating types. This matches the runtime wiring and the docs examples.Please run your TypeScript/typecheck pipeline (or
tscforpackages/bun-types) to confirm there are no module name / lib conflicts around the"node:assert"typings in this repo’s configuration.docs/guides/test/assert.mdx (1)
1-93: Clear, focused documentation forassertinbun:testThe page accurately describes
assertas anode:assertre‑export, shows realistic TS narrowing usage, covers core methods (including async helpers), and explains mixing it withexpect(). The “See also” links correctly point users to Node’s docs and Bun’s test guide. No changes needed.
| auto* globalObject = jsCast<Zig::GlobalObject*>(init.owner); | ||
| auto& vm = init.vm; | ||
|
|
||
| JSValue result = JSValue::decode(Bun__Jest__createTestModuleObject(globalObject)); | ||
| init.set(result.toObject(globalObject)); | ||
| JSObject* testModule = result.toObject(globalObject); | ||
|
|
||
| // Add node:assert as "assert" export for vitest compatibility | ||
| JSValue assertModule = globalObject->internalModuleRegistry()->requireId(globalObject, vm, Bun::InternalModuleRegistry::Field::NodeAssert); | ||
| if (assertModule && !assertModule.isUndefinedOrNull()) { | ||
| testModule->putDirect(vm, Identifier::fromString(vm, "assert"_s), assertModule); | ||
| } | ||
|
|
||
| init.set(testModule); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Guard lazy test module initializer with a ThrowScope when loading node:assert
Inside m_lazyTestModuleObject.initLater you now:
- Decode the Jest test module object.
- Call
internalModuleRegistry()->requireId(..., Field::NodeAssert). putDirectthe returned value as"assert".
Unlike the nearby m_utilInspectFunction initializer, this path doesn’t use DECLARE_THROW_SCOPE / RETURN_IF_EXCEPTION, so any unexpected exception from Bun__Jest__createTestModuleObject, requireId, or putDirect would escape without a controlled early return from the initializer.
You can align this with existing patterns and make it more robust with a small change:
m_lazyTestModuleObject.initLater(
[](const Initializer<JSObject>& init) {
- auto* globalObject = jsCast<Zig::GlobalObject*>(init.owner);
- auto& vm = init.vm;
-
- JSValue result = JSValue::decode(Bun__Jest__createTestModuleObject(globalObject));
- JSObject* testModule = result.toObject(globalObject);
-
- // Add node:assert as "assert" export for vitest compatibility
- JSValue assertModule = globalObject->internalModuleRegistry()->requireId(globalObject, vm, Bun::InternalModuleRegistry::Field::NodeAssert);
- if (assertModule && !assertModule.isUndefinedOrNull()) {
- testModule->putDirect(vm, Identifier::fromString(vm, "assert"_s), assertModule);
- }
-
- init.set(testModule);
+ auto* globalObject = jsCast<Zig::GlobalObject*>(init.owner);
+ auto& vm = init.vm;
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue result = JSValue::decode(Bun__Jest__createTestModuleObject(globalObject));
+ JSObject* testModule = result.toObject(globalObject);
+ RETURN_IF_EXCEPTION(scope, );
+
+ // Add node:assert as "assert" export for vitest compatibility
+ JSValue assertModule =
+ globalObject->internalModuleRegistry()->requireId(globalObject, vm, Bun::InternalModuleRegistry::Field::NodeAssert);
+ RETURN_IF_EXCEPTION(scope, );
+ if (assertModule && !assertModule.isUndefinedOrNull()) {
+ testModule->putDirect(vm, Identifier::fromString(vm, "assert"_s), assertModule);
+ RETURN_IF_EXCEPTION(scope, );
+ }
+
+ init.set(testModule);
});This way a failure to load node:assert simply means the assert export is absent, without leaving a stray pending exception from a lazy initializer.
| import { assert, expect, test } from "bun:test"; | ||
|
|
||
| test("assert is exported from bun:test", () => { | ||
| expect(typeof assert).toBe("function"); | ||
| }); | ||
|
|
||
| test("assert(condition) works", () => { | ||
| assert(true); | ||
| assert(1); | ||
| assert("non-empty string"); | ||
|
|
||
| expect(() => assert(false)).toThrow(); | ||
| expect(() => assert(0)).toThrow(); | ||
| expect(() => assert("")).toThrow(); | ||
| }); | ||
|
|
||
| test("assert with message works", () => { | ||
| assert(true, "should not throw"); | ||
|
|
||
| expect(() => assert(false, "custom error message")).toThrow(/custom error message/); | ||
| }); | ||
|
|
||
| test("assert.ok works", () => { | ||
| assert.ok(true); | ||
| assert.ok(1); | ||
|
|
||
| expect(() => assert.ok(false)).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.strictEqual works", () => { | ||
| assert.strictEqual(1, 1); | ||
| assert.strictEqual("hello", "hello"); | ||
|
|
||
| expect(() => assert.strictEqual(1, 2)).toThrow(); | ||
| expect(() => assert.strictEqual(1, "1")).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.deepStrictEqual works", () => { | ||
| assert.deepStrictEqual({ a: 1 }, { a: 1 }); | ||
| assert.deepStrictEqual([1, 2, 3], [1, 2, 3]); | ||
|
|
||
| expect(() => assert.deepStrictEqual({ a: 1 }, { a: 2 })).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.notStrictEqual works", () => { | ||
| assert.notStrictEqual(1, 2); | ||
| assert.notStrictEqual(1, "1"); | ||
|
|
||
| expect(() => assert.notStrictEqual(1, 1)).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.throws works", () => { | ||
| assert.throws(() => { | ||
| throw new Error("test error"); | ||
| }); | ||
|
|
||
| expect(() => | ||
| assert.throws(() => { | ||
| // does not throw | ||
| }), | ||
| ).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.doesNotThrow works", () => { | ||
| assert.doesNotThrow(() => { | ||
| // does not throw | ||
| }); | ||
|
|
||
| expect(() => | ||
| assert.doesNotThrow(() => { | ||
| throw new Error("test error"); | ||
| }), | ||
| ).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.rejects works", async () => { | ||
| await assert.rejects(async () => { | ||
| throw new Error("async error"); | ||
| }); | ||
|
|
||
| await expect( | ||
| assert.rejects(async () => { | ||
| // does not reject | ||
| }), | ||
| ).rejects.toThrow(); | ||
| }); | ||
|
|
||
| test("assert.doesNotReject works", async () => { | ||
| await assert.doesNotReject(async () => { | ||
| // does not reject | ||
| }); | ||
|
|
||
| await expect( | ||
| assert.doesNotReject(async () => { | ||
| throw new Error("async error"); | ||
| }), | ||
| ).rejects.toThrow(); | ||
| }); | ||
|
|
||
| test("assert.equal works (loose equality)", () => { | ||
| assert.equal(1, 1); | ||
| assert.equal(1, "1"); // loose equality allows this | ||
|
|
||
| expect(() => assert.equal(1, 2)).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.notEqual works (loose inequality)", () => { | ||
| assert.notEqual(1, 2); | ||
|
|
||
| expect(() => assert.notEqual(1, 1)).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.deepEqual works", () => { | ||
| assert.deepEqual({ a: 1 }, { a: 1 }); | ||
| assert.deepEqual([1, 2], [1, 2]); | ||
|
|
||
| expect(() => assert.deepEqual({ a: 1 }, { a: 2 })).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.notDeepEqual works", () => { | ||
| assert.notDeepEqual({ a: 1 }, { a: 2 }); | ||
|
|
||
| expect(() => assert.notDeepEqual({ a: 1 }, { a: 1 })).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.fail works", () => { | ||
| expect(() => assert.fail()).toThrow(); | ||
| expect(() => assert.fail("custom message")).toThrow(/custom message/); | ||
| }); | ||
|
|
||
| test("assert.ifError works", () => { | ||
| assert.ifError(null); | ||
| assert.ifError(undefined); | ||
|
|
||
| expect(() => assert.ifError(new Error("test"))).toThrow(); | ||
| expect(() => assert.ifError("some error")).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.match works", () => { | ||
| assert.match("hello world", /world/); | ||
|
|
||
| expect(() => assert.match("hello", /world/)).toThrow(); | ||
| }); | ||
|
|
||
| test("assert.doesNotMatch works", () => { | ||
| assert.doesNotMatch("hello", /world/); | ||
|
|
||
| expect(() => assert.doesNotMatch("hello world", /world/)).toThrow(); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Comprehensive coverage of the assert export; consider also asserting identity with node:assert
These tests do a solid job of exercising the assert export from bun:test across the core Node APIs (sync, async, loose/strict, deep vs non‑deep, and helper methods). They align with Bun’s testing style guidelines and should quickly catch regressions in the wiring to node:assert.
If you want to further lock in the “re‑export” guarantee (not just behavioral similarity), you could add a small identity check:
-import { assert, expect, test } from "bun:test";
+import { assert, expect, test } from "bun:test";
+import nodeAssert from "node:assert";
+
+test("assert is the node:assert export", () => {
+ expect(assert).toBe(nodeAssert);
+});Optional, but it would guarantee that bun:test and node:assert stay in sync at the object level.
🤖 Prompt for AI Agents
In test/js/bun/test/assert-export.test.ts around lines 1 to 149, add a small
identity check to ensure the exported assert from bun:test is the same object
exported by node:assert; require or import node:assert (e.g., import * as
nodeAssert from "node:assert" or require("node:assert")) and add an expectation
that assert === nodeAssert (or otherwise assert strict identity), so the test
verifies a re-export rather than only behavioral equivalence.
What does this PR do?
add assert to bun test
How did you verify your code works?
vitest has assert function, which is useful especially if you use union types