How to Test Your Express APIs with Supertest
Tags: express, javascript, node, testing
Published: 2019-08-24 13:19:16

_Read the original article [here](https://rahmanfadhil.com/test-express-with-supertest)_

## Introduction

Express is the most popular Node.js framework for building web applications, especially REST APIs. And in this article, I'm going to show you how you can test your API endpoints with a cool library called SuperTest.

[SuperTest](https://github.com/visionmedia/supertest) is an HTTP assertions library that allows you to test your Node.js HTTP servers. It is built on top of [SuperAgent](https://github.com/visionmedia/superagent) library, wich is an HTTP client for Node.js.

## Getting Started

Let's start by creating a simple Express server with a single endpoint that returns a simple json.

```js
// index.js

const express = require("express")
const app = express()

app.get("/", (req, res) => {
  res.send({ name: "John Doe" })
})

app.listen(8000, () => {
  console.log("Server has started!")
})
```

To test it manually, you can simply run `node index.js` and send a request to `http://localhost:8000` with Postman or cURL.

```terminal
$ curl http://localhost:8000
{"name":"John Doe"}
```

To make our code testable, we need to separate our `listen` method to another file, so that we can require our express instance without starting the server.

```js
// index.js

const server = require("./server.js")

server.listen(8000, () => {
  console.log("Server has started!")
})
```

```js
// server.js

const express = require("express")

const app = express()

app.get("/", (req, res) => {
  res.send({ name: "John Doe" })
})

module.exports = app
```

We have our server up and running, now it's time to write some test.

## SuperTest Basic Usage

Before we get started with SuperTest, we need to install a testing framework. It's a handy tool to write automated tests, so that you'll know what part of your application went wrong.

In this tutorial, we will going to use [Jest](https://jestjs.io). Which is by far the easiest testing framework for JavaScript I've ever used.

```terminal
$ npm install --save-dev jest
```

Then, we need to setup our test command by adding a test script inside our `package.json`.

```json
{
  // ...
  "scripts": {
    "test": "jest"
  }
  // ...
}
```

After Jest installed and configured, we now can write our first test by creating new test file.

```js
// server.test.js

const app = require("./server")

test("GET /", done => {
  supertest(app)
    .get("/")
    .expect(200, JSON.stringify({ name: "John Doe" }))
    .end(done)
})
```

Here we require our `server.js` file to get our Express.js server instance. Then, create a new test called "GET /", run a `GET` request to `/` endpoint and expect the result to be the defined object. We also want to make sure that the response has `200` HTTP status, which means that our request is OK.

If you notice, when we're asserting our response, we are stringifying our JSON object. That's because by default, supertest will compare our response as a string.

We can now run our tests by running `npm test` or `npm run test`.

<!-- Test result -->

## Using Callbacks

There are other approach to assert your server response. Instead of passing the expected result as an argument, we can pass a callback to get and assert our response.

```js
supertest(app)
  .get("/")
  .expect(response => {
    expect(response.status).toBe(200)
    expect(response.body).toEqual({ name: "John Doe" })
    done()
  })
```

By using the callback approach, we're asserting your response body and status code directly inside our response callback. We also need to run Jest `done` function to finish our test when our assertion is completed.

We also get our response body as a JavaScript `Object`, so we can compare it directly with `toEqual` method provided by Jest matchers.

## Send Form Data

Form input is the most essential feature of dynamic web applications nowadays. And testing a endpoint with form data is a piece of cake in SuperTest.

To handle form data, we need to install another third-party library called [Body Parser](https://github.com/expressjs/body-parser). Body Parser is an Express middleware that we can use to handle form data inside our Express app.

If you don't know what middlware is, essentially, it's just a function that can intercept users request. In this can we use it to get our form data.

We can install Body Parser by running the command below.

```terminal
$ npm install body-parser
```

Then, we can use Body Parser middleware inside our `server.js` file.

```js
// server.js

const express = require("express")
const bodyParser = require("body-parser")

const app = express()
app.use(bodyParser.urlencoded({ extended: false }))

// ...
```

We can now access users form data inside our route handler by accessing `req.body` variable.

```js
// server.js

// ...

app.post("/form-data", (req, res) => {
  const formData = {
    name: req.body.name,
    age: req.body.age,
  }

  res.send(formData)
})

// ...
```

To test it out, we can send our form data by calling the `field` method for every field in our form inside our supertest request.

```js
supertest(app)
  .get("/form-data")
  .field("name", "John Doe")
  .field("age", "25")
  .expect(response => {
    expect(response.status).toBe(200)
    expect(response.body).toEqual({ name: "John Doe", age: "24" })
    done()
  })
```

## JSON Request Body

By default, supertest will send your form data with `Content-Type` of `application/x-www-form-urlencoded`. If the client wants to send a more complex data types, you way want to use JSON format, which is `application/json`. To do that we can use another method from supertest called `send`.

`send` method lets you send a request with body that has a `Content-Type` of `application/json`. So that you can send a more complex data like numbers, arrays, nested objects, etc.

```js
const formData = {
  name: "John Doe",
  age: 25,
  fruits: ["Apple", "Orange"],
}

supertest(app)
  .get("/form-data")
  .send(formData)
  .expect(response => {
    expect(response.status).toBe(200)
    expect(response.body).toEqual(formData)
    done()
  })
```

Then, you need to add another express middleware from `body-parser` package, which lets you decode request body with the `Content-Type` of `application/json`.

```js
// server.js

const express = require("express")
const bodyParser = require("body-parser")

const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

// ...
```

## File Upload

We also can upload files to our server with SuperTest!

To do this, we need to setup our server first, so that we can handle file upload from the client. The easiest way to handle file upload in Express is by using another third-party library called [Multer](https://github.com/expressjs/multer). So, lets install it first!

```terminal
$ npm install multer
```

Then, we can initialize a new Multer object and specify our upload directory.

```js
// server.js

const express = require("express")
const multer = require("multer")

const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

const upload = multer({ dest: "uploads/" })

// ...
```

Finally, we can handle the file upload by adding the Multer middleware from our Multer instance. This let us upload the file inside `avatar` field in our client side form.

```js
// server.js

// ...

app.post("/upload", upload.single("avatar"), (req, res) => {
  // req.file is the `avatar` file
  // req.body will hold the text fields, if there were any
})

// ...
```

We can test it out by using the `attach` method where we can specify the field name and the file path we want to upload.

```js
supertest(app)
  .get("/")
  .field("name", "John Doe")
  .attach("avatar", "/path/to/file.png")
  .expect(response => {
    expect(response.status).toBe(200)
    done()
  })
```

By default, our form data will be sent with `Content-Type` of `multipart/form-data`.