Search code examples
node.jsunit-testingmocha.jschaisupertest

NodeJs: next is not function


I try to write the unit tests using Mocha, Chai and Supertest, but now, unfortunately, unsuccessfully.
I have next route:

var express = require('express');
var GoogleUrl = require('google-url');
var _ = require('lodash');
var token = require('../middlewares/token');
var Url = require('../models/url');
var config = require('../config');
var router = express();

router.post('/urls/create', token.required, createShortUrl);

module.exports = router;

function createShortUrl(req, res) {

    _.trim(req.body.list_tags);
    var tags = _.split(req.body.list_tags, ',');
    tags.splice(tags.length - 1, 1);

    var date = returnDate();
    var time = returnTime();

    var googleUrl = new GoogleUrl({
        'key': config.get('google_key')
    });

    googleUrl.shorten(req.body.full_url, function (err, shortUrl) {

        if (err) {
            res.status(500).json(err);
        }

        var url = new Url({
            'author': req.payload.username,
            'description': req.body.description,
            'full_url': req.body.full_url,
            'short_url': shortUrl,
            'list_tags': tags,
            'date': date,
            'time': time
        });

        url.save(function (err) {

            if (err) {
                res.status(500).json(err);
            } else {
                res.status(200).json('Shortener url is created!');
            }

        });

    });

}

   function returnDate() {
    var d = new Date();
    var yyyy = d.getFullYear();
    var mm = d.getMonth() < 9 ? '0' + (d.getMonth() + 1) : (d.getMonth() + 1);
    var dd = d.getDate() < 10 ? '0' + d.getDate() : d.getDate();
    return dd + '-' + mm + '-' + yyyy;
}

function returnTime() {
    var d = new Date();
    var hh = d.getHours() < 10 ? '0' + d.getHours() : d.getHours();
    var min = d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes();
    var ss = d.getSeconds() < 10 ? '0' + d.getSeconds() : d.getSeconds();
    return hh + ':' + min + ':' + ss;
}

I save the data in the MongoDB using Mongoose. For route I wrote the unit test:

var app = require('../server');
var chai = require('chai');
var request = require('supertest');
var jwt = require('express-jwt');
var config = require('../config');

var expect = chai.expect;

describe('Urls Tests', function () {

  var url = {
    author : 'Alexey',
    description : 'grrggr',
    full_url : 'https://github.com',
    short_url : 'short_url_by_google',
    date : '30-06-2017',
    time : '18:21:27',
    count_click : 0,
    list_tags : [
      'Sport',
      'Football'
    ]
  };

  var token = {
    required: jwt({
      secret: config.get('jwtSecret'),
      userProperty: 'payload',
      getToken: 'token',
    })
  };

describe('## Create url ', function() {
    it('should create a url', token.required, function(done) {
      request(app)
        .post('/urls/create')
        .send(url)
        .end(function(err, res) {
        expect(res.statusCode).to.equal(200);
        expect(res.body.author).to.equal('Alexey');
        url = res.body;
        done();
      });
    });
  });

});

When I run the unit test I get an error:

TypeError: next is not a function
      at Context.middleware (node_modules\express-jwt\lib\index.js:76:16)

I cannot understand why I get it. Help me, please ! I think that I created little the error which since can find.

UPDATED

middlewares/token.js:

var jwt = require('express-jwt');
var config = require('../config');

function getTokenFromHeader(req){
    if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Token') {
        return req.headers.authorization.split(' ')[1];
    }

    return null;
}

var token = {
    required: jwt({
        secret: config.get('jwtSecret'),
        userProperty: 'payload',
        getToken: getTokenFromHeader
    })
};

module.exports = token;

Solution

  • The error is on your it('should create a url', token.required, function(done) line. Because the token is supposed to be a middleware, it requires the parameters req, res, and next.

    In your test, you are not supplying the server with a token so you can remove the token.required from your test.

    If you do make a test for the token authentication, however, you can get around this problem by calling token.required manually inside your test with your own next function. You would also need to supply the server with a jwt in your request.