AWS SDK v3 Client Mock Jest Matchers
aws-sdk-client-mock-jest provides custom Jest matchers that extend Jest's `expect` API, specifically designed to simplify testing AWS SDK v3 clients when used in conjunction with `aws-sdk-client-mock`. It enables developers to assert on AWS SDK command invocations with readable and intuitive syntax like `toHaveReceivedCommand` or `toHaveReceivedCommandWith`. The package is currently at version 4.1.0 and maintains an active release cadence, with several minor and patch releases in recent months, often including beta cycles. Its key differentiator is the seamless integration into Jest's testing framework, allowing for robust unit and integration tests of AWS Lambda functions, frontend applications, and Node.js services interacting with AWS, without needing to manually inspect mock call arguments. Version 4.1.0 notably introduced support for Vitest, broadening its compatibility within the JavaScript testing ecosystem.
Common errors
-
TypeError: expect(...).toHaveReceivedCommand is not a function
cause The Jest matchers have not been imported and registered with Jest's `expect` API.fixAdd `import 'aws-sdk-client-mock-jest';` to your test setup file (e.g., `setupFilesAfterEnv` in Jest configuration) or directly at the top of your test files. -
Matcher error: Received value must be an instance of AwsStub
cause The `expect()` assertion is being called on an object that is not an `AwsStub` instance returned by `mockClient()`.fixEnsure that `expect()` is called with the result of `mockClient(YourClient)` (e.g., `expect(ddbMock)`) not the client instance itself (e.g., `expect(ddbClient)`). -
Command type mismatch. Expected to receive a Command of type 'PutItemCommand', but received 'GetItemCommand'.
cause The test is asserting that a specific command type was received, but a different command type was actually invoked.fixReview your application code to confirm the correct AWS SDK command is being sent, or adjust your test assertion to match the actual command type invoked. -
Expected to receive 'DynamoDBClient.PutItemCommand' with input matching: { TableName: 'WrongTable' } but no matching command was received.cause The `toHaveReceivedCommandWith` matcher found the correct command type but no invocation matched the specified input parameters.fixInspect the input arguments passed to your AWS SDK command in the application code and ensure they precisely match (or are a partial match of) the object provided to `toHaveReceivedCommandWith`.
Warnings
- breaking The behavior of `expect.assertions()` was corrected for commands used with `toHaveReceivedCommandWith` matchers. If your tests relied on an incorrect assertion count for these matchers, they might now fail.
- gotcha When using `toHaveReceivedCommandWith`, partial matching for `Command` inputs was inconsistent in older versions. If you attempted to match only a subset of the command's input fields, it might have failed or behaved unexpectedly.
- gotcha Support for `@jest/globals` asymmetric matchers (e.g., `expect.any(String)`, `expect.objectContaining`) was improved in `v4.0.1`. Using them in `toHaveReceivedCommandWith` with older versions might have led to incorrect matching results.
- gotcha The package added `vitest` as an optional peer dependency starting from version 4.1.0-beta.0. While this broadens compatibility, ensure your project's testing setup correctly distinguishes between Jest and Vitest environments if both are present, to avoid potential conflicts or unexpected behavior.
Install
-
npm install aws-sdk-client-mock-jest -
yarn add aws-sdk-client-mock-jest -
pnpm add aws-sdk-client-mock-jest
Imports
- Matchers
import { toHaveReceivedCommand } from 'aws-sdk-client-mock-jest';import 'aws-sdk-client-mock-jest';
- Types
/// <reference types="aws-sdk-client-mock-jest" />
- CommonJS Setup
require('aws-sdk-client-mock-jest');
Quickstart
import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb';
import { mockClient } from 'aws-sdk-client-mock';
import 'aws-sdk-client-mock-jest'; // Import to enable Jest matchers
describe('DynamoDB interactions', () => {
let ddbMock: ReturnType<typeof mockClient>;
const tableName = 'MyTestTable';
beforeEach(() => {
ddbMock = mockClient(DynamoDBClient);
});
afterEach(() => {
ddbMock.reset();
});
it('should put an item into DynamoDB', async () => {
ddbMock.on(PutItemCommand).resolves({ Attributes: { id: { S: '123' } } });
const client = new DynamoDBClient({});
const command = new PutItemCommand({
TableName: tableName,
Item: { id: { S: '123' }, name: { S: 'Test Item' } },
});
await client.send(command);
expect(ddbMock).toHaveReceivedCommand(PutItemCommand);
expect(ddbMock).toHaveReceivedCommandTimes(PutItemCommand, 1);
expect(ddbMock).toHaveReceivedCommandWith(PutItemCommand, {
TableName: tableName,
Item: { id: { S: '123' } }, // Partial match works
});
expect(ddbMock).toHaveReceivedAnyCommand();
expect(ddbMock).toHaveReceivedAnyCommandTimes(1);
});
});