Testing Frameworks in Thunderbolt: A Complete Guide to Unit, Component, and E2E Testing
Thunderbolt uses Bun's built-in test runner for unit and integration tests, React Testing Library for component testing, and Playwright for end-to-end testing, all configured through src/testing-library.ts and playwright.config.ts.
The thunderbird/thunderbolt repository employs a modern JavaScript testing stack to ensure reliability across its React frontend. Understanding the testing frameworks used in Thunderbolt helps contributors write effective tests that cover everything from utility functions to full browser workflows.
Testing Frameworks Used in Thunderbolt
Bun Test Runner for Unit and Integration Tests
Thunderbolt uses Bun's built-in test runner (bun test) as its primary test executor. This is configured in the root package.json under the "test" script, which executes all .test.ts files using globals like describe, it, expect, beforeEach, and afterEach.
Unlike Jest, Bun provides these utilities through the bun:test module. You can see this pattern in files like vite.config.test.ts, which imports testing utilities directly from bun:test.
React Testing Library for Component and Hook Tests
For React-specific testing, Thunderbolt integrates @testing-library/react combined with @testing-library/jest-dom. This setup renders components and hooks in a lightweight DOM environment using happy-dom.
The global configuration and mocks for browser-only modules like web-haptics/react and posthog-js reside in src/testing-library.ts. This harness provides utilities like renderHook and act, along with DOM matchers such as toBeInTheDocument and toHaveTextContent.
Playwright for End-to-End Testing
Playwright (@playwright/test) handles E2E testing by driving a real Chromium browser. Configuration is centralized in playwright.config.ts at the project root, while test files reside in the e2e/ directory.
The e2e/helpers.ts file provides reusable utilities like loginViaOidc for authentication flows and collectPageErrors for capturing console errors during test execution.
Supporting Tools and Type Shims
Thunderbolt augments its testing stack with @sinonjs/fake-timers for deterministic timer control, wrapped by a custom installFakeTimers helper in src/testing-library.ts.
The repository also includes a type-only shim in vitest.shims.d.ts that allows Playwright-based tests to be typed as Vitest tests, though execution remains handled by Playwright.
How to Write Tests in Thunderbolt
Create a Test File
Place test files adjacent to their source files with the .test.ts extension. For example, src/hooks/use-draft-input.test.ts tests the use-draft-input.ts hook.
Write Unit Tests with Bun
Import the Bun test API and write assertions using the familiar describe/it pattern:
// src/lib/utils.test.ts
import { describe, it, expect } from 'bun:test'
import { capitalize } from './utils'
describe('capitalize()', () => {
it('upper-cases the first character', () => {
expect(capitalize('hello')).toBe('Hello')
})
it('leaves an empty string unchanged', () => {
expect(capitalize('')).toBe('')
})
})
Run with bun test src/lib/utils.test.ts.
Test React Hooks and Components
Import from @testing-library/react to test React-specific behavior. The global harness in src/testing-library.ts automatically handles mocks and fake timers:
// src/hooks/use-draft-input.test.ts
import { renderHook, act } from '@testing-library/react'
import { useDraftInput } from './use-draft-input'
describe('useDraftInput', () => {
it('updates the draft when setDraft is called', () => {
const { result } = renderHook(() => useDraftInput())
act(() => result.current.setDraft('new draft'))
expect(result.current.draft).toBe('new draft')
})
})
Write E2E Tests with Playwright
Create specs in the e2e/ directory using Playwright's test API. Use helpers from e2e/helpers.ts for common operations:
// e2e/oidc-login.spec.ts
import { test, expect } from '@playwright/test'
import { loginViaOidc, collectPageErrors } from './helpers'
test('unauthenticated user is redirected through OIDC and lands on chat', async ({ page }) => {
const errors = collectPageErrors(page)
await loginViaOidc(page)
await expect(page).toHaveURL(/\/chats\//)
expect(errors).toHaveLength(0)
})
Run E2E tests via bunx playwright test.
Summary
- Bun test runner executes unit and integration tests via
bun test, providingdescribe,it, andexpectglobals through thebun:testmodule. - React Testing Library handles component and hook testing with
renderHookandact, configured globally insrc/testing-library.tswith automatic mocking of browser-only modules. - Playwright manages end-to-end testing in a real Chromium browser, with configuration in
playwright.config.tsand reusable helpers ine2e/helpers.ts. - Fake timers via
@sinonjs/fake-timersprovide deterministic time control, wrapped by theinstallFakeTimershelper in the global test setup. - Tests are organized as
.test.tsfiles co-located with source code, while E2E specs reside in thee2e/directory and execute throughbunx playwright test.
Frequently Asked Questions
What is the primary test runner used in Thunderbolt?
Thunderbolt uses Bun's built-in test runner (bun test) as its primary test executor. This is configured in the root package.json and provides standard testing globals like describe, it, expect, beforeEach, and afterEach through the bun:test module.
How does Thunderbolt handle browser-only modules when testing React components?
The project mocks browser-specific modules like web-haptics/react and posthog-js in the global test harness located at src/testing-library.ts. This configuration allows React components and hooks to be tested in a lightweight happy-dom environment without requiring an actual browser.
Can I use Jest-style matchers like toBeInTheDocument in Thunderbolt tests?
Yes. Thunderbolt integrates @testing-library/jest-dom matchers through the global test setup in src/testing-library.ts. These matchers work with Bun's expect function, allowing you to use DOM-specific assertions like toBeInTheDocument() and toHaveTextContent() in your component tests.
Where should I place end-to-end tests in the Thunderbolt repository?
End-to-end tests belong in the e2e/ directory at the repository root. These files use Playwright's test API and import helpers from e2e/helpers.ts for common operations like OIDC authentication and error collection. Configure Playwright settings in playwright.config.ts at the project root.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →