Key Takeaways
aws-sdk-client-mock allows Jest to intercept AWS SDK v3 calls, ensuring tests do not mutate actual DynamoDB or S3 resources.esbuild, eliminating the need for complex Webpack configurations to transpile TypeScript Lambda functions.Serverless computing eliminates server management, but it doesn't eliminate bugs. In fact, the geographically distributed event-driven nature of AWS Lambda often makes testing harder. If your development cycle involves saving a file, running sam deploy, waiting 180 seconds for CloudFormation to provision, and checking CloudWatch logs to see if a typo crashed your function, your development velocity is dead.
The solution is isolated local testing. By combining the AWS Serverless Application Model (SAM) with TypeScript and Jest, engineering teams can build robust test suites that execute in milliseconds before a single byte of code touches the AWS cloud.
The Serverless Testing Stack
AWS SAM CLI
Provides local Docker-based execution environments that mimic the AWS Lambda runtime, allowing local invocation of API Gateway endpoints.
TypeScript (esbuild)
Delivers static typing for AWS Lambda event payloads (e.g., APIGatewayProxyEvent). Natively transpiled and minified by SAM via esbuild.
Jest + Mocking
The premier testing framework for JavaScript logic isolation. Used alongside aws-sdk-client-mock to intercept and simulate AWS infrastructure calls.
Step 1: Initializing the SAM TypeScript Environment
Historically, setting up TypeScript with AWS SAM required tangled Webpack configurations. Today, SAM natively supports esbuild, handling transpilation automatically during the build process.
# Initialize a new project
sam init
# Select:
# 1 - AWS Quick Start Templates
# 2 - Hello World Example
# [y] - Use the most popular runtime and package type?
# TypeScript - Runtime selection
# Zip - Package type
Crucially, inspect your template.yaml. You will see SAM defining the esbuild configuration natively within the Metadata parameters of the Lambda resource, ensuring node_modules are excluded and code is minified for zero-cold-start performance.
Step 2: Configuring Jest for TypeScript and AWS
Once initialized, install the necessary testing dependencies. We need Jest, the TypeScript definitions, and the SDK mocking libraries for AWS SDK v3.
npm install -D jest @types/jest ts-jest
npm install -D aws-sdk-client-mock aws-sdk-client-mock-jest
# Initialize Jest configuration
npx ts-jest config:init
This generates a jest.config.js file that instructs Jest to pass .ts files through the ts-jest preset rather than choking on non-standard JavaScript syntax.
Step 3: Writing Testable Lambda Functions
A common anti-pattern in serverless development is writing thick handler functions that contain database logic, business logic, and API response formatting in a single block. This makes unit testing impossible.
✗ Untestable Pattern (Thick Handler)
export const handler = async (event) => {
const db = new DynamoDBClient({});
// API Gateway parsing
const body = JSON.parse(event.body);
// Database execution mixed with logic
await db.send(new PutItemCommand({...}));
// Hardcoded responses
return { statusCode: 200, body: "Success" };
};
✓ Testable Pattern (Thin Handler)
// dbService.ts (Isolated Logic)
export const saveUser = async (id, client) => {
return client.send(new PutItemCommand({...}));
};
// app.ts (Thin Routing layer)
export const handler = async (event) => {
// Only parses events and delegates
await saveUser(event.pathParameters.id, db);
return formatResponse(200, "Success");
};
Engineering Insight: When our dedicated teams build serverless architectures, we strictly enforce Hexagonal Architecture (Ports and Adapters). The core typescript business logic knows nothing about AWS API Gateway or DynamoDB—it simply accepts interfaces, making the logic 100% unit-testable without requiring AWS mocks.
Step 4: Mocking AWS SDK v3 with Jest
When you must test the integration layer that interacts with AWS services, never make live API calls. Use aws-sdk-client-mock to intercept the requests.
import { mockClient } from 'aws-sdk-client-mock';
import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb';
import { handler } from '../../app';
// Mock the specific client
const ddbMock = mockClient(DynamoDBDocumentClient);
describe('Lambda API Handler', () => {
beforeEach(() => {
ddbMock.reset();
});
it('should return 200 and data when user exists', async () => {
// Stage the mocked AWS response
ddbMock.on(GetCommand).resolves({
Item: { id: '123', name: 'Serverless Pro' }
});
// Construct a mock API Gateway Event
const event = { pathParameters: { id: '123' } } as any;
const response = await handler(event, {} as any);
expect(response.statusCode).toEqual(200);
expect(JSON.parse(response.body).name).toEqual('Serverless Pro');
});
});
Step 5: Local Integration Testing with SAM
While unit tests are fast, they mock reality. To verify that your IAM permissions, environment variables, and API Gateway configurations are correct, use the SAM CLI to spin up a local Docker representation of the AWS cloud.
- Build the artifacts:
sam buildruns esbuild, transpiling the TypeScript to minified JavaScript. - Start local API:
sam local start-apimounts your built lambda code inside a Docker container mimicking the AWS runtime. - Integration Test: Use a tool like Supertest alongside Jest to fire real HTTP requests at
localhost:3000to verify the entire stack logic.
Need Expert Cloud Engineers?
Boundev provides senior cloud architecture talent through software outsourcing. Expand your team with AWS certified engineers who structure CI/CD pipelines, write comprehensive Jest coverage, and optimize serverless backend performance.
Talk to Our EngineersFAQ
Why use AWS SAM instead of Serverless Framework?
AWS SAM is officially supported by AWS and is essentially an extension of CloudFormation. This means any valid CloudFormation syntax works within a SAM template natively. SAM CLI's local Docker environment perfectly mimics the AWS Lambda runtimes, providing high-fidelity local testing through commands like sam local invoke and sam local start-api. While Serverless Framework is excellent and highly adopted, SAM offers deep, native integration into the AWS ecosystem.
How do I transpile TypeScript for AWS Lambda?
You no longer need to write complex Webpack configurations. Modern AWS SAM templates directly support esbuild via the Metadata Properties block in the template.yaml file. When you run sam build, SAM automatically uses esbuild to transpile your .ts files down to highly optimized, minified JavaScript that drastically reduces Lambda cold boot times.
How do you mock AWS SDK v3 in Jest?
Unlike AWS SDK v2 where you could mock entire service classes, SDK v3 uses a modular architecture with command objects. The industry standard approach is to use the aws-sdk-client-mock library. You wrap the initialized client (e.g., DynamoDBDocumentClient) with mockClient() and then use the .on(Command).resolves({}) syntax to force specific deterministic responses during your unit tests without making actual network requests.
