serverless-framework-test-plugin
Wraps the Serverless Framework (serverless.com) test ecosystem: serverless-offline (local HTTP emulator), serverless-jest-plugin / serverless-mocha-plugin (per-runtime test runners), and the `serverless invoke local` CLI for one-off invocations. Use when testing Lambda functions deployed via the Serverless Framework. Composes cold-start-budget-reference + lambda-timeout-budget-reference.
serverless-framework-test-plugin
Overview
The Serverless Framework (serverless.com/framework/docs) is one of the older deploy-frameworks for Lambda. Its test-friendly ecosystem includes:
When to use
Authoring
Install
npm install -g serverless
npm install --save-dev serverless-offline serverless-jest-plugin jestserverless.yml plugin registration
plugins:
- serverless-offline
- serverless-jest-plugin
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: getserverless invoke local (single invocation)
serverless invoke local --function hello --data '{"name":"world"}'Output: handler's return value (JSON), plus emulated Lambda log lines.
serverless-offline (local HTTP)
serverless offline --httpPort 3000Now curl http://localhost:3000/hello exercises the full Serverless → API Gateway → Lambda route.
serverless-jest-plugin
Per npmjs.com/package/serverless-jest-plugin:
serverless create test --function hello # Generates test scaffold
serverless invoke test # Runs testsThe scaffold uses Jest under the hood; tests follow standard Jest patterns:
import { hello } from '../handler';
test('returns greeting', async () => {
const event = { queryStringParameters: { name: 'world' } };
const response = await hello(event);
expect(response.statusCode).toBe(200);
expect(JSON.parse(response.body).message).toContain('Hello world');
});Direct handler test (lightweight)
// handler.ts
export const hello = async (event: any) => ({
statusCode: 200,
body: JSON.stringify({ message: `Hello ${event.queryStringParameters?.name ?? 'World'}` }),
});
// handler.test.ts
import { hello } from './handler';
test('hello-world', async () => {
const result = await hello({ queryStringParameters: {} });
expect(result.statusCode).toBe(200);
});This skips the Serverless plugin entirely - often the cleanest path.
Environment variables
serverless-offline reads serverless.yml env definitions:
provider:
environment:
DATABASE_URL: ${env:DATABASE_URL}Tests should mirror this via process.env.DATABASE_URL in jest setup.
Running
npx jest # Direct handler tests
serverless offline # Local HTTP emulator
serverless invoke local --function hello # CLI one-offCI integration
jobs:
serverless-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
- run: npm ci
- run: npx jestFor deployed-Lambda smoke tests:
- run: serverless deploy --stage staging
- run: npx jest tests/staging-smoke/Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Tests use serverless invoke local per test | Subprocess startup cost; slow | Direct handler invocation |
Skip serverless offline for routing tests | API Gateway routing untested | Use serverless offline for HTTP tests |
| Hardcoded env vars in test code | Drift from serverless.yml | Load via dotenv from .env.test |
Mocking event object incompletely | Handler reads event.headers → undefined | Use aws-sam-local-testing generate-event |
| Serverless plugin pinned to old version | Behaviour drift vs prod Lambda runtime | Match Lambda runtime version |
| No deployed smoke tests | Local-pass + prod-fail gap | Always include staging smoke |
| Treating serverless-jest as replacement for direct test | Adds plugin complexity for no gain | Use plain Jest |