Overview
Test your AWS Typescript Serverless API’s using Jest
Sample code is here
If you find any typo’s or cut-n-paste errors or mistakes please let me know.
Please also comment if you have any improvement suggestions.
The follow steps and examples was created on April 15th 2020 using:
- Node v12.16.1
- and Serverless Framework versions:
Framework Core: 1.67.3
Plugin: 3.6.6
SDK: 2.3.0
Components: 2.29.1
Setup from scratch
The following steps are all command line on a Unix platorm, please adjust for your platorm where required.
Create a new directory and chnage to it (for example):
mkdir serverless-e2e-typescript-example
cd serverless-e2e-typescript-example
Create an AWS Lambda serverless API:
npx serverless create --template aws-nodejs-typescript --name api
Here’s an example of the output:
❯ npx serverless create --template aws-nodejs-typescript --name api
Serverless: Generating boilerplate...
_______ __
| _ .-----.----.--.--.-----.----| .-----.-----.-----.
| |___| -__| _| | | -__| _| | -__|__ --|__ --|
|____ |_____|__| \___/|_____|__| |__|_____|_____|_____|
| | | The Serverless Application Framework
| | serverless.com, v1.67.3
-------'
Serverless: Successfully generated boilerplate for template: "aws-nodejs-typescript"
Install the node dependencies
npm install
Edit the serverless.yml
file so that we can set a default stage and region.
Under the provider
section add:
stage: ${opt:stage, 'dev'}
region: ${opt:region, 'us-east-1'}
Lets make our API endpoint output only a message and not echo the Lambda input
Edit handler.ts
, comment out line 9
// input: event
Deploy the API to the ‘dev’ stage.
Example deployment command and output:
> npx serverless --stage dev deploy
Serverless: Bundling with Webpack...
Time: 394ms
Built at: 04/15/2020 1:38:22 PM
Asset Size Chunks Chunk Names
handler.js 1.28 KiB 0 [emitted] handler
handler.js.map 5.27 KiB 0 [emitted] [dev] handler
Entrypoint handler = handler.js handler.js.map
[0] ./handler.ts 316 bytes {0} [built]
[1] external "source-map-support/register" 42 bytes {0} [built]
Serverless: Package lock found - Using locked versions
Serverless: Packing external modules: source-map-support@^0.5.10
Serverless: Packaging service...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service api.zip file to S3 (289.14 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............................
Serverless: Stack update finished...
Service Information
service: api
stage: dev
region: us-east-1
stack: api-dev
resources: 11
api keys:
None
endpoints:
GET - https://driyuairb6.execute-api.us-east-1.amazonaws.com/dev/hello
functions:
hello: api-dev-hello
layers:
None
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
Lets call the new API endpoint, copy the hello
endpoint from your deployment:
❯ curl https://driyuairb6.execute-api.us-east-1.amazonaws.com/dev/hello
{
"message": "Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!"
}
``
Great! Our new typescript API endpoint is working, lets setup the end-to-end testing.
Install test dependencies:
npm i -D jest ts-jest @types/jest axios
Create a testing directory and Jest config file
mkdir e2e
touch e2e/jest.config.js
This is how your jest.config.js
file should be:
module.exports = {
testEnvironment: "node",
transform: {
"^.+\\.tsx?$": "ts-jest",
},
}
You can create any testing file structure you prefer but for this example we’ll be creating files of the test functions then importing them into a single test file describing all the tests in order and assigning them with the imported functions.
Create a test file for the hello
API endpoint, I prefer to prefix with a number as it’s common to test API endpoints in sequence:
Create the file 100_hello.ts
with the code content:
import axios from "axios"
const url = process.env.URL
export const helloTest = () => {
test("should reply success", async () => {
const res = await axios.get(`${url}/hello`)
expect(res.status).toEqual(200)
expect(res.data.message).toMatch(/Your function executed successfully!/)
})
}
Create the test suite runner file index.test.js
with the code content:
import { helloTest } from "./100_hello"
describe("hello", helloTest)
Lets run the end-to-end test manually first, then we’ll create an npm script to simplify it:
URL=https://driyuairb6.execute-api.us-east-1.amazonaws.com/dev ./node_modules/.bin/jest -c e2e/jest.config.js --runInBand --bail
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
PASS e2e/index.test.ts
hello
✓ should reply success (474ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.059s, estimated 2s
Ran all test suites.
Yay! Our end-to-end test passes.
Let’s fix that ts-jest warning by adding "esModuleInterop": true
in the tsconfig.json file
"esModuleInterop": true
Run the tests manually again:
URL=https://driyuairb6.execute-api.us-east-1.amazonaws.com/dev ./node_modules/.bin/jest -c e2e/jest.config.js --runInBand --bail
PASS e2e/index.test.ts
hello
✓ should reply success (489ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.96s, estimated 2s
Ran all test suites.
Next lets create an npm script in package.json
:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"e2e": "jest -c e2e/jest.config.js --runInBand --bail e2e"
},
Now we can run our tests with:
URL=https://driyuairb6.execute-api.us-east-1.amazonaws.com/dev npm run e2e
> api@1.0.0 e2e /home/rudi/projects/serverless-e2e-typescript-example
> jest -c e2e/jest.config.js --runInBand e2e
PASS e2e/index.test.ts
hello
✓ should reply success (474ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.001s
Ran all test suites matching /e2e/i.
Finally lets clean up with:
npx serverless --stage dev remove
npx serverless --stage dev remove
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
.............
Serverless: Stack removal finished...