Testing Overview
@stratal/testing provides first-class testing utilities built on Vitest and @cloudflare/vitest-pool-workers. It gives you module bootstrapping, an HTTP test client with fluent assertions, provider overrides, fake storage, and fetch mocking — all running on the real Workers runtime.
Why test on the Workers runtime
Section titled “Why test on the Workers runtime”Cloudflare Workers run on the workerd runtime, which differs from Node.js in several ways: no fs or net modules, a different fetch implementation, and environment bindings like KV, R2, D1, and Queues that only exist inside workerd. Testing on Node.js alone means your tests cannot exercise real bindings or catch runtime-specific issues.
@cloudflare/vitest-pool-workers runs each test inside a local workerd instance, so your tests use the same runtime as production. @stratal/testing builds on this foundation to provide a higher-level API for bootstrapping modules, making HTTP requests, and asserting responses.
Install dependencies
Section titled “Install dependencies”yarn add -D @stratal/testing @cloudflare/workers-types vitestProject setup
Section titled “Project setup”Vitest configuration
Section titled “Vitest configuration”Create a vitest.config.ts at the root of your project using the stratalTest() plugin:
import { stratalTest } from '@stratal/testing/vitest-plugin'import { defineConfig } from 'vitest/config'
export default defineConfig({ plugins: [stratalTest({ wrangler: { configPath: './wrangler.jsonc' } })], test: { setupFiles: ['./vitest.setup.ts'], },})Vitest setup file
Section titled “Vitest setup file”Create a vitest.setup.ts that imports reflect-metadata (required in tests since they don’t go through the Stratal entry point, which handles this import automatically in production) and configures shared base modules:
import 'reflect-metadata'import { Test } from '@stratal/testing'import { CoreModule } from './src/core/core.module'
Test.setBaseModules([CoreModule])Test.setBaseModules() registers modules that should be included in every test module. This avoids repeating common imports like your CoreModule in every test file.
Wrangler configuration
Section titled “Wrangler configuration”Your project needs a wrangler.jsonc (or wrangler.toml) with the nodejs_compat compatibility flag enabled. This is required for Node.js APIs used by the framework:
{ "name": "my-app", "compatibility_date": "2024-12-01", "compatibility_flags": ["nodejs_compat"], "main": "src/index.ts"}Your first test
Section titled “Your first test”With the setup in place, create a test file for a module. Here is a complete example testing a NotesController:
import { Test, type TestingModule } from '@stratal/testing'import { afterAll, beforeEach, describe, expect, it } from 'vitest'import { NotesModule } from '../notes.module'
describe('NotesController', () => { let module: TestingModule
beforeEach(async () => { module = await Test.createTestingModule({ imports: [NotesModule], }).compile() })
afterAll(async () => { await module.close() })
it('should list notes', async () => { const response = await module.http.get('/api/notes').send()
response.assertOk() await response.assertJsonStructure(['data']) })
it('should create a note', async () => { const response = await module.http .post('/api/notes') .withBody({ title: 'Test Note', content: 'Hello from tests' }) .send()
response.assertCreated() await response.assertJsonPath('data.title', 'Test Note') await response.assertJsonPathExists('data.id') })})Test.createTestingModule() creates an isolated application instance with your module’s controllers, providers, and routes. The module.http property provides a fluent HTTP client for making requests and asserting responses.
Test lifecycle
Section titled “Test lifecycle”| Hook | Purpose |
|---|---|
beforeEach | Create a fresh TestingModule with Test.createTestingModule().compile() |
afterAll | Call module.close() to shut down the application and release resources |
Next steps
Section titled “Next steps”- Testing Module for creating modules, provider overrides, and environment configuration.
- HTTP Testing for the full request builder and response assertion API.
- Mocks and Fakes for deep mocks, fake storage, and fetch interception.