4

I would like to write unit tests using Mocha for my Nodejs/Express app that I have written in visual studio. I have scoured everywhere I could looking for a simple tutorial but not found what I am looking for. I have seen many tutorials in creating a test using assert to test that 5=5, etc. but that's not what I want to do.

I am trying to add a JavaScript Mocha Unit Test file through VS and then all I really want it to do is open the home page of my app, check for some content in the body and pass the test. If I want to run the tests from the Test Explorer window the nodejs app can't be running and if it isn't running there would be nothing to receive the request for the homepage.

So I'm not sure if the test itself is somehow supposed to launch the app or what? I feel like I'm in a catch 22 and missing the very basics, just don't see it described anywhere.

nicholaswmin
  • 21,686
  • 15
  • 91
  • 167
Chris H
  • 501
  • 1
  • 4
  • 15
  • Possible duplicate of [How do i test my express app with mocha?](https://stackoverflow.com/questions/8831984/how-do-i-test-my-express-app-with-mocha) – devius Feb 25 '18 at 21:00

1 Answers1

4

What you're looking for is most commonly called an API test - a part of integration testing, not a unit test. If a test touches network, a database or I/O it's, most commonly, an integration test instead.

Now to your question. In order to test your app.js code without starting up the server manually beforehand you can do the following:

  • module.export your app server.
  • In your tests, use chai-http to test routes.
  • require your app in the tests and use that instead of URL's when testing routes.

The key here is the 1st bullet point. You must export your app so you can require it and use it in your tests. This allows you to skip the part where you start a separate server process to run the tests on.

Server code

// app.js

const express = require('express')
const app = express()
const bodyParser = require('body-parser')

app.use(bodyParser.json())

// Routes

app.post('/register', (req, res) => {
  const requiredFields = ['name', 'email']

  if (requiredFields.every(field => Object.keys(req.body).includes(field))) {
    // Run business logic and insert user in DB ...
    res.sendStatus(204)
  } else {
    res.sendStatus(400)
  }
})

app.listen(3000)

// export your app so you can include it in your tests.
module.exports = app

Test code

// test/registration.spec.js
const chai = require('chai')
const chaiHttp = require('chai-http')
// `require` your exported `app`.
const app = require('../app.js')

chai.should()
chai.use(chaiHttp)

describe('User registration', () => {
  it('responds with HTTP 204 if form fields are valid', () => {
    return chai.request(app)
      .post('/register')
      .send({
        name: 'John Doe',
        email: 'john@doe.com'
      })
      .then(res => {
        res.should.have.status(204)
      })
      .catch(err => {
        throw err
      })
  })

  it('responds with HTTP 400 if some fields are missing', () => {
    return chai.request(app)
      .post('/register')
      .send({
        name: 'John Doe'
      })
      .catch(err => {
        err.should.have.status(400)
      })
  })
})

Then just run your test from the root directory with:

$ mocha test/registration.spec.js
nicholaswmin
  • 21,686
  • 15
  • 91
  • 167
  • I'll take a look at that info regarding E2E testing thanks. Having never setup unit tests before I think I'm probably struggling a little with exactly what should be tested. Lets say I have a controller method that is called when a form is posted on the web site. I want to call that controller method in a unit test but the problem is that all paths through that code result in a response.redirect or response.render which I'm guessing will fail. Is that controller method still too big a piece to run a unit test on? – Chris H Feb 25 '18 at 23:21
  • Not sure about controllers but: If your test touches network, a database or any type of disk I/O, it's not a unit test, but rather an integration test. A unit is most commonly a module or a class. Making a system work is rather easy, making it easily testable (which has additional benefits such as decoupled parts etc) is another story. – nicholaswmin Feb 25 '18 at 23:40
  • I'll update my answer by the way because you can get away with an API test here. – nicholaswmin Feb 25 '18 at 23:46