import type { AsyncCompletionClient, ClientPlugin, ConnectionPlugin, WorkflowClient } from '@temporalio/client'; import { Client, Connection } from '@temporalio/client'; import type { Duration } from '@temporalio/common'; import type { NativeConnectionPlugin, NativeConnectionOptions } from '@temporalio/worker'; import { NativeConnection, Runtime } from '@temporalio/worker'; import { native } from '@temporalio/core-bridge'; import type { temporal } from '@temporalio/proto'; import type { DevServerConfig, TimeSkippingServerConfig } from './ephemeral-server'; import type { ClientOptionsForTestEnv } from './client'; /** * Options for {@link TestWorkflowEnvironment.createLocal} */ export type LocalTestWorkflowEnvironmentOptions = { server?: Omit; client?: ClientOptionsForTestEnv; plugins?: (ClientPlugin | ConnectionPlugin | NativeConnectionPlugin)[]; }; /** * Options for {@link TestWorkflowEnvironment.createTimeSkipping} */ export type TimeSkippingTestWorkflowEnvironmentOptions = { server?: Omit; client?: ClientOptionsForTestEnv; plugins?: (ClientPlugin | ConnectionPlugin | NativeConnectionPlugin)[]; }; export type ExistingServerConnectionOptions = Pick; /** * Options for {@link TestWorkflowEnvironment.createFromExistingServer} * * Accepts connection options that can be used for both the client and worker connections. */ export type ExistingServerTestWorkflowEnvironmentOptions = { /** If not set, defaults to localhost:7233 */ address?: string; /** If not set, defaults to default */ namespace?: string; connectionOptions?: ExistingServerConnectionOptions; client?: ClientOptionsForTestEnv; plugins?: (ClientPlugin | ConnectionPlugin | NativeConnectionPlugin)[]; }; /** * An execution environment for running Workflow integration tests. * * Runs an external server. * By default, the Java test server is used which supports time skipping. */ export declare class TestWorkflowEnvironment { private readonly runtime; readonly options: TestWorkflowEnvironmentOptionsWithDefaults; readonly supportsTimeSkipping: boolean; protected readonly server: native.EphemeralServer | 'existing'; /** * Address used when constructing `connection` and `nativeConnection` */ readonly address: string; /** * Connection options used when constructing `connection` and `nativeConnection`. */ readonly connectionOptions: ExistingServerConnectionOptions; /** * Namespace used in this environment (taken from {@link TestWorkflowEnvironmentOptions}) */ readonly namespace?: string; /** * Get an established {@link Connection} to the ephemeral server */ readonly connection: Connection; /** * A {@link TimeSkippingClient} for interacting with the ephemeral server */ readonly client: Client; /** * An {@link AsyncCompletionClient} for interacting with the test server * * @deprecated - use `client.activity` instead */ readonly asyncCompletionClient: AsyncCompletionClient; /** * A {@link TimeSkippingWorkflowClient} for interacting with the test server * * @deprecated - use `client.workflow` instead */ readonly workflowClient: WorkflowClient; /** * A {@link NativeConnection} for interacting with the test server. * * Use this connection when creating Workers for testing. */ readonly nativeConnection: NativeConnection; protected constructor(runtime: Runtime, options: TestWorkflowEnvironmentOptionsWithDefaults, supportsTimeSkipping: boolean, server: native.EphemeralServer | 'existing', connection: Connection, nativeConnection: NativeConnection, namespace: string | undefined, /** * Address used when constructing `connection` and `nativeConnection` */ address: string, /** * Connection options used when constructing `connection` and `nativeConnection`. */ connectionOptions?: ExistingServerConnectionOptions); /** * Start a time skipping workflow environment. * * This environment automatically skips to the next events in time when a workflow handle's `result` is awaited on * (which includes {@link WorkflowClient.execute}). Before the result is awaited on, time can be manually skipped * forward using {@link sleep}. The currently known time can be obtained via {@link currentTimeMs}. * * This environment will be powered by the Temporal Time Skipping Test Server (part of the [Java SDK](https://github.com/temporalio/sdk-java)). * Note that the Time Skipping Test Server does not support full capabilities of the regular Temporal Server, and may * occasionally present different behaviors. For general Workflow testing, it is generally preferable to use {@link createLocal} * instead. * * Users can reuse this environment for testing multiple independent workflows, but not concurrently. Time skipping, * which is automatically done when awaiting a workflow result and manually done on sleep, is global to the * environment, not to the workflow under test. We highly recommend running tests serially when using a single * environment or creating a separate environment per test. * * By default, the latest release of the Test Server will be downloaded and cached to a temporary directory * (e.g. `$TMPDIR/temporal-test-server-sdk-typescript-*` or `%TEMP%/temporal-test-server-sdk-typescript-*.exe`). Note * that existing cached binaries will be reused without validation that they are still up-to-date, until the SDK * itself is updated. Alternatively, a specific version number of the Test Server may be provided, or the path to an * existing Test Server binary may be supplied; see {@link LocalTestWorkflowEnvironmentOptions.server.executable}. * * Note that the Test Server implementation may be changed to another one in the future. Therefore, there is no * guarantee that Test Server options, and particularly those provided through the `extraArgs` array, will continue to * be supported in the future. * * IMPORTANT: At this time, the Time Skipping Test Server is not supported on ARM platforms. Execution on Apple * silicon Macs will work if Rosetta 2 is installed. */ static createTimeSkipping(opts?: TimeSkippingTestWorkflowEnvironmentOptions): Promise; /** * Start a full Temporal server locally. * * This environment is good for testing full server capabilities, but does not support time skipping like * {@link createTimeSkipping} does. {@link supportsTimeSkipping} will always return `false` for this environment. * {@link sleep} will sleep the actual amount of time and {@link currentTimeMs} will return the current time. * * This local environment will be powered by [Temporal CLI](https://github.com/temporalio/cli), which is a * self-contained executable for Temporal. By default, Temporal's database will not be persisted to disk, and no UI * will be launched. * * By default, the latest release of the CLI will be downloaded and cached to a temporary directory * (e.g. `$TMPDIR/temporal-sdk-typescript-*` or `%TEMP%/temporal-sdk-typescript-*.exe`). Note that existing cached * binaries will be reused without validation that they are still up-to-date, until the SDK itself is updated. * Alternatively, a specific version number of the CLI may be provided, or the path to an existing CLI binary may be * supplied; see {@link LocalTestWorkflowEnvironmentOptions.server.executable}. * * Note that the Dev Server implementation may be changed to another one in the future. Therefore, there is no * guarantee that Dev Server options, and particularly those provided through the `extraArgs` array, will continue to * be supported in the future. */ static createLocal(opts?: LocalTestWorkflowEnvironmentOptions): Promise; /** * Create a new test environment using an existing server. You must already be running a server, which the test * environment will connect to. */ static createFromExistingServer(opts?: ExistingServerTestWorkflowEnvironmentOptions): Promise; /** * Create a new test environment */ private static create; /** * Kill the test server process and close the connection to it */ teardown(): Promise; /** * Wait for `durationMs` in "server time". * * This awaits using regular setTimeout in regular environments or manually skips time in time-skipping environments. * * Useful for simulating events far into the future like completion of long running activities. * * **Time skippping**: * * The time skippping server toggles between skipped time and normal time depending on what it needs to execute. * * This method is _likely_ to resolve in less than `durationMs` of "real time". * * @param durationMs number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string} * * @example * * `workflow.ts` * * ```ts * const activities = proxyActivities({ startToCloseTimeout: 2_000_000 }); * * export async function raceActivityAndTimer(): Promise { * return await Promise.race([ * wf.sleep(500_000).then(() => 'timer'), * activities.longRunning().then(() => 'activity'), * ]); * } * ``` * * `test.ts` * * ```ts * const worker = await Worker.create({ * connection: testEnv.nativeConnection, * activities: { * async longRunning() { * await testEnv.sleep(1_000_000); // <-- sleep called here * }, * }, * // ... * }); * ``` */ sleep: (durationMs: Duration) => Promise; /** * Get the current time known to this environment. * * For non-time-skipping environments this is simply the system time. For time-skipping environments this is whatever * time has been skipped to. */ currentTimeMs(): Promise; /** * Create a Nexus endpoint targeting a worker task queue. * * This is a convenience method that wraps `connection.operatorService.createNexusEndpoint` for easier * testing of Nexus services. * * @param name - The name of the Nexus endpoint * @param taskQueue - The task queue that will handle Nexus operations * @returns The created Nexus endpoint * * @example * ```ts * const endpoint = await testEnv.createNexusEndpoint('my-endpoint', 'my-task-queue'); * const endpointId = endpoint.id; * ``` */ createNexusEndpoint(name: string, taskQueue: string): Promise; /** * Delete a Nexus endpoint. * * This is a convenience method that wraps `connection.operatorService.deleteNexusEndpoint` for easier * testing of Nexus services. * * @param endpoint - The endpoint to delete (can pass the full endpoint object or just an object with id and version) * * @example * ```ts * const endpoint = await testEnv.createNexusEndpoint('my-endpoint', 'my-task-queue'); * // ... use the endpoint ... * await testEnv.deleteNexusEndpoint(endpoint); * ``` */ deleteNexusEndpoint(endpoint: Pick): Promise; } export type NexusEndpointIdentifier = { id: NonNullable; version: NonNullable; raw: temporal.api.nexus.v1.IEndpoint; }; /** * Options for {@link TestWorkflowEnvironment.create} */ type TestWorkflowEnvironmentOptions = { server: DevServerConfig | TimeSkippingServerConfig | ExistingServerConfig; client?: ClientOptionsForTestEnv; plugins?: (ClientPlugin | ConnectionPlugin | NativeConnectionPlugin)[]; }; type ExistingServerConfig = { type: 'existing'; }; type TestWorkflowEnvironmentOptionsWithDefaults = Required; export {};