Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing requests that redirect with mocha/supertest in node

I can't seem to get the following integration test to pass in an express project using mocha, supertest, and should (and coffeescript).


The test

should  = require('should')
request = require('supertest')
app     = require('../../app')

describe 'authentication', ->
  describe 'POST /sessions', ->
    describe 'success', (done) ->
      it 'displays a flash', (done) ->
        request(app)
          .post('/sessions')
          .type('form')
          .field('user', 'username')
          .field('password', 'password')
          .end (err, res) ->
            res.text.should.include('logged in')
            done()

Relevant application code

app.post '/sessions', (req, res) ->
  req.flash 'info', "You are now logged in as #{req.body.user}"
  res.redirect '/login'

Failure

1) authentication POST /sessions success displays a flash:
   AssertionError: expected 'Moved Temporarily. Redirecting to //127.0.0.1:3456/login' to include 'logged in'

Obviously, the application code doesn't do anything useful. I'm just trying to get the test to pass.

Putting the expectation (res.text.should.include('logged in')) outside the end function and inside the expect function yields the same results. I've also tried a variation of the function calls, for example removing the .type('form') call, and using .send(user: 'username', password: 'password') instead of the two .field() calls.

If it means anything, sending a curl POST request to the the app when it's running locally yields the same output (Moved Temporarily. Redirecting to //127.0.0.1:3456/login)

I have a feeling this is a trivial error. Possibly something I'm forgetting in the application code or the test code.

Any suggestions?

EDIT 1: It's also worth noting that when clicking the submit button in the browser I get the expected results (a flash message).

EDIT 2: Further investigation shows the output of any redirect results in the Moved Temporarily. Redirecting to ... response body. This makes me wonder if there is a problem in the way I'm exporting the app in app.js.

var express = require('express')
var app = express();

module.exports = app;
like image 927
Feech Avatar asked Sep 04 '12 22:09

Feech


People also ask

What is SuperTest in Mocha?

SuperTest is a Node. js library that helps developers test APIs. It extends another library called superagent, a JavaScript HTTP client for Node. js and the browser. Developers can use SuperTest as a standalone library or with JavaScript testing frameworks like Mocha or Jest.

What does SuperTest request do?

SuperTest is an HTTP assertions library that allows you to test your Node. js HTTP servers. It is built on top of SuperAgent library, wich is an HTTP client for Node. js.


4 Answers

There is built-in assertion for this in supertest:

should  = require('should')
request = require('supertest')
app     = require('../../app')

describe 'authentication', ->
  describe 'POST /sessions', ->
    describe 'success', ->
      it 'redirects to the right path', (done) ->
        request(app)
          .post('/sessions')
          .send(user: 'username', password: 'password')
          .expect(302)
          .expect('Location', '/home')
          .end(done)
like image 99
VuesomeDev Avatar answered Sep 24 '22 09:09

VuesomeDev


For anyone who comes across this page, the answer to this question is pretty simple. The Moved Temporarily. response body is what is returned from supertest. See the issue for more details.

To summarize, I ended up doing something like this.

should  = require('should')
request = require('supertest')
app     = require('../../app')

describe 'authentication', ->
  describe 'POST /sessions', ->
    describe 'success', ->
      it 'redirects to the right path', (done) ->
        request(app)
          .post('/sessions')
          .send(user: 'username', password: 'password')
          .end (err, res) ->
            res.header['location'].should.include('/home')
            done()

Just check that the response header location is what you expect it to be. Testing for flash messages and view specific integration tests should be done using another method.

like image 35
Feech Avatar answered Sep 26 '22 09:09

Feech


describe 'authentication', ->
  describe 'POST /sessions', ->
    describe 'success', (done) ->
      it 'displays a flash', (done) ->
        request(app)
          .post('/sessions')
          .type('form')
          .field('user', 'username')
          .field('password', 'password')
          .redirects(1)
          .end (err, res) ->
            res.text.should.include('logged in')
            done()

The redirects() will follow the redirect so you can do your usual view tests.

like image 22
super_noobling Avatar answered Sep 24 '22 09:09

super_noobling


I was trying to write some integration tests for requests that redirected as well, and found a good example by the author of the module himself here.

In TJ's example, he's using chaining, so I used something like that as well.

Consider a scenario in which a logged-in user is redirected to the home page when he or she logs out.

it('should log the user out', function (done) {
  request(app)
    .get('/logout')
    .end(function (err, res) {
      if (err) return done(err);
      // Logging out should have redirected you...
      request(app)
        .get('/')
        .end(function (err, res) {
          if (err) return done(err);
          res.text.should.not.include('Testing Tester');
          res.text.should.include('login');
          done();
        });
    });
});

Depending on how many redirects you have, you might have to nest a few callbacks, but TJ's example should suffice.

like image 21
User 1058612 Avatar answered Sep 23 '22 09:09

User 1058612