aws-sdk-client-mock review
aws-sdk-client-mock 4.1.0 replaces the `send` method on AWS SDK for JavaScript v3 clients with a Sinon stub. Tests can choose a response by Command class, match all or part of its input, return different results on consecutive calls, and inspect what was sent. The current release adds `commandCall`, which retrieves one indexed call for a chosen Command. This is a unit-test boundary around `Client#send`; it does not exercise credentials, signing, middleware, retries, HTTP transport, or AWS service behavior. Our package check found bundled TypeScript declarations and working CommonJS and ESM loading.
aws-sdk-client-mock 4.1.0 installed in 2.7 seconds with 17 packages, used 8 MB in our sandbox, and returned 0 audit findings, making it a practical dev dependency for AWS SDK v3 `send` unit tests. Do not install it as proof that credentials, middleware, retries, or AWS itself will behave correctly.
We installed it
| Install | ✓ · 2.7s | 17 packages on disk · 8 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 250.7 KB | gzipped (719.1 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does aws-sdk-client-mock install cleanly?
Yes. In a fresh container with an empty cache, npm install aws-sdk-client-mock finished in 3 seconds, leaving 17 packages and 8 MB on disk. npm audit reported no known vulnerabilities.
How much does aws-sdk-client-mock add to a browser bundle?
250.7 KB gzipped (719.1 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does aws-sdk-client-mock work with both ESM and CommonJS?
Yes. Both import 'aws-sdk-client-mock' and require('aws-sdk-client-mock') worked in Node 22 in our run. The package is published as CommonJS.
Does aws-sdk-client-mock include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
aws-sdk-client-mock or sinon: which should you use?
sinon: Use a direct send stub when one client instance and a few fixed responses are all the test needs. aws-sdk-client-mock 4.1.0 installed in 2.7 seconds with 17 packages, used 8 MB in our sandbox, and returned 0 audit findings, making it a practical dev dependency for AWS SDK v3 send unit tests.
When should you not use aws-sdk-client-mock?
You need to test IAM, SigV4 signing, middleware, retries, endpoint selection, or wire serialization. Replacing send bypasses every one of those paths.
Use it if
- Your unit tests call AWS SDK v3 clients through `client.send(new Command(input))` and must stay offline.
- A test needs typed responses plus partial or exact matching against Command input.
- You want to assert Command order and payloads without changing production client construction.
- Your suite can reset a shared Sinon-backed stub between cases and keep a separate integration layer for AWS behavior.
- You need to test IAM, SigV4 signing, middleware, retries, endpoint selection, or wire serialization. Replacing `send` bypasses every one of those paths.
- The code still uses AWS SDK v2 service methods. The README's compatibility table and examples cover v3 Client and Command classes; `aws-sdk-mock` targets the older API.
- Several `@smithy/types` versions coexist in your lockfile and cannot be aligned. The README documents client assignment errors caused by mismatched middleware-stack types.
- Your test depends on presigning, waiters, or a realistic local AWS service. Those behaviors are outside the `Client#send` stub and fit direct helper mocks or LocalStack better.
- A 719.1 KB minified browser test dependency is unacceptable. Our full-package esbuild check produced 250.7 KB gzipped, so keep it out of shipped browser code.
Setup reality
We installed aws-sdk-client-mock 4.1.0 in 2.7 seconds in our fresh Node 22 sandbox. The install left 17 packages and 8 MB on disk. npm audit reported 0 known vulnerabilities. The package itself has 3 direct dependencies, no peer dependencies, 184 KB unpacked, an MIT license, and bundled TypeScript declarations. Both require() and ESM import worked even though the CommonJS package has no exports map.
No AWS credentials, region, endpoint, or emulator is required because the library replaces Client#send. An unmatched call resolves to undefined, which can make the failure appear later when application code reads a missing output field. Configure a fallback or every expected Command. reset() clears behavior and history while leaving the stub installed; restore() puts the real method back and may let a later test reach the network.
The README calls out type failures when installed AWS clients resolve different @smithy/types versions. Align the @aws-sdk/* packages or force one Smithy type version before weakening types. Partial input matching is the default, and strict matching needs the third true argument. Broader behaviors should be registered before narrower ones because a broad matcher added later can take precedence. When mixing class and instance mocks, create the instance mock first.
Our browser bundle of the package was 719.1 KB minified and 250.7 KB gzipped. That cost includes a testing stack and does not belong in production browser output. Jest and Vitest assertions require the separate aws-sdk-client-mock-jest package, with its /vitest entry under Vitest. S3 stream responses also need @smithy/util-stream and sdkStreamMixin; multipart upload tests must stub the individual Commands that Upload sends.
Patterns
Return one SNS result mock-command-response
import { mockClient } from 'aws-sdk-client-mock';
import { PublishCommand, SNSClient } from '@aws-sdk/client-sns';
const snsMock = mockClient(SNSClient);
snsMock.on(PublishCommand).resolves({ MessageId: 'msg-123' });
const sns = new SNSClient({});
const result = await sns.send(new PublishCommand({ Message: 'hello' }));Version 4.1.0 resolves an unmatched mocked `send` call to `undefined`, so set behavior for every output shape that production code reads.
Match part or all of the input match-command-input
snsMock.on(PublishCommand, { Message: 'hello' })
.resolves({ MessageId: 'partial' });
snsMock.on(PublishCommand, {
TopicArn: 'arn:aws:sns:us-east-1:111111111111:events',
Message: 'strict',
}, true).resolves({ MessageId: 'exact' });Input matching is partial unless the third argument is `true`; strict mode rejects a call that contains any extra input field.
Provide a fallback for any Command set-default-response
snsMock.resolves({});
snsMock.on(PublishCommand)
.resolves({ MessageId: 'publish-result' });Register the broad fallback first. A broad behavior added after a specific one can win the match and hide the specific response.
Change the result across calls return-sequential-results
snsMock.on(PublishCommand)
.resolvesOnce({ MessageId: 'first' })
.resolvesOnce({ MessageId: 'second' })
.resolves({ MessageId: 'later' });After 2 one-time responses are consumed, the final `resolves` value handles every later matching call.
Return an AWS-shaped error reject-command
const error = new Error('rate exceeded');
error.name = 'ThrottlingException';
Object.assign(error, { $metadata: { httpStatusCode: 429 } });
snsMock.on(PublishCommand).rejects(error);Set the error `name` and `$metadata` that the application checks; this stub does not generate retry metadata or run retry middleware.
Read client configuration in a fake compute-response
snsMock.on(PublishCommand).callsFake(async (input, getClient) => {
const region = await getClient().config.region();
return { MessageId: `${region}:${input.Message}` };
});`getClient()` returns the client for this call, but the fake still bypasses the AWS middleware stack and network validation.
Limit the stub to one client object mock-one-instance
const primary = new SNSClient({ region: 'us-east-1' });
const secondary = new SNSClient({ region: 'eu-west-1' });
const primaryMock = mockClient(primary);
primaryMock.resolves({ MessageId: 'primary-only' });
await primary.send(new PublishCommand({ Message: 'test' }));
// secondary.send is unchangedCreate instance mocks before a class mock when both are needed; the README warns that reversing this order changes which instances stay stubbed.
Clear calls between tests reset-test-state
const snsMock = mockClient(SNSClient);
beforeEach(() => { snsMock.reset(); });
afterAll(() => { snsMock.restore(); });`reset()` clears history and behavior but keeps the stub. `restore()` reinstalls the real `send` method and can re-enable network calls.
Read matching calls by index inspect-command-calls
const publishes = snsMock.commandCalls(PublishCommand, { Message: 'hello' });
expect(publishes).toHaveLength(2);
expect(publishes[0].args[0].input.TopicArn).toContain(':events');
const secondPublish = snsMock.commandCall(1, PublishCommand);The 4.1.0 `commandCall` index is zero-based among calls for that Command; `call` indexes every recorded `send`.
Load Vitest Command assertions use-runner-matchers
import 'aws-sdk-client-mock-jest/vitest';
expect(snsMock).toHaveReceivedCommandWith(
PublishCommand,
{ Message: expect.stringContaining('hello') }
);Install `aws-sdk-client-mock-jest` separately and use its `/vitest` entry; the package's default matcher entry is for Jest.
Stub a DocumentClient query mock-dynamodb-document-client
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, QueryCommand } from '@aws-sdk/lib-dynamodb';
const ddbMock = mockClient(DynamoDBDocumentClient);
ddbMock.on(QueryCommand).resolves({ Items: [{ pk: 'USER#1' }] });
const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));
await ddb.send(new QueryCommand({ TableName: 'app' }));Mock `DynamoDBDocumentClient` when application code sends `@aws-sdk/lib-dynamodb` Commands; stubbing the lower-level client will miss that call.
Return an S3 body with SDK helpers mock-s3-stream
import { Readable } from 'node:stream';
import { sdkStreamMixin } from '@smithy/util-stream';
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
const s3Mock = mockClient(S3Client);
const body = sdkStreamMixin(Readable.from(['hello']));
s3Mock.on(GetObjectCommand).resolves({ Body: body });Install `@smithy/util-stream`; a plain Node stream does not have the `transformToString` helper returned on a real S3 response body.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| sinon | npm | Use a direct `send` stub when one client instance and a few fixed responses are all the test needs. |
| aws-sdk-mock | npm | Use it for code built on the monolithic AWS SDK for JavaScript v2 service API. |
| testcontainers | npm | Use it with LocalStack when serialization, endpoints, retries, and service-like responses must run in the test. |
More testing guides
pytest · chai · jsdom · vitest · playwright · coverage · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

