I've wasted too many hours fighting ts-jest import errors that work fine everywhere except tests. Jest's watch mode crashed my laptop twice last month when I forgot to close it. I've had it with Jest's config bullshit, so I tried Bun's test runner. Spoiler: it actually doesn't suck.
The Jest Configuration Nightmare (We've All Been There)
I've spent entire afternoons fighting Jest setups. Every new project is the same shitshow: install Jest, configure ts-jest, fight with import paths, debug why snapshots broke, then discover Jest doesn't work with the latest Node version.
Here's what my last Jest setup looked like before I rage-quit:
{
"devDependencies": {
"jest": "^29.0.0",
"ts-jest": "^29.0.0",
"@types/jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.0"
}
}
Plus a 50-line jest.config.js that I copied from Stack Overflow and prayed worked. Every time someone cloned the project, they'd slack "tests are broken on my machine" and I'd waste an hour debugging their Node version. Pro tip: always use exact versions in package.json or npm will fuck you.
Seriously, how many times have you copy-pasted a Jest config from Stack Overflow and prayed it worked? I've done it dozens of times and I still don't know what half these options do. testPathIgnorePatterns, testMatch, testRegex - who designed this shit? Three different ways to tell Jest which files to run.
With Bun, this is the entire setup:
bun test
That's it. No config files. TypeScript works. JSX works. Coverage reports just work. I can finally write tests instead of debugging test configs.
Tests Are Actually Fast Now (Not Marketing "Fast")
Jest startup time killed my TDD flow. On my M1 MacBook, our test suite was slow as hell with Jest. With Bun it's way faster - not sure exactly how much but tests actually start instantly instead of me staring at a loading spinner. Forget the marketing bullshit about 10x faster - it's just noticeably quicker.
What I noticed after switching (your setup will definitely be different):
- Startup time: Jest took forever to even start, Bun starts instantly
- Our 200-ish test suite: Jest was slow as molasses, Bun runs way faster
- Watch mode memory: Jest ate RAM like crazy, Bun doesn't crash my laptop
- CI time: Cut our GitHub Actions time roughly in half
The biggest win is TDD finally works. Tests run fast enough that I actually run them instead of git push
and hoping CI catches my fuckups.
Migration Is Easier Than Expected (With Gotchas)
Check the Bun test docs - they're actually decent, unlike most framework docs.
Migrating basic tests takes 10 minutes. Change your imports from Jest globals to bun:test
and 80% of tests run immediately:
// Old Jest way (globals)
test('user creation', () => {
expect(user.name).toBe('test');
});
// Bun way (explicit imports)
import { test, expect } from 'bun:test';
test('user creation', () => {
expect(user.name).toBe('test');
});
Basic stuff works: describe
, beforeAll
, afterEach
, toThrow()
, toBe()
. I migrated 150 simple tests without issues.
But then reality hit. Here's what broke:
- Custom matchers I wrote for JWT validation - had to rewrite all of them using
expect.extend()
jest.mock()
auto-hoisting broke 20+ tests - Bun doesn't hoist mocks automatically- Snapshot tests - all snapshots had to be regenerated from scratch
- Some async timing behaved differently - spent 2 hours debugging
waitFor()
timeouts - Module mocking syntax is completely different - goodbye
__mocks__
folders - A few tests that relied on Jest's weird hoisting quirks just had to be rewritten
TypeScript That Actually Works
I've wasted days debugging ts-jest configs. Import paths that work in VS Code fail in tests. Source maps break. TypeScript errors get swallowed and you only find out when tests mysteriously fail.
With Bun, TypeScript just runs:
// users.test.ts - this actually works first try
import { test, expect } from 'bun:test';
import { User, createUser } from './user.ts';
test('user creation with proper typing', () => {
const user: User = createUser({
name: 'John',
email: 'john@example.com',
age: 30
});
expect(user.id).toBeTypeOf('string');
expect(user.createdAt).toBeInstanceOf(Date);
});
No tsconfig fuckery. No source map debugging. Import paths work like everywhere else. TypeScript errors show up immediately instead of getting buried in Jest's compilation output. Path mapping from your tsconfig.json just works - no need to duplicate it anywhere.
Mocking That Makes Sense
Jest's jest.mock()
hoisting broke my brain. You call jest.mock()
at the bottom of a file but it runs first? Mock implementations get hoisted but assignments don't? Who thought this was a good idea?
Bun mocking is explicit and predictable:
import { test, expect, mock } from 'bun:test';
import { sendEmail } from './email.js';
test('email sending works', async () => {
const mockSendEmail = mock(sendEmail);
mockSendEmail.mockResolvedValue({ messageId: '123' });
const result = await sendWelcomeEmail('user@example.com');
expect(mockSendEmail).toHaveBeenCalledWith({
to: 'user@example.com',
subject: 'Welcome!'
});
});
No magic hoisting. No __mocks__
folders. Mock what you need, when you need it. Still crashes sometimes with complex module mocks, but at least the syntax makes sense.
Full disclosure: I tried Bun, rage-quit back to Jest when module mocking broke, then came back when I realized Jest was still worse.
And here's something nobody talks about: Jest's mock hoisting actually broke our CI twice. Once because someone moved a jest.mock()
call and tests that passed locally started failing in CI. Another time Jest decided to hoist mocks in a different order after a Node update. Spent an entire afternoon figuring out why tests were importing the wrong modules.
With Bun, what you see is what you get. Mock calls run where you put them. Revolutionary concept, I know.
Coverage and Watch Mode Actually Work
Coverage with Jest means configuring Istanbul, debugging source maps, and waiting forever for reports. The --coverage flag is slower than molasses but at least it works. With Bun:
bun test --coverage
HTML coverage reports generate in under a second. TypeScript is included correctly. No setup required.
Watch mode doesn't crash every 20 minutes like Jest:
bun test --watch
File changes trigger re-runs quickly. Memory stays reasonable instead of eating everything like Jest. Works on our huge monorepo without dying.
After dealing with this shit for months
What works better than Jest:
- Setup time (just run
bun test
vs an hour of config hell) - Test speed (way faster, fast enough that TDD actually works)
- TypeScript integration (works without any config bullshit)
- Watch mode stability (doesn't crash and eat all my RAM)
What still sucks:
- Custom matchers need rewriting
- Some Testing Library edge cases break
- Ecosystem is smaller (fewer Stack Overflow answers)
- Browser testing doesn't exist yet
Should you switch?
If you're starting fresh: absolutely. Why torture yourself with Jest configuration when you don't have to?
If you have hundreds of Jest tests with custom matchers and complex mocking: stick with Jest for now. The migration pain isn't worth it.
If your Jest setup works but you're tired of slow tests and random configuration issues: try Bun on a side project first. See if the speed improvement is worth the switch for your team. In my experience, the productivity boost from actually being able to run tests during development is huge.