Part 3: Local Test
This is the third part of a series about creating Azure Functions in TypeScript. In this part we add a test using the Jest test framework and then use the CircleCI continuous integration framework to run the test automatically each time code is pushed to GitHub.
The code after this third part.
Writing the Test
Since we’re coding in TypeScript we also have to install ts-jest
and @types/jest
when installing jest
.
$ yarn add --exact --dev jest ts-jest @types/jest
(Side note: Installing Jest blows up the number of Node packages from 108 to 448. These guys really like using packages.)
Our test is pretty straight forward: It creates fake request
and context
objects and calls the run
function to verify that the response is indeed Hello Jan Aagaard
as expected.
// greet/index.test.ts
import { run as greet } from "./index";
describe("greet function", () => {
test("returns correct greeting", async () => {
const request = {
query: {
name: "Jan Aagaard"
}
};
const context = {
log: () => undefined,
req: request
};
await greet(context, request);
const response = (context as any).res;
expect(response.body).toBe("Hello Jan Aagaard");
});
});
Running the Tests in Visual Studio Code
The code base includes a script command to run the tests, so that they can be executed by typing yarn test
. Instead of relying on an external command to run the tests, I recommend installing the excellent Jest extension for Visual Studio Code. I will run the tests continuously in the background, and show the results in VSCode’s status bar.
The default setting is to show a ‘Debug’ link above the tests that are failing, but I like being able to step into my code at any time. Adding the following line to .vscode/settings.json
makes the ‘Debug’ link show permanently.
// In .vscode/settings.json
"jest.debugCodeLens.showWhenTestStateIn": ["fail", "pass", "skip", "unknown"],
Running the Tests When Pushing Commits
Instead of relying on that the developers remember to run the tests locally, we will set up a continuous integration pipeline that executes the tests and blocks the pull request, should any of them fail. CircleCI is one of the options for automating builds when having code hosted on GitHub, and it seems like it’s currently gaining a lot of traction. Create your CircleCI account by signing in via GitHub, and then create a config.yml
file that configures pipeline. These are the steps in the pipeline:
- Check out the code from GitHub.
- Install the Node.js packages.
- Build the code.
- Lint the code.
- Run the tests.
It isn’t necessary to build the code before running the tests because ts-jest
takes care of that when running them. But it’s nice to include the build step anyways to catch any compile errors, and likewise we also include a lint step.
# .circleci/config.yml
version: 2.1
jobs:
build:
docker:
# Match the version in azure-resource.json. See https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#node-version.
- image: circleci/node:10.14.1-stretch
steps:
- checkout
- run:
name: Install Node modules
command: yarn install --frozen-lockfile
- run:
name: Build
command: yarn run build
- run:
name: Lint
command: yarn run lint
- run:
name: Run tests
command: yarn run test
The final config.yml
has a few more steps, adding a cache of the node_modules
folder to speed up the build time and presenting the test results in CircleCI.
- Check out the code from GitHub.
- Restore cached
node_modules
. - Install the Node.js packages.
- Cache
node_modules
. - Build the code.
- Lint the code.
- Run the tests.
- Store test results in CircleCI.
CircleCI requires that test results are stored as JUnit XML files, and Jest uses json by default. The command for saving the test results ended up being quite long.
// In package.json
"test-save-results": "cross-env JEST_JUNIT_OUTPUT=test-results/test-results.xml jest --ci --runInBand --reporters=default --reporters=jest-junit"