0

I'm trying to write some tests where I need to authenticate first. If I make multiple requests in "before()" I get connection refused. If I split it between "before()" and "it()" it works but I cannot acheive what I want.

Code I want to work:

var agent = request.agent(myExpressApp),
      token;
    before(function(done) {
      async.series([
        function(cb) {
          agent
            .post('/1/auth/login')
            .send({
              email: 'john@smith.com',
              password: 'j0hn_Sm1TH'
            })
            .expect(200)
            .end(cb);
        }, function(cb) {
          agent
            .get('/1/auth/authorize')
            .query({
              response_type: 'token',
              client_id: 'some id',
              redirect_uri: 'http://ignore'
            })
            .expect(302)
            .end(function(err, res) {
              /* console.log(arguments) = { '0': 
                { [Error: connect ECONNREFUSED]
                  code: 'ECONNREFUSED',
                  errno: 'ECONNREFUSED',
                  syscall: 'connect' } }*/
              if (err) return cb(err);
              cb();
            });
        }
      ], done);
    });
    it('some authenticated task', function(done) {
      // do something else
      done();
    });

Code that is working:

var agent = request.agent(myExpressApp),
      token;
    before(function(done) {
      async.series([
        function(cb) {
          agent
            .post('/1/auth/login')
            .send({
              email: 'john@smith.com',
              password: 'j0hn_Sm1TH'
            })
            .expect(200)
            .end(cb);
        }, function(cb) {
          cb();
        }
      ], done);
    });
    it('some authenticated task', function(done) {
      agent
        .get('/1/auth/authorize')
        .query({
          response_type: 'token',
          client_id: 'some id',
          redirect_uri: 'http://ignore'
        })
        .expect(302)
        .end(function(err, res) {
          if (err) return done(err);
          done();
        });
    });
Simon
  • 5,158
  • 8
  • 43
  • 65
  • Bizarrely if I add `function(cb) { process.nextTick(cb); }` to the async.series it works as desired. This seems a bit hacky. Is there a proper way to do this? – Simon Jun 01 '14 at 12:42

1 Answers1

0

You have encountered issue 153 with superagent. Annoyingly and magically, superagent looks at the arity of the callback function you pass to it. If the function is declared accepting 2 arguments, superagent conforms to the node convention of (error, result), however, if the callback function looks like it expects any other number of arguments (zero in the case of use with async.js), it invokes the function as just callback(res) which I guess TJ thought would be nice for the browser, but for node it totally breaks convention.

The exact line of code in question is here

Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • I understood this to change `cb` to `function (err, res) { cb(err) }` but it still doesn't work as desired. Am I missing something? Thanks. – Simon Jun 01 '14 at 22:54
  • Please post a complete updated example. It's too hard to follow an isolated snippet. The problem is `.end(cb)` when `.end` is a superagent request and `cb` is an async.js callback. That needs an extra wrapper: `.end(function(err, res) {cb(err, res)})`. – Peter Lyons Jun 01 '14 at 23:15
  • It looks like your issue is more related to https://github.com/tj/supertest/issues/126 which https://github.com/tj/supertest/pull/137 may have broken for agent. – Gardner Bickford Feb 08 '15 at 03:11