aws-sdk-client-mock for TypeScript
aws-sdk-client-mock is an npm package that mocks AWS SDK for JavaScript v3 clients directly, without a network call or a container.
Busque em todas as páginas da documentação
aws-sdk-client-mock is an npm package that mocks AWS SDK for JavaScript v3 clients directly, without a network call or a container.
It wraps a client's send() method so that when your code calls client.send(new SomeCommand(...)), the mock intercepts it and returns whatever response you configured - or throws whatever error you configured.
Create the mock once per client class with
mockClient(...), then configure per-command responses with.on(Command).resolves(...).
# --- Python (boto3) ---
# The equivalent test pattern in Python uses moto's @mock_aws
# decorator, not aws-sdk-client-mock (that package is TS/JS-only).
import boto3
from moto import mock_aws
@mock_aws
def test_get_object_returns_body():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="reports")
s3.put_object(Bucket="reports", Key="q1.csv", Body=b"revenue,1000")
obj = s3.get_object(Bucket="reports", Key="q1.csv")
assert obj["Body"].read() == b"revenue,1000"// --- TypeScript (AWS SDK v3) ---
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
import { mockClient } from "aws-sdk-client-mock";
import { sdkStreamMixin } from "@aws-sdk/util-stream-node";
import { Readable } from "node:stream";
const s3Mock = mockClient(S3Client);
test("get_object returns body", async () => {
s3Mock.on(GetObjectCommand, { Bucket: "reports", Key: "q1.csv" }).resolves({
Body: sdkStreamMixin(Readable.from(["revenue,1000"])) as never,
});
const s3 = new S3Client({});
const res = await s3.send(new GetObjectCommand({ Bucket: "reports", Key: "q1.csv" }));
expect(await res.Body!.transformToString()).toBe("revenue,1000");
});When to reach for this:
A fuller test that stubs multiple commands, varies responses by input, and asserts on call counts.
# --- Python (boto3) ---
import boto3
from moto import mock_aws
def process_pending_orders(table_name: str) -> int:
ddb = boto3.resource("dynamodb")
table = ddb.Table(table_name)
resp = table.scan(FilterExpression="#s = :pending", ExpressionAttributeNames={"#s": "status"},
ExpressionAttributeValues={":pending": "PENDING"})
for item in resp["Items"]:
table.update_item(Key={"id": item["id"]}, UpdateExpression="SET #s = :done",
ExpressionAttributeNames={"#s": "status"},
ExpressionAttributeValues={":done": "DONE"})
return len(resp["Items"])
@mock_aws
def test_process_pending_orders():
ddb = boto3.resource("dynamodb", region_name="us-east-1")
ddb.create_table(
TableName="Orders",
KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}],
BillingMode="PAY_PER_REQUEST",
)
table = ddb.Table("Orders")
table.put_item(Item={"id": "o-1", "status": "PENDING"})
table.put_item(Item={"id": "o-2", "status": "DONE"})
count = process_pending_orders("Orders")
assert count == 1
assert table.get_item(Key={"id": "o-1"})["Item"]["status"] == "DONE"// --- TypeScript (AWS SDK v3) ---
import {
DynamoDBClient,
ScanCommand,
UpdateItemCommand,
} from "@aws-sdk/client-dynamodb";
import { mockClient } from "aws-sdk-client-mock";
import "aws-sdk-client-mock-jest"; // adds toHaveReceivedCommandWith / Times matchers
async function processPendingOrders(ddb: DynamoDBClient, tableName: string): Promise<number> {
const scan = await ddb.send(new ScanCommand({
TableName: tableName,
FilterExpression: "#s = :pending",
ExpressionAttributeNames: { "#s": "status" },
ExpressionAttributeValues: { ":pending": { S: "PENDING" } },
}));
const items = scan.Items ?? [];
for (const item of items) {
await ddb.send(new UpdateItemCommand({
TableName: tableName,
Key: { id: item.id },
UpdateExpression: "SET #s = :done",
ExpressionAttributeNames: { "#s": "status" },
ExpressionAttributeValues: { ":done": { S: "DONE" } },
}));
}
return items.length;
}
const ddbMock = mockClient(DynamoDBClient);
beforeEach(() => ddbMock.reset());
test("processPendingOrders updates only pending items", async () => {
ddbMock.on(ScanCommand).resolves({
Items: [{ id: { S: "o-1" }, status: { S: "PENDING" } }],
});
ddbMock.on(UpdateItemCommand).resolves({});
const count = await processPendingOrders(new DynamoDBClient({}), "Orders");
expect(count).toBe(1);
expect(ddbMock).toHaveReceivedCommandTimes(UpdateItemCommand, 1);
expect(ddbMock).toHaveReceivedCommandWith(UpdateItemCommand, {
TableName: "Orders",
Key: { id: { S: "o-1" } },
});
});What this demonstrates:
get_item check is a genuine round trip.aws-sdk-client-mock-jest (or the built-in Vitest matchers) package adds the toHaveReceivedCommand* assertions used above.mockClient(ServiceClient) returns a Sinon-based stub that intercepts every send() call made by any instance of that client class..on(Command) matches any instance of that command; .on(Command, input) matches only when the input matches (a partial match by default)..resolves(value) returns a successful response; .rejects(error) throws; .resolvesOnce(...) chains a sequence of responses for repeated calls.mockClient(...) is usually created once at module scope, so its configured stubs and call history persist across test cases unless cleared..reset() in a beforeEach to clear both stubs and the recorded call history..restore() fully removes the mock and returns the client to real behavior - rarely needed inside a single test file, but useful when tearing down shared setup.toHaveReceivedCommand(Command) checks the command was sent at all.toHaveReceivedCommandTimes(Command, n) checks the exact call count - useful for catching an accidental double-write.toHaveReceivedCommandWith(Command, input) checks the exact (or partial) input your code sent, catching bugs where a parameter is wrong even though the mocked call still "succeeds."aws-sdk-client-mock-jest package for Jest; Vitest users can import the same assertions via aws-sdk-client-mock-vitest or use raw Sinon call inspection on the mock..reset() between tests - stubs and call history persist at module scope. Fix: call mock.reset() in beforeEach..on(Command) with no input matches every call to that command, which can mask a bug where the wrong parameters are sent. Fix: add an input matcher when the specific parameters matter to the test.mockClient patches the class, so constructing the client after configuring stubs is fine, but importing a different client instance (e.g., a singleton set up before the mock exists) can bypass it. Fix: construct or import the client after mockClient(...) runs, or ensure your app code doesn't cache a client from before test setup.GetObjectCommand's Body is a stream, and a plain string won't satisfy the real SDK's stream interface. Fix: wrap fixture bodies with sdkStreamMixin(Readable.from([...])) from @aws-sdk/util-stream-node.| Alternative | Use When | Don't Use When |
|---|---|---|
| aws-sdk-client-mock | TypeScript/JS unit tests against SDK v3 | You need real, cross-service integration behavior |
| LocalStack | Integration tests needing a real server | A stubbed command response already covers the case |
Manual jest.mock() of the whole module | A very small, one-off test | You're stubbing many commands - the boilerplate grows fast |
| Contract test vs real AWS | Verifying real IAM/quota edges before release | Everyday unit testing |
aws-sdk-client-mock on npm. It's the standard way to mock AWS SDK for JavaScript v3 command clients in Jest or Vitest tests.
No. It only wraps the client's send() method in-process; there's no server or container involved, which is why tests run in milliseconds.
Pass a second argument to .on(Command, input) to match specific input, and chain multiple .on(...) calls for different inputs on the same command.
It adds the toHaveReceivedCommand* custom matchers used to assert on what was sent, not just what was returned. Without it you'd inspect the underlying Sinon stub's call history manually.
Yes, since it wraps the shared send() method every SDK v3 client class exposes, regardless of which service the client is for.
Stubs and call history from a previous test remain active, which can make a later test pass for the wrong reason or fail unexpectedly. Always reset in beforeEach.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última atualização: 23 de jul. de 2026