Testing Express with Jasmine

I recently worked on a side project using node. In the past, I’ve used vows extensively as a testing framework. There are many great things about vows including speed of execution and seemless support for testing asynchronous functions. However, looking back on that project I feel I spent more time debugging vows issues than actually testing/writing my code. I’ve previously used jasmine for in-browser testing and I enjoyed it. I decided to give jasmine-node a try this time around.

The project used express, a micro-framework for building web apps in node. Express is a great library but it wasn’t immediately obvious the best way to test an application using jasmine. I put together a few simple helpers that made the process of testing an express app with jasmine painless.

The Approach

My general approach was straight forward: spin up the express app, use the request library to hit the running server, make assertions and the stop the express app. First, let’s look at the project layout.

The Layout
The project layout is below, not much more to say here.

example_app  
|-- lib
|   `-- app.coffee
`-- spec
    |-- app-spec.coffee
    `-- spec-helper.coffee

2 directories, 3 files  

The App

Our example app is very simple. It includes two routes, one get and one post. The important piece here is the fact that we export the app for testing and we only start the server if the file is run directly, not when it is required.

express = require 'express'

exports.app = app = express.createServer()

app.get "/", (req, res) ->  
  res.send "Hello, world!"

app.post "/", (req, res) ->  
  res.send "You posted!"

if __filename == process.argv[1]  
  app.listen 6789

The Spec Helper

Now, let’s take a look at the spec helper for our application. It exposes a function called withServer that we’ll use to test our express application. The withServer function creates the server, starts listening, and then calls the provided callback with a nice wrapper around request and a callback that must be called at the end of your spec. withServer also calls asyncSpecWait and the provided callback calls asyncSpecDone.

request = require "request"

class Requester  
  get: (path, callback) ->
    request "http://localhost:3000#{path}", callback

  post: (path, body, callback) ->
    request.post {url: "http://localhost:3000#{path}", body: body}, callback

exports.withServer = (callback) ->  
  asyncSpecWait()

  {app} = require "../lib/app.coffee"

  stopServer = ->
    app.close()
    asyncSpecDone()

  app.listen 3000

  callback new Requester, stopServer

The Spec

Finally, we’ll take a look at how the withServer function is actually used in a spec.

helper = require './spec-helper'

describe "App", ->  
  describe "get /", ->
    it "responds successfully", ->
      helper.withServer (r, done) ->
        r.get "/", (err, res, body) ->
          expect(res.statusCode).toEqual 200
          done()

    it "has the correct body", ->
      helper.withServer (r, done) ->
        r.get "/", (err, res, body) ->
          expect(body).toEqual "Hello, world!"
          done()

  describe "post /", ->
    it "has the correct body", ->
      helper.withServer (r, done) ->
        r.post "/", "post body", (err, res, body) ->
          expect(body).toEqual "You posted!"
          done()

Next time you start a project based on express, consider using this technique to aid testing.