mercredi 29 mai 2019

How do I stub a function that is not directly passed to the calling function?

I have an express app with API endpoints secured using JWT token. I have a method that verifies a received token.

// authentication.js

import jwt from 'jsonwebtoken';
import Settings from '../settings';

const AuthenticationMiddleware = {
    verifyToken: (req, res, next) => {
        const token = req.headers['x-access-token'];
        if (!token) {
            const msg = 'Include a valid token in the x-access-token header';
            return res.status(422).json({ 
                error: 'No token provided',
                msg 
            });
        }
        try {
            req.user = jwt.verify(token, Settings.jwtSecret);
            req.token = token;
            return next();
        }
        catch (e) {
            return res.status(422).json({ error: 'Invalid token' });
        }
    }
};

export default AuthenticationMiddleware;

This works fine when I call the API endpoints from postman with the token header included.

Now I have a test such as shown below. There's about 40 of them, each requiring a token to be sent with each API request.

// should is not used directly in the file but is added as a mocha requirement

import supertest from 'supertest';
import app from '../app';

const server = supertest.agent(app);
const BASE_URL = '/api/v1';

describe('/loans: Get all loans', () => {
    it('should return a list of all loans', done => {
        server
            .get(`${BASE_URL}/loans`)
            .expect(200)
            .end((err, res) => {
                res.status.should.equal(200);
                res.body.data.should.be.an.instanceOf(Array);
                for (const each of res.body.data) {
                    each.should.have.property('id');
                    each.should.have.property('userid');
                }
                done();
            });
    });
});

I've looked at sinon and tried stubbing the verifyToken function in mocha's before hook like so

import sinon from 'sinon';
import AuthenticationMiddleware from '../middleware/authentication';

before(() => {
    const stub = sinon.stub(AuthenticationMiddleware, 'verifyToken');
    stub.returnsThis()
});

But I can already see a problem here. While the verifyToken stub may have been created, it is NOT used during the test. The verifyToken that is being called during the test is passed as middleware from the route like so

router.get('/loans', AuthenticationMiddleware.verifyToken, LoansController.get_all_loans);

I want a way to stub verifyToken during the test so that I can just return next() immediately.

My question is, is it possible to stub AuthenticationMiddleware.verifyToken universally during the test so that all calls to the API endpoint call the stubbed version?

Aucun commentaire:

Enregistrer un commentaire