Test Overview
The test package is a built-in test runner for Remix applications. It provides a familiar describe/it API for structuring tests, lifecycle hooks for setup and teardown, mock functions for isolating dependencies, and spies for observing calls to existing functions. No external test framework (like Jest or Vitest) is needed.
When to Use This Package
Use the test package to:
- Write unit tests for utility functions, data loaders, and actions
- Test route handlers by sending simulated
Requestobjects - Mock external services and dependencies
- Run tests in the same runtime your application uses
Quick Example
ts
import { describe, it } from 'remix/test'
describe('add', () => {
it('adds two numbers', (t) => {
t.assert.equal(1 + 1, 2)
})
it('handles negative numbers', (t) => {
t.assert.equal(-1 + 1, 0)
})
})Run tests with:
bash
npx remix testKey Concepts
- describe / suite -- Groups related tests into a block. Can be nested to any depth.
suiteis an alias fordescribe. - it -- Defines a single test case. Receives a test context
twith assertion and mocking utilities. - Test context (
t) -- Every test callback receivestwitht.assert(assertions),t.mock(create mocks), andt.spyOn(spy on methods). - Lifecycle hooks --
before/afterrun once per describe block.beforeEach/afterEachrun before/after every test. - Mocks -- Functions that record their calls and can be configured to return specific values.
- Spies -- Wrappers around real functions that record calls while still executing the original.
Test Structure
ts
import { describe, it, before, afterEach } from 'remix/test'
describe('UserService', () => {
before(async () => {
// Runs once before all tests in this block
await setupDatabase()
})
afterEach(async () => {
// Runs after each test
await clearTestData()
})
it('creates a user', async (t) => {
let user = await createUser({ name: 'Alice' })
t.assert.ok(user.id)
t.assert.equal(user.name, 'Alice')
})
it('rejects duplicate emails', async (t) => {
await createUser({ email: 'a@b.com' })
await t.assert.rejects(() => createUser({ email: 'a@b.com' }))
})
})Mocking and Spying
ts
it('calls the handler', (t) => {
// Create a mock function
let handler = t.mock()
emitter.on('event', handler)
emitter.emit('event', 'data')
t.assert.equal(handler.calls.length, 1)
t.assert.deepEqual(handler.calls[0].arguments, ['data'])
})
it('tracks method calls', (t) => {
let spy = t.spyOn(logger, 'info')
doSomething()
t.assert.equal(spy.calls.length, 1)
})Related
- assert -- The assertion functions available via
t.assert - API Reference -- Full API documentation