How to stub express middleware using sinon in typescript?

强颜欢笑 提交于 2020-07-10 10:27:35

问题


I'm trying to write an integration test for my express router using typescript, mocha, sinon and chai-http. This router uses a custom middleware that I wrote which checks for JWT in the header.

Ideally, I want to stub my authMiddleware so that I can control its behaviour without actually providing valid/invalid JWT for every test case.

When I try to stub authMiddleware in my tests, I realised that express app uses the actual implementation of authMiddleware rather than mocked one.

I've tried to import app after mocking authMiddleware using dynamic imports of typescript but it didn't work also.

authMiddleware.ts

import { Request, Response, NextFunction } from 'express';

export default class AuthMiddleware {
    
    verifyToken(req: Request, res: Response, next: NextFunction) :void {
        console.log('Actual implemetation of verifyToken is called!');
        
        // verify token
        
        next();
    }
}

subjectRouter.ts

import express from'express';
import AuthMiddleware from '../middleware/authMiddleware';
import * as subjectController from '../controller/subjectController';

const router = express.Router();
const authMiddleware = new AuthMiddleware();

router.post('/', authMiddleware.verifyToken, subjectController.createSubject);

export default router;

app.ts

import express from 'express';
import subjectRoute from './route/subjectRoute';

// Initilize express app
const app = express();

app.set("port", 3000);

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// Routers
app.use('/user', userRoute);
app.use('/subject', subjectRoute);

export default app;

subjectTests.ts

import app from '../../src/app';
import AuthMiddleware from '../../../src/middleware/AuthMiddleware';

describe('Subject', () => {

    let app;
    
    beforeEach(async () => {
        sinon.stub(AuthMiddleware.prototype, 'verifyToken').callsFake((req: Request, res: Response, next: NextFunction): void => {
            console.log('Fake verifyToken is called!');
             
            // THIS IS NEVER CALLED IN TESTS...

        });
        app = (await import('../../../src/app')).default;
    });

    it('should throw 403 when jwt is missing in header', (done) => {
        request(app)
            .post(/subject)
            .end((err, res) => {
                expect(res).has.status(403);
                done();
            });
    });
});

When I run the above test I see that mock authMiddleware is not called. app in tests uses the real implementation of authMiddleware object.

Is there a way to stub express middleware and pass it to app explicitly?


回答1:


I've just explained what is happening in this response, however giving only workaround.

After few thoughts, i believe the best way to overcome this is to remove global state from your modules and capture whole initialization code into explicitly called functions (or classes, if you like), so you can create your server for each tests. Namely, change your architecture to:

// router.ts
export function createRouter() {
    /// ...
    router.post('/', authMiddleware.verifyToken, subjectController.createSubject);
    return router;
}

// app.ts
import { createRouter} from "./router.js"
export function createApp() {
   ///same code as currently, but in function
   app.use('/subject', createRouter());
}

Now, you can create new "app" in each setup callback:

// test.ts
beforeEach(async () => {
    sinon.stub(AuthMiddleware.prototype, 'verifyToken').callsFake((req: Request, res: Response, next: NextFunction): void => {
        ...
    });
    app = (await import('../../../src/app')).createApp(); // note that we create new app for each test, so you're not polutting global state of app
});

This approach has many advantages, among others:

  • you can mock different functions for different tests;
  • you're effectively removing "implicit singletons" from code whose existence was root cause of your issue.


来源:https://stackoverflow.com/questions/62604398/how-to-stub-express-middleware-using-sinon-in-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!