Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocha + supertest + assert: print response body on test failure

I'm using mocha, supertest, and assert to test my Express app. My Express app is run in development mode so it returns useful debug info as JSON whenever a request fails. I'd like to print this data in my test suite but only when a test fails. An example of one of my tests (in CoffeeScript):

  assert  = require "assert"
  request = require "supertest"
  url     = request "http://localhost:3000"

  describe "GET /user/:id", ->
    it "should return one user", (done) ->
      url
        .get("/user" + id)
        .expect(200)
        .expect("Content-Type", /json/)
        .end (err, res) ->
          if err
            done err
          else
            # assuming the test reaches here, but fails on one of the following,
            # how do i make mocha print res.body?
            assert.equal(res.body.name, user.name)
            assert.equal(res.body.email, user.email)
            done()

How do I make mocha print res.body, but only when a test fails? I'd prefer to not have to put something like console.log(res.body) if test.failed in each describe block, if possible.

like image 907
Charles Avatar asked Aug 17 '14 08:08

Charles


2 Answers

I do it similarly:

var supertest = require("supertest");
var should    = require("should");
var util      = require('util');

describe("My test",function(){

  var response;

  it("should validate the API key",function(done){
    server
    .post("/validate")
    .set('authorization', apiKey)
    .expect("Content-type",/json/)
    .expect(200) 
    .end(function(err,res){
      response = res;
      res.status.should.equal(200);
      res.body.error.should.equal(false);
      done();
    });
  });

  afterEach(function(){
    if (this.currentTest.state == 'failed') { 
      console.log("    Response body: " + util.inspect(response.body,{depth: null, colors: true}) + "\n");
    }
  })  

});

I dedicated a response variable in my test scope, and each test sets it to the given response (response = res;). I have to do it once in each test, but then I don't have to worry when and where it fails. Before, I had to be careful, because if the test failed, some code below it wouldn't be executed, so it wouldn't even reach the print statement. This way, I save what I need, no matter what the outcome is.

Then after each test, this afterEach event will kick off and check if the test passed or failed.

  afterEach(function(){
    if (this.currentTest.state == 'failed') { 
      console.log("    Response body: " + util.inspect(response.body,{depth: null, colors: true}) + "\n");
    }
  })  

This provides a consistent way to print for each test. It's just 1 line for all the tests, so it's easy to change the format or disable, and I don't need to care where the test failed, I just care about the final result. This seems to me like the best and easiest approach, out of all the lazy approaches. Even the output JSON is nicely and colorfully displayed. There is probably a more proper way to handle it, but this is a nice, lazy approach.

like image 95
Anton Krug Avatar answered Nov 02 '22 11:11

Anton Krug


Multiple ways to achieve this :

Option 1 : I would simply use a if condition to check the failed condition in the else block and do a console.log(res.body)

Option 2: or in the call back function, if there is an error then you can return res.body.

Eg:

Use something like below in the end

.end(function(err, res){
        if (err) throw err;
        if (!res.body.password) assert.fail(res.body.password, "valid password", "Invalid password") 
        else done()
    }); 

You can use res.body instead of res.body.password as well

Try this it should work.

like image 43
swathy valluri Avatar answered Nov 02 '22 11:11

swathy valluri