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.
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 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
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
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
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.