1

The code I am trying to test is:

exports.hasTokenOrApi = (req, res, next) ->
  if not req.headers?.authorization
    return res.status(403).end()

  new Promise (resolve, reject) ->
    if req.headers.authorization.length is 32
      # We are using an API key
      global.db.User.find
        where:
          api_key: req.headers.authorization
      .then (dbUser) ->
        resolve dbUser.apiDisplay()
    else
      # We are using a redis session
      req.redisSession.getAsync
        app: 'sessions'
        token: req.headers.authorization
      .then (response) ->
        resolve response.d
  .then (user) ->
    if not user.id
      return res.status(403).end()
    req.user = user

    next()
  .catch (err) ->
    next err

This is a middleware (I'm using Express) to catch tokens or API keys for various API endpoints.

So far the tests I have are:

describe 'Authentication Middleware', ->
  mock_res = {}
  before (done) ->
    mock_res =
      status: ->
        @
      end: ->
        @

    global.db =
      User:
        find: ->
          @
        then: ->
          id: 1


    done()

  it 'should return a 403 is no authorization is set in the header', ->
    mock_req = {}
    mock_next = null

    status_spy = sinon.spy mock_res, 'status'
    end_spy = sinon.spy mock_res, 'end'

    authentication.hasTokenOrApi mock_req, mock_res, mock_next
    status_spy.calledWith(403).should.equal true
    end_spy.called.should.equal true

  it.only 'should detect a valid API key', ->
    mock_req =
      headers:
        authorization: 'e16b2ab8d12314bf4efbd6203906ea6c'
    mock_next = sinon.spy()

    authentication.hasTokenOrApi mock_req, mock_res, mock_next
    mock_next.called.should.equal true

The first test is fine, works great, solves all of my problems. The second one isn't working properly. I assume it has something to do with the Promises? My test us returning false, when what I'm trying to do is true

Any help would be GREATLY appreciated!

Shamoon
  • 41,293
  • 91
  • 306
  • 570

2 Answers2

2

I'd just do:

it.only 'should detect a valid API key', (done) ->
    mock_req =
      headers:
        authorization: 'e16b2ab8d12314bf4efbd6203906ea6c'

    authentication.hasTokenOrApi mock_req, mock_res, done

If done is not called at all, the test will timeout. If it is called with an error, then Mocha will report the error.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • But shouldn't there be a spy on the res? – Shamoon Mar 31 '15 at 01:36
  • Probably but the 2nd test in your question shows no spy for the `res`. At any rate, instead of calling done right away, the callback passed to `hasTokenOrApi` can perform tests on the `res` mock and call `done` after that. – Louis Mar 31 '15 at 10:28
1

the callback next will be called asynchronously. Your test is checking mock_next.called before it ever has a chance to be called. You can verify that the next callback is called by writing your own callback in:

authentication.hasTokenOrApi mock_req, mock_res, err ->
    if err
        done err
    # if the code has entered this callback, and there's no error 
    # that means that the promise has resolved and everything's good... 
    # we can end the test now
    done()
lyjackal
  • 3,984
  • 1
  • 12
  • 25