Testing - TypeScript SDK
The Testing section of the Temporal Application development guide describes the frameworks that facilitate Workflow and integration testing.
In the context of Temporal, you can create these types of automated tests:
- End-to-end: Running a Temporal Server and Worker with all its Workflows and Activities; starting and interacting with Workflows from a Client.
- Integration: Anything between end-to-end and unit testing.
- Running Activities with mocked Context and other SDK imports (and usually network requests).
- Running Workers with mock Activities, and using a Client to start Workflows.
- Running Workflows with mocked SDK imports.
- Unit: Running a piece of Workflow or Activity code (a function or method) and mocking any code it calls.
We generally recommend writing the majority of your tests as integration tests.
Because the test server supports skipping time, use the test server for both end-to-end and integration tests with Workers.
Test frameworks
Some SDKs have support or examples for popular test frameworks, runners, or libraries.
TypeScript has sample tests for Jest and Mocha.
Jest
- Minimum Jest version:
27.0.0
- Sample test file
jest.config.js
(must usetestEnvironment: 'node'
;testEnvironment: 'jsdom'
is not supported)
Mocha
- Sample test file
- Test coverage library:
@temporalio/nyc-test-coverage
Testing Activities
An Activity can be tested with a mock Activity environment, which provides a way to mock the Activity context, listen to Heartbeats, and cancel the Activity. This behavior allows you to test the Activity in isolation by calling it directly, without needing to create a Worker to run the Activity.
Run an Activity
If an Activity references its context, you need to mock that context when testing in isolation.
First, create a MockActivityEnvironment
.
The constructor accepts an optional partial Activity Info
object in case any info fields are needed for the test.
Then use MockActivityEnvironment.run()
to run a function in an Activity Context.
import { activityInfo } from '@temporalio/activity';
import { MockActivityEnvironment } from '@temporalio/testing';
import assert from 'assert';
// A function that takes two numbers and returns a promise that resolves to the sum of the two numbers
// and the current attempt.
async function activityFoo(a: number, b: number): Promise<number> {
return a + b + activityInfo().attempt;
}
// Create a MockActivityEnvironment with attempt set to 2. Run the activityFoo
// function with parameters 5 and 35. Assert that the result is 42.
const env = new MockActivityEnvironment({ attempt: 2 });
const result = await env.run(activityFoo, 5, 35);
assert.equal(result, 42);
Listen to Heartbeats
When an Activity sends a Heartbeat, be sure that you can see the Heartbeats in your test code so that you can verify them.
MockActivityEnvironment
is an EventEmitter
that emits a heartbeat
event that you can use to listen for Heartbeats emitted by the Activity.
When an Activity is run by a Worker, Heartbeats are throttled to avoid overloading the server.
MockActivityEnvironment
, however, does not throttle Heartbeats.
import { heartbeat } from '@temporalio/activity';
import assert from 'assert';
async function activityFoo(): Promise<void> {
heartbeat(6);
}
const env = new MockActivityEnvironment();
env.on('heartbeat', (d: unknown) => {
assert(d === 6);
});
await env.run(activityFoo);
Cancel an Activity
If an Activity is supposed to react to a Cancellation, you can test whether it reacts correctly by canceling it.
MockActivityEnvironment
exposes a .cancel()
method that cancels the Activity Context.
import { CancelledFailure, heatbeat, sleep } from '@temporalio/activity';
import { MockActivityEnvironment } from '@temporalio/testing';
import assert from 'assert';
async function activityFoo(): Promise<void> {
heartbeat(6);
// @temporalio/activity's sleep() is Cancellation-aware, which means that on Cancellation,
// CancelledFailure will be thrown from it.
await sleep(100);
}
const env = new MockActivityEnvironment();
env.on('heartbeat', (d: unknown) => {
assert(d === 6);
});
await assert.rejects(env.run(activityFoo), (err) => {
assert.ok(err instanceof CancelledFailure);
});