Engineering

Testing Serverless Like a Pro: AWS SAM, TypeScript, and Jest

B

Boundev Team

Mar 7, 2026
14 min read
Testing Serverless Like a Pro: AWS SAM, TypeScript, and Jest

Serverless architectures remove infrastructure overhead, but they dramatically shift the burden onto testing strategies. Without local isolation, developers testing AWS Lambda functions are forced into agonizing 3-minute deploy-to-cloud feedback loops, stalling productivity. By uniting the AWS Serverless Application Model (SAM) with TypeScript for strong typing and Jest for robust mocking, teams can execute cloud-like tests locally in milliseconds. This tutorial demystifies the modern serverless testing pipeline: configuring esbuild for rapid transpilation, utilizing sam local invoke for API Gateway simulations, and leveraging aws-sdk-client-mock to isolate interactions with DynamoDB and S3.

Key Takeaways

Testing AWS Lambda functions in the cloud during development creates an agonizing feedback loop; local emulation using the AWS SAM CLI restores millisecond feedback.
The modern stack for serverless backends combines AWS SAM for declarative infrastructure, TypeScript for static typing, and Jest for isolated unit testing.
Leveraging aws-sdk-client-mock allows Jest to intercept AWS SDK v3 calls, ensuring tests do not mutate actual DynamoDB or S3 resources.
AWS SAM now natively supports esbuild, eliminating the need for complex Webpack configurations to transpile TypeScript Lambda functions.
Boundev provides staff augmentation with cloud-native developers who architect highly testable, CI/CD-ready serverless applications.

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.

terminal bash
# 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.

terminal bash
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.

tests/unit/handler.test.ts typescript
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.

  1. Build the artifacts: sam build runs esbuild, transpiling the TypeScript to minified JavaScript.
  2. Start local API: sam local start-api mounts your built lambda code inside a Docker container mimicking the AWS runtime.
  3. Integration Test: Use a tool like Supertest alongside Jest to fire real HTTP requests at localhost:3000 to 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 Engineers

FAQ

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.

Tags

#AWS SAM#TypeScript#Jest#Serverless#AWS Lambda
B

Boundev Team

At Boundev, we're passionate about technology and innovation. Our team of experts shares insights on the latest trends in AI, software development, and digital transformation.

Ready to Transform Your Business?

Let Boundev help you leverage cutting-edge technology to drive growth and innovation.

Get in Touch

Start Your Journey Today

Share your requirements and we'll connect you with the perfect developer within 48 hours.

Get in Touch