# Testing Frameworks in Thunderbolt: A Complete Guide to Unit, Component, and E2E Testing

> Explore Thunderbolt's testing frameworks: Bun for unit/integration, React Testing Library for component, and Playwright for E2E. Learn how developers write tests efficiently.

- Repository: [Thunderbird/thunderbolt](https://github.com/thunderbird/thunderbolt)
- Tags: how-to-guide
- Published: 2026-04-19

---

**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`](https://github.com/thunderbird/thunderbolt/blob/main/src/testing-library.ts) and [`playwright.config.ts`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/package.json) under the `"test"` script, which executes all [`.test.ts`](https://github.com/thunderbird/thunderbolt/blob/main/.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`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/playwright.config.ts) at the project root, while test files reside in the `e2e/` directory.

The [`e2e/helpers.ts`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/src/testing-library.ts).

The repository also includes a type-only shim in [`vitest.shims.d.ts`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/.test.ts) extension. For example, [`src/hooks/use-draft-input.test.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/hooks/use-draft-input.test.ts) tests the [`use-draft-input.ts`](https://github.com/thunderbird/thunderbolt/blob/main/use-draft-input.ts) hook.

### Write Unit Tests with Bun

Import the Bun test API and write assertions using the familiar `describe`/`it` pattern:

```typescript
// 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`](https://github.com/thunderbird/thunderbolt/blob/main/src/testing-library.ts) automatically handles mocks and fake timers:

```typescript
// 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`](https://github.com/thunderbird/thunderbolt/blob/main/e2e/helpers.ts) for common operations:

```typescript
// 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`, providing `describe`, `it`, and `expect` globals through the `bun:test` module.
- **React Testing Library** handles component and hook testing with `renderHook` and `act`, configured globally in [`src/testing-library.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/testing-library.ts) with automatic mocking of browser-only modules.
- **Playwright** manages end-to-end testing in a real Chromium browser, with configuration in [`playwright.config.ts`](https://github.com/thunderbird/thunderbolt/blob/main/playwright.config.ts) and reusable helpers in [`e2e/helpers.ts`](https://github.com/thunderbird/thunderbolt/blob/main/e2e/helpers.ts).
- **Fake timers** via `@sinonjs/fake-timers` provide deterministic time control, wrapped by the `installFakeTimers` helper in the global test setup.
- Tests are organized as [`.test.ts`](https://github.com/thunderbird/thunderbolt/blob/main/.test.ts) files co-located with source code, while E2E specs reside in the `e2e/` directory and execute through `bunx 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`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/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`](https://github.com/thunderbird/thunderbolt/blob/main/e2e/helpers.ts) for common operations like OIDC authentication and error collection. Configure Playwright settings in [`playwright.config.ts`](https://github.com/thunderbird/thunderbolt/blob/main/playwright.config.ts) at the project root.