Setup and write Jest Unit Tests for Azure Functions in TypeScript

Image for post
Image for post
Photo by Kevin Ku on Unsplash

Testing is important to ensure the quality of your software. One part of that is to write unit tests. For that many tools exist in the JavaScript World, e.g. Jest, Jasmine or Mocha. Just to name a few.

Coming from frontend focused development with React, I love Jest for writing and executing my unit tests. Knowledge gained in that domain would be great to be applied in the Azure serverless functions world. Well, when you write your serverless functions in Node.js that’s possible.

We first need to create an Azure Function App to have functions we can test in the first place. This can be done via the Azure Functions CLI.

Once installed you can initialise your function app:

func init --worker-runtime node --language typescript --source-control

Obviously, we also need to have a function we can unit test. We create an HTTP trigger function.

func new --name DemoFunction --template "HTTP trigger"

To use Jest as our unit testing framework, we need to install it first as a dev dependency. And as we write our code in Typescript, we also need to install types for it.

npm install --save-dev jest @types/jest

The type itself is not enough to let Jest execute our tests written in TypeScript also need to install Babel to compile our typescript code to Node compatible JavaScript code. For that, we install additional dec dependencies.

npm install --save-dev babel-jest @babel/core @babel/preset-env @babel/preset-typescript

In addition, we also need to create a babel.config.js in our project root to configure Babel.

// babel.config.js
module.exports = {
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-typescript",
],
};

Let’s have a look at our Azure Function we just created previously.

import { AzureFunction, Context, HttpRequest } from "@azure/functions"

const httpTrigger: AzureFunction = async function (context: Context, req: HttpR$
context.log('HTTP trigger function processed a request.');
const name = (req.query.name || (req.body && req.body.name));
const responseMessage = name
? "Hello, " + name + ". This HTTP triggered function executed successfu$
: "This HTTP triggered function executed successfully. Pass a name in t$

context.res = {
// status: 200, /* Defaults to 200 */
body: responseMessage
};

};

export default httpTrigger;

In our unit tests, we will test the pure function which will not be executed in an Azure Function environment, therefore we need to uncomment the status 200, which would be otherwise not returned.

context.res = {
status: 200, /* Defaults to 200 */
body: responseMessage
};

We all adjustments made, we can now start unit testing our function.

In the same directory as our index.ts lives, we create an index.test.ts file.

In our test file, we first import our Azure function and the Context type from Azure Function as we will need it later.

import httpTrigger from "./index";
import { Context } from "@azure/functions";

Our HTTP trigger function takes two arguments, a Context object and a request object. The Context object contains all information that the Azure Function Runtime environment provides to the function if executed within Azure. The request object includes the usual information from a HTTP request, e.g. the query or body.

The context is important for us, as all the results from a function are attached to that context. Therefore, we need to mock it via jest. We won’t mock the whole context object, but only the attributes that are called in our function. In our case that is the log function.

As the context is necessary for every of our unit tests, it is good practices to declare it centralised and mock it before each unit test execution. We can declare it in a describe-block and reset it in a beforeEach block.

describe("Test for Demo Function", () => {
let context: Context;

beforeEach(() => {
context = ({ log: jest.fn() } as unknown) as Context;
});

// Here our test will be written

});

Now let’s write our first unit test in an it-block.

// beforeEach Block

[...]

it("should return a 200", async () => {
// Arrange
const request = {
query: {},
body: { name: "John" },
};

// Action
await httpTrigger(context, request);

// Assertion
expect(context.log).toBeCalledTimes(1);
expect(context.res.status).toEqual(200);
});

[...]

We first arrange our request object with a name property in the body which we provide together with the context object as parameters to our HTTP trigger function execution. Our function looks into the request’s query and body. Therefore, we need to provide both attributes in this object.

Our test asserts that the log function is called once and the context response has a status of 200.

Currently, we only test the response code and the call of the context log, but to further quality secure our function, we also want to test the actual response of our function.

If a name attribute is provided either in queries or in the body, it will be embedded in the string “Hello, NAME. This HTTP triggered function executed successfully.” That is something we can test. In a second test, we arrange also a result string and assert that our body in the context object will be equal to our result string.

[...]it("should return a result string with the name given in the request body", async () => {
// Arrange
const request = {
query: {},
body: { name: "John" },
};
const resultString =
"Hello, John. This HTTP triggered function executed successfully.";

// Action
await httpTrigger(context, request);

// Assertion
expect(context.log).toBeCalledTimes(1);
expect(context.res.body).toEqual(resultString);
});
[...]

That’s it. That is a quick overview on how to configure Jest for an Azure Function app written in TypeScript and write units tests to test the functions.

I hope you enjoyed it and will try out testing your Azure Functions with Jest. When the article helped you would appreciate a little applause.

Stay safe and keep on coding!

The whole code can be also here: https://github.com/tobim-dev/azure-function-jest-typescript

Written by

I’m a self-taught web developer who loves React, the Jamstack and serverless architectures. Lives and works in Munich. Opinions are my own.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store