# How to create a Node.js app with Docker, Part 4: Testing

In the previous posts, we created a Node.js web application and we learned how to manage its deployment, development and debugging with Docker. Although in the early stages of development it seems that manual testing is enough to check that our app works properly, the growth of its codebase and complexity will make this solution very inefficient and we will need automatic, fast and widespread tests to check the behavior of app's components.

It's easy to create a testing environment and it doesn't need particular configurations as regards the Docker container. Meanwhile, on the app side, we can use the stack that we want. In this guide, we'll use Mocha as test framework and Chai as assertion library.

## Prerequisites

* The `Dockerfile`, `index.js` and `package.json` files from the previous post.
    

## Installing Mocha and Chai

Before building a new image, we have to update the `package.json` file and add `mocha`, `chai` and `chai-http` (a Chai plugin for testing HTTP endpoints) to the dependencies. We can do it in several ways:

* Adding the dependencies to the file manually.
    
* Starting a container, update the file inside the container and propagate changes to the outside by using a volume (we saw how to do in the second article of this series).
    
* Starting a container, update the file inside the container and copy it to the outside in our working directory.
    

Since the first option doesn't need further clarification and the second one has already been examined, let's take the opportunity to see a new approach.

If you haven't already created an image from the Dockerfile, do it now

```bash
$ docker build --tag my-app .
```

Run a container from the image and edit the entrypoint to launch a shell in it (we already discussed on this practice in the post about the debugging).

```bash
$ docker run -it --entrypoint /bin/sh my-app
```

Install the needed dependencies with NPM

```bash
$ npm install -D mocha chai chai-http
```

When the installation it's over, exit from the shell (you can do with `CTRL + D` or `exit` command) and copy or overwrite the `package.json` file from inside the container to the outside, in our working directory.

```bash
$ docker cp <CONTAINER_ID>:app/package.json ./package.json
```

## Writing the tests

We'll create a test to verify that the application shows the 'Hello world' message on the homepage.

But first, we have to make a change in the `index.js`

```javascript
var express = require('express')
var app = express()
var port = process.env.PORT || 3000

app.get('/', function (req, res) {
  res.send('Hello World!')
})

if (process.env.NODE_ENV === 'test') {
  module.exports = app
} else {
  app.listen(port)
}
```

We added an *if* block to check, by using the `NODE_ENV` environment variable, if the code is executed in a testing context and if so, the `app` object will be exported (we'll see why shortly) otherwise the application will be started normally.

Let's move on to the test. Since Mocha runs all tests inside the `test` folder by default, create in your working directory the following `test/homepage.js` file

```javascript
// Import the dependencies
var chai = require('chai')
var chaiHttp = require('chai-http')
// Import the application to test
var app = require('../index')
// Configure Chai
chai.use(chaiHttp)
chai.should()

describe('Homepage', () => {
  it('should show the Hello World message', done => {
    chai
      .request(app)
      .get('/')
      .end((error, response) => {
        response.text.should.equal('Hello World!')
        done()
      })
  })
})
```

Let's see more in detail how this test is structured:

* We use `chai.use()` to add the `chai-http` plugin to Chai.
    
* We use `chai.should()` to choose *should* as assertion style. Other styles are *assert* and *expect*.
    
* We use `it()` to create a test, `describe()` to group them in suites.
    
* With `request()` we set an Express application of which we want test the endpoints with Chai.
    
* In Mocha, we use `done()` at the end of a test to manage the assertions rightly in asynchronous functions like `end()`.
    

## Running the tests

Let's add a `test` script to the `package.json` file to launch Mocha (note that here we pass the `NODE_ENV` environment variable used in `index.js`)

```json
{
  "name": "nodejs-app",
  "dependencies": {
    "express": "^4.17.0"
  },
  "scripts": {
    "start": "node index.js",
    "dev": "npx nodemon index.js",
    "debug": "node --inspect=0.0.0.0:9229 index.js",
    "test": "NODE_ENV=test npx mocha"
  },
  "devDependencies": {
    "chai": "^4.2.0",
    "chai-http": "^4.3.0",
    "mocha": "^6.1.4",
    "nodemon": "^1.19.1"
  }
}
```

Build a new image of our app and run a container

```bash
$ docker build --tag my-app .
$ docker run -d -p 4000:3000 my-app
```

At this point we can execute the tests in two ways:

* we can run them like a process outside the container (this choice is made, for example, when we need to run them in a CI/CD pipeline)
    

```bash
$ docker exec <CONTAINER_ID> npm test
```

* we can run them like a process inside the container by opening a shell in it
    

```bash
$ docker exec -it <CONTAINER_ID> /bin/sh
# npm test
```

## Conclusions

Now we learned how to manage easily every phase of Node.js application development by using Docker. In the next post, we'll talk about services integration and we'll see how to include a database in our application by using a new tool, **Docker Compose**.
