Mehfuz's Blog

Mocha + SuperTest = Fun!

Building application with node is fun. Node community came up with application framework like express providing robust set of features for creating multi-page and hybrid web applications. As you layer your application and if you are test comes first type of developer then it is obvious that you will write tests to maintain simple design and increase confidence of your application (as mentioned by Kent Black in 2003).

Mocha is a feature rich javascript test framework for node. It runs seamlessly with node async model with BDD style syntax. If you have node and npm configured then to install it type this command:

npm install -g mocha

Note: Mocha is preferred to be installed globally.

While I was building lighter (the very blog engine), I wanted to test a specific module is behaving correctly. As for example I wanted to verify if the blog module is returning the expected post for a given permalink. Therefore, I opened my text editor and wrote this:

describe 'Blog module', ->    
  describe 'find post by permalink', ->
    expected = 'test post'
    _id = ''
    before (done)->     
          blog.create
              posts    : [{
                title        : expected
                author         : ''        
                body        : ''}]
                ,(result) =>
                    _id = result._id
                    done()

     it 'should return the post for given permaLink', (done)->    
            blog.findPost helper.linkify(expected), (data) ->
                 data.post.title.should.equal expected
                 done()

      after (done)->        
            blog.deletePost _id, ()->
              done()  

This is quite self explanatory and speaks the intent. Here I am basically creating a blog post with a given title then verifying that the module is returning the expected post for a permalink created from that title. Finally done function is used to signal the end of the test.

Next switching to terminal, I typed the following command:

mocha

This runs tests in files located under test folder and prints output in the terminal window.

Now lighter uses AtomPub for managing post. I further wanted to automate the process a post is created and thus wanted to verify the following behaviors:

  • Response contains 401 for an unauthorized request.
  • Response contains 201 for a valid request after the post is created.
  • Once the post is created, it is sending back the required data (title, id, content) properly.

This is where supertest came really handy as I wrote the following test:

describe 'atom feed', ()->
    request = request(app)
    describe 'POST /api/atom/feeds', ()->
        id = ''

        it 'should return 401 for unauthorized request', (done)->
                post = request.post('/api/atom/feeds')
                post.expect(401).end (err, res)->
                    if err != null
                        throw err
                    done()

        it 'should return 201 and expected result', (done)=>
            credentials = new Buffer('admin:admin').toString('base64')
            post = request.post('/api/atom/feeds')
            post.set('Content-Type', 'application/atom+xml')
            post.set('authorization', util.format('Basic %s', credentials))
            fs.readFile __dirname + '/post.xml','utf8', (err, result)=>   
                    post.write(result)
                    post.expect(201).end (err, res)->
                        if err != null
                             throw err
                        parser = new xml2js.Parser();
                        parser.parseString res.text, (err, result)->
                            result.entry.title[0].should.be.ok
                            result.entry.content[0].should.be.ok 
                            result.entry.id[0].should.be.ok   
                            lastIndex = result.entry.id[0].lastIndexOf('/') + 1
                            id = result.entry.id[0].substr(lastIndex)
                        done()

        afterEach (done)->
            blog.deletePost id, ()->
                done() 

Here request is a supertest object where it is created in the following way:

express = require('express')
request = require 'supertest'

app = express()   
...
request = request(app)    

As you can see that it takes express instance as its parameter which let me run the test with exact configuration as in production environment.

Eventually supertest let me expect status code, write raw body, or set specific header using expect(), write(), set() etc and perform assertions in the end() callback. This works seamlessly with mocha therefore it eventually let me write automated unit test over HTTP request.

In this post I wrote a simple test with mocha and extended it further using supertest which makes HTTP assertions super easy and fun providing high level abstraction layer.

coffee-script
mocha
nodejs
superTest
Discussions