
Security News
/Research
Popular node-ipc npm Package Infected with Credential Stealer
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.
@aws/durable-execution-sdk-js-testing
Advanced tools
AWS Durable Execution Testing SDK for TypeScript
Testing utilities for the AWS Durable Execution SDK for JavaScript and TypeScript.
This package provides testing tools for durable functions both locally and in the cloud:
LocalDurableTestRunner - Execute and test durable functions locally without AWS deployment
CloudDurableTestRunner - Test against deployed AWS Lambda functions
Testing Capabilities
run-durable CLI - Command-line tool for quick testing without writing test code
npx run-durable your-function.jsnpm install --save-dev @aws/durable-execution-sdk-js-testing
import {
withDurableExecution,
DurableContext,
} from "@aws/durable-execution-sdk-js";
const handler = async (event: any, context: DurableContext) => {
// Execute a durable step with automatic retry
const userData = await context.step("fetch-user", async () =>
fetchUserFromDB(event.userId),
);
// Wait for 5 seconds
await context.wait({ seconds: 5 });
// Process data in another step
const result = await context.step("process-user", async () =>
processUser(userData),
);
return result;
};
export const lambdaHandler = withDurableExecution(handler);
import {
LocalDurableTestRunner,
WaitingOperationStatus,
} from "@aws/durable-execution-sdk-js-testing";
import { lambdaHandler } from "./lambdaHandler";
beforeAll(() =>
LocalDurableTestRunner.setupTestEnvironment({
skipTime: true,
}),
);
afterAll(() => LocalDurableTestRunner.teardownTestEnvironment());
describe("LocalDurableTestRunner", () => {
let runner;
beforeEach(() => {
runner = new LocalDurableTestRunner({
handlerFunction: lambdaHandler,
});
});
it("should wait for 5 seconds and return result", async () => {
const execution = await runner.run({ payload: { userId: "123" } });
expect(execution.getStatus()).toBe("SUCCEEDED");
expect(execution.getOperations()).toHaveLength(3); // fetch-user, wait, process-user
// Check the fetch-user step
const fetchStep = runner.getOperation("fetch-user");
await fetchStep.waitForData(WaitingOperationStatus.COMPLETED);
const fetchDetails = fetchStep.getStepDetails();
expect(fetchDetails?.result).toBeDefined();
// Check the wait operation
const waitOp = runner.getOperationByIndex(1);
const waitDetails = waitOp.getWaitDetails();
expect(waitDetails?.waitSeconds).toBe(5);
// Check the process-user step
const processStep = runner.getOperation("process-user");
await processStep.waitForData(WaitingOperationStatus.COMPLETED);
const processDetails = processStep.getStepDetails();
expect(processDetails?.result).toBeDefined();
});
});
import {
CloudDurableTestRunner,
WaitingOperationStatus,
} from "@aws/durable-execution-sdk-js-testing";
describe("CloudDurableTestRunner", () => {
let runner;
beforeEach(() => {
runner = new CloudDurableTestRunner({
functionName: "my-durable-function", // Your deployed function name
});
});
it("should wait for 5 seconds and return result", async () => {
const execution = await runner.run({ payload: { userId: "123" } });
expect(execution.getStatus()).toBe("SUCCEEDED");
expect(execution.getOperations()).toHaveLength(3); // fetch-user, wait, process-user
// Check the fetch-user step
const fetchStep = runner.getOperation("fetch-user");
const fetchDetails = fetchStep.getStepDetails();
expect(fetchDetails?.result).toBeDefined();
expect(fetchDetails?.attempt).toBe(1);
// Check the wait operation
const waitOp = runner.getOperationByIndex(1);
const waitDetails = waitOp.getWaitDetails();
expect(waitDetails?.waitSeconds).toBe(5);
// Check the process-user step
const processStep = runner.getOperation("process-user");
const processDetails = processStep.getStepDetails();
expect(processDetails?.result).toBeDefined();
});
});
This README provides a quick reference for the Testing SDK's main features. For more detailed information:
Run durable functions locally with a simulated durable execution backend.
import { LocalDurableTestRunner } from "@aws/durable-execution-sdk-js-testing";
import { handler } from "./my-durable-function";
// Set up test environment with optional time skipping
await LocalDurableTestRunner.setupTestEnvironment({
skipTime: true, // Skip wait delays for faster tests
});
const runner = new LocalDurableTestRunner({
handlerFunction: handler,
});
const execution = await runner.run({ payload: { test: "data" } });
// Assert on results
expect(execution.getStatus()).toBe("SUCCEEDED");
expect(execution.getResult()).toEqual(expectedValue);
// Assert on operations
const operations = execution.getOperations();
expect(operations).toHaveLength(3);
// Clean up test environment
await LocalDurableTestRunner.teardownTestEnvironment();
Mock external dependencies using Jest or your preferred testing framework:
import { LocalDurableTestRunner } from "@aws/durable-execution-sdk-js-testing";
// Mock external functions
jest.mock("../services/userService", () => ({
fetchUserFromDB: jest.fn(),
processUser: jest.fn(),
}));
import { fetchUserFromDB, processUser } from "../services/userService";
import { lambdaHandler } from "./lambdaHandler";
const mockFetchUser = fetchUserFromDB as jest.MockedFunction<
typeof fetchUserFromDB
>;
const mockProcessUser = processUser as jest.MockedFunction<typeof processUser>;
describe("Mocked Dependencies", () => {
let runner: LocalDurableTestRunner;
beforeAll(() =>
LocalDurableTestRunner.setupTestEnvironment({ skipTime: true }),
);
afterAll(() => LocalDurableTestRunner.teardownTestEnvironment());
beforeEach(() => {
runner = new LocalDurableTestRunner({ handlerFunction: lambdaHandler });
// Reset mocks
mockFetchUser.mockClear();
mockProcessUser.mockClear();
});
it("should call mocked functions and return expected results", async () => {
// Setup mocks
const userData = { id: "123", name: "John Doe" };
const processedResult = { id: "123", processed: true };
mockFetchUser.mockResolvedValue(userData);
mockProcessUser.mockResolvedValue(processedResult);
// Run test
const execution = await runner.run({ payload: { userId: "123" } });
// Verify results
expect(execution.getStatus()).toBe("SUCCEEDED");
expect(execution.getResult()).toEqual(processedResult);
// Verify mock calls
expect(mockFetchUser).toHaveBeenCalledWith("123");
expect(mockProcessUser).toHaveBeenCalledWith(userData);
// Verify operations
const fetchStep = runner.getOperation("fetch-user");
const fetchDetails = fetchStep.getStepDetails();
expect(fetchDetails?.result).toEqual(userData);
});
});
Register additional functions that can be invoked during local testing of chained invocations:
const mainHandler = withDurableExecution(async (event, context) => {
await context.invoke("workflow-a:$LATEST");
await context.invoke("workflow-b:$LATEST");
await context.invoke("utility-function");
await context.invoke("utility-helper");
});
const runner = new LocalDurableTestRunner({ handlerFunction: mainHandler });
// Register durable functions
runner.registerDurableFunction("workflow-a:$LATEST", durableWorkflowA);
// Register regular functions
runner.registerFunction("utility-function", utilityHandler);
// Method chaining is supported
runner
.registerDurableFunction("workflow-b:$LATEST", durableWorkflowB)
.registerFunction("helper", helperHandler);
Test against deployed Lambda functions in AWS.
import {
CloudDurableTestRunner,
InvocationType,
} from "@aws/durable-execution-sdk-js-testing";
import { LambdaClient } from "@aws-sdk/client-lambda";
const runner = new CloudDurableTestRunner({
functionName: "MyDurableFunction",
client: new LambdaClient({ region: "us-east-1" }), // optional
config: {
pollInterval: 1000, // optional, default 1000ms
invocationType: InvocationType.RequestResponse, // optional
},
});
const execution = await runner.run({ payload: { userId: "123" } });
expect(execution.getStatus()).toBe("SUCCEEDED");
Both runners return a TestResult object with methods for assertions:
const execution = await runner.run();
// Get execution status and results
execution.getStatus(); // "SUCCEEDED" | "FAILED" | "RUNNING" | etc.
execution.getResult(); // Returns the function result
execution.getError(); // Returns error details if failed
// Get operations
execution.getOperations(); // All operations
execution.getOperations({ status: "SUCCEEDED" }); // Filter by status
// Get execution history and invocations
execution.getHistoryEvents(); // Detailed event history
execution.getInvocations(); // Handler invocation details
// Print operations table to console
execution.print(); // Default columns
execution.print({ name: true, status: true, duration: true }); // Custom columns
Access specific operations for detailed assertions:
// Get operations by different methods
const operation = runner.getOperation("my-step"); // By name
const firstOp = runner.getOperationByIndex(0); // By execution order
const secondNamedOp = runner.getOperationByNameAndIndex("my-step", 1); // By name + index
const opById = runner.getOperationById("abc123"); // By unique ID
// Wait for operation data to be available
await operation.waitForData(); // Default to STARTED status
await operation.waitForData(WaitingOperationStatus.COMPLETED);
// Get operation details based on type
const stepDetails = operation.getStepDetails(); // For step operations
const contextDetails = operation.getContextDetails(); // For context operations
const callbackDetails = operation.getCallbackDetails(); // For callback operations
const waitDetails = operation.getWaitDetails(); // For wait operations
// Get basic operation information
operation.getName();
operation.getStatus();
operation.getStartTimestamp();
operation.getEndTimestamp();
For callback operations, you can send responses:
const callback = runner.getOperation("my-callback");
await callback.waitForData(WaitingOperationStatus.SUBMITTED);
// Send callback responses
await callback.sendCallbackSuccess("result data");
await callback.sendCallbackFailure({ errorMessage: "Failed" });
await callback.sendCallbackHeartbeat();
// Constructor
new LocalDurableTestRunner({ handlerFunction: handler });
// Environment setup
await LocalDurableTestRunner.setupTestEnvironment({ skipTime: true });
// Environment teardown
await LocalDurableTestRunner.teardownTestEnvironment();
// Basic configuration
new CloudDurableTestRunner({ functionName: "MyFunction:$LATEST" });
// Advanced configuration
new CloudDurableTestRunner({
functionName: "MyFunction:$LATEST",
client: new LambdaClient({ region: "us-east-1" }),
config: { pollInterval: 500, invocationType: InvocationType.Event },
});
The reset() method is required if you reuse the same runner instance between tests. Data about an individual execution is cleared from the runner instance when reset() is called.
describe("Reusing Runner Instance", () => {
let runner: LocalDurableTestRunner;
beforeAll(() => {
// Create runner once
runner = new LocalDurableTestRunner({ handlerFunction: handler });
});
beforeEach(() => {
// Reset state when reusing the same instance
runner.reset();
});
// ... tests
});
See CONTRIBUTING for more information.
This project is licensed under the Apache-2.0 License.
FAQs
AWS Durable Execution Testing SDK for TypeScript
We found that @aws/durable-execution-sdk-js-testing demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.

Security News
TeamPCP and BreachForums are promoting a Shai-Hulud supply chain attack contest with a $1,000 prize for the biggest package compromise.

Security News
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.