- Unit testing - Test individual steps as plain functions, without the workflow runtime.
- Integration testing - Test entire workflows against a real workflow setup using the Vite plugin. Required for workflows that use hooks, webhooks,
sleep(), or retries.
Unit Testing Steps
Without the workflow compiler, the"use step" directive is a no-op. Your step functions run as regular JavaScript functions, making them straightforward to unit test with no special configuration.
Example Steps
Given a workflow file with step functions like this:workflows/user-signup.ts
Writing Unit Tests for Steps
You can import and test step functions directly with Vitest. No special configuration or workflow plugin is needed:workflows/user-signup.test.ts
Unit testing works well for individual steps. A simple workflow that only calls steps can also be unit tested this way, since
"use workflow" is similarly a no-op without the compiler. However, any workflow that uses runtime features like sleep(), hooks, or webhooks cannot be unit tested directly because those APIs require the workflow runtime. Use integration testing for testing entire workflows, especially those that depend on workflow-only features.Integration Testing with the Vite Plugin
For workflows that rely on runtime features like hooks, webhooks,sleep(), or error retries, you need to test against a real workflow setup. The workflow/vite plugin integrates directly with Vitest, compiling your "use workflow" and "use step" directives so the full workflow runtime is active during tests.
Vitest Configuration
Create a separate Vitest config for integration tests that includes theworkflow() plugin and a globalSetup script:
vitest.integration.config.ts
Use a separate Vitest configuration and a distinct file naming convention (e.g.
*.integration.test.ts) to keep unit tests and integration tests separate. Unit tests run with a standard Vitest config without the workflow plugin, while integration tests use the config above.Global Setup Script
Integration tests need a running server to execute workflow steps. TheglobalSetup script starts a Nitro server as a sidecar process before tests run, and tears it down afterwards:
vitest.integration.setup.ts
WORKFLOW_LOCAL_BASE_URLtells the runtime where to send step execution requestsWORKFLOW_LOCAL_DATA_DIRtells the runtime where to persist workflow state locally
Running Integration Tests
Add a script to yourpackage.json:
package.json
Testing Hooks and Waits
The real power of integration testing comes when testing workflow-only features. Hooks and waits can be resumed programmatically using theworkflow/api functions, making it straightforward to simulate external events in your tests.
Given a workflow that waits for approval via a hook, then sleeps before publishing:
workflows/approval.ts
wakeUp() to skip the sleep — so your tests don’t have to wait for the full duration:
workflows/approval.integration.test.ts
start(), resumeHook(), and getRun().wakeUp() are the key API functions for integration testing. Use start() to trigger a workflow, resumeHook() to simulate external events, and wakeUp() to skip sleep() calls so tests run instantly.Debugging Test Runs
When integration tests fail, the Workflow DevKit CLI and Web UI can help you inspect what happened. Because integration tests persist workflow state toWORKFLOW_LOCAL_DATA_DIR, you can use the same observability tools you would use in development.
Launch the Web UI to visually explore your test workflow runs:
See the Observability docs for the full set of CLI commands and Web UI features.
Best Practices
Separate Unit and Integration Tests
Keep two test configurations:- Unit tests - Standard Vitest config, no workflow plugin. Fast, no infrastructure required.
- Integration tests - Vitest config with
workflow()plugin. Tests the full workflow lifecycle including hooks, sleeps, and retries.
Use Custom Hook Tokens for Deterministic Testing
When testing workflows with hooks, use custom tokens based on predictable values (like document IDs or test identifiers). This makes it easy to resume the correct hook in your test code.Set Appropriate Timeouts
Workflows may take longer to execute than typical unit tests, especially when they involve multiple steps or retries. Set a generoustestTimeout in your integration test config.
Test Error and Retry Scenarios
Integration tests are the right place to verify that your workflows handle errors correctly, including retryable errors, fatal errors, and timeout scenarios.Further Reading
- Observability - Inspect and debug workflow runs with the CLI and Web UI
This guide was inspired by the testing approach described in Mux’s article Launching durable AI workflows for video with @mux/ai, which demonstrates how Mux uses the
workflow/vite plugin with Vitest to integration test their durable AI video workflows built on Workflow DevKit.