Mock-Testing a Node Server with Supertest

In the previous section, we tested each of our Backbone entities against a mock server, using Sinon to fake responses to each collection’s HTTP requests. Now it’s time to create the mirror image of those tests, testing that our server provides the correct response to a set of fake requests.

Before we start writing tests, though, we should refactor our server to make it test-friendly. As we wrote it originally, it would define an Express instance (called app) and then immediately start listening on a port. For testing, we don’t want to actually open a TCP port. It’s much easier to simulate our requests. So let’s separate the code that defines app from the code that tells app to start listening:

 # Read environment configuration
 env = process.env.NODE_ENV or ​'development'
 
 # In development mode, enable source map support
 if​ env is ​'development'
  require(​'source-map-support'​).install()
 
 # Create an Express server instance
 express = require ​'express'
 app = express()
 
 app.use(express.static(​"​​#{​__dirname​}​​/public"​))
 
 Datastore = require(​'nedb'​)
 db = {}
 [​'boards'​, ​'columns'​, ​'cards'​].forEach (collectionKey) =>
  db[collectionKey] = ​new​ Datastore
  filename: ​"​​#{​__dirname​}​​/​​#{​collectionKey​}​​.db"
  autoload: true
 
  db[collectionKey].ensureIndex {fieldName: ​'id'​, unique: true}
 return
 
 # Set the initial board state if none already exists
 db.boards.insert({
  id: 1
  name: ​'New Board'
 })
 
 bodyParser = require(​'body-parser'​)
 app.use(bodyParser.json())
 
 [​'boards'​, ​'columns'​, ​'cards'​].forEach (collectionKey) =>
 
 # Endpoint to fetch the entire collection
  app.get ​"/​​#{​collectionKey​}​​"​, (req, res) =>
  db[collectionKey].find {}, (err, collection) =>
 throw​ err ​if​ err
  res.send(collection)
 return
 
 # Endpoint to add a new object to the collection (assigns id)
  app.post ​"/​​#{​collectionKey​}​​"​, (req, res) =>
  object = req.body
  db[collectionKey].count {}, (err, count) =>
 throw​ err ​if​ err
  object.id = count + 1
  db[collectionKey].insert object, (err) =>
 throw​ err ​if​ err
  res.send(object)
 return
 
 # Endpoint to update an existing object in the collection
  app.put ​"/​​#{​collectionKey​}​​/:id"​, (req, res) =>
  query = {id: +req.params.id}
  object = req.body
  options = {}
  db[collectionKey].update query, object, options, (err) =>
 throw​ err ​if​ err
  res.send(object)
 return
 
 # Export the server instance
 module.exports = app

Because this module just defines and exports app, it’s now dual-purpose. We can require it and run assertions against it, or we can require it and call the listen method to start the server.

Now to write some Node tests. In the browser, we used Sinon to simulate Ajax requests. Here, we’ll use Supertest[59] to simulate requests to our Node server. Let’s start by installing Supertest as a dev dependency:

 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​supertest

Now let’s create a new folder for our new tests:

 $ ​​mkdir​​ ​​tests/src/node_unit

And a Gruntfile section, just like the one for our UI tests but with runType: ’client’ (meaning “Node client”) instead of runType: ’runner’:

 node_unit:
  options:
  runType: ​'client'
  config: ​'tests/compiled/node_unit/intern'
  reporters: [​'console'​]

For Node tests, we don’t need anything like Selenium, so our Intern config will be much simpler:

 define
  excludeInstrumentation: ​/^(?:tests|node_modules)//
  suites: [
 'tests/compiled/node_unit/cardEndpoint'
  ]

(Notice that we’ve excluded node_modules from instrumentation here, since we aren’t worried about how well our tests cover our third-party libraries.)

Our dependencies will be simpler as well. All we need is our basic testing libraries and the module that defines our Express instance:

 define [
 'intern!object'
 'intern/chai!assert'
 'intern/dojo/node!supertest'
 'intern/dojo/node!../../../lib/app'
 ], (registerSuite, assert, supertest, server) ->

Now for the test itself. At a minimum, we should make sure that the /cards endpoint yields a 200 response, while a request to a nonexistent endpoint yields a 404:

 registerSuite
  name: ​'card endpoint'
 
 'request for cards yields a 200 response'​: ->
  supertest(server).get(​'/cards'​)
  .expect(200)
  .end (err, res) =>
 throw​ err ​if​ err
 
 'request for bad URL yields a 404 response'​: ->
  supertest(server).get(​'/adsfsfd'​)
  .expect(404)
  .end (err, res) =>
 throw​ err ​if​ err

We should, of course, write analogous tests for every endpoint our server provides, but this is a good starting point. Now to build our Node server and run our final batch of tests:

 $ ​​grunt​​ ​​build
 $ ​​grunt​​ ​​intern:node_unit
 >>​​ ​​PASS:​​ ​​main​​ ​​-​​ ​​card​​ ​​endpoint​​ ​​-​​ ​​request​​ ​​for​​ ​​cards​​ ​​yields​​ ​​a​​ ​​200​​ ​​response​​ ​​(8ms)
 >>​​ ​​PASS:​​ ​​main​​ ​​-​​ ​​card​​ ​​endpoint​​ ​​-​​ ​​request​​ ​​for​​ ​​bad​​ ​​URL​​ ​​yields​​ ​​a​​ ​​404​​ ​​response​​ ​​(1ms)
 >>​​ ​​0/2​​ ​​tests​​ ​​failed
 >>​​ ​​0/2​​ ​​tests​​ ​​failed
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.71.115