Read the original article here
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 is an HTTP assertions library that allows you to test your Node.js HTTP servers. It is built on top of 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.
// 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.
$ 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.
// index.js
const server = require("./server.js")
server.listen(8000, () => {
console.log("Server has started!")
})
// 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. Which is by far the easiest testing framework for JavaScript I've ever used.
$ npm install --save-dev jest
Then, we need to setup our test command by adding a test script inside our package.json
.
{
// ...
"scripts": {
"test": "jest"
}
// ...
}
After Jest installed and configured, we now can write our first test by creating new test file.
// 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
.
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.
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. 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.
$ npm install body-parser
Then, we can use Body Parser middleware inside our server.js
file.
// 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.
// 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.
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.
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
.
// 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. So, lets install it first!
$ npm install multer
Then, we can initialize a new Multer object and specify our upload directory.
// 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.
// 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.
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
.
Top comments (0)