I'd like to be able to stub my middleware functions on a per-test basis. The problem, as articulated here, is that I can't just stub my middleware functions since node has cached the middleware function so I can't stub it since I create my app at the very beginning.
const request = require("supertest");
const { expect } = require("chai");
const sinon = require('sinon');
const auth = require ("../utils/auth-middleware")
const adminStub = sinon.stub(auth, "isAdmin").callsFake((req, res, next) => next());
const app = require("../app.js"); // As soon as I create this, the middleware isAdmin function becomes cached and no longer mutable
The above works as the solution described in the linked SO answer, but I don't like that in order to restore the stub or modify the fake, I have to completely recreate the server.
I'm wondering if there's a better, elegant way to work around the fact that Node caches these functions upon first require
. I was looking into maybe using proxyquire
or decache
but both seem to provide workarounds rather than sustainable solutions (although I may very well be wrong here).
The problem is not really related to Node caching modules - it's express who stores a reference to a middleware function when a server is initially created.
After isAdmin
method of require
d module is stubbed, it's the cached version who gets stubbed, so using a tool like proxyquire
would only allow you to require a fresh version of the module (without stubbed method) if you need it for some reason.
If what you're looking for is adjusting behavior of a particular middleware for already created express server, you'd need a way to alter middleware function's behavior by its reference. Hopefully, sinon stubs (and others too, e.g. ones jest provides) are capable of that. However, you still need to stub the module before creating an express server so it stores a reference to the stubbed function.
Sample implementation might look as follows:
const request = require("supertest");
const { expect } = require("chai");
const sinon = require('sinon');
const auth = require ("../utils/auth-middleware");
// store reference to original function in case you need it:
const originalIsAdmin = auth.isAdmin
// replace isAdmin method with a stubbed, but don't specify implementation yet
const adminStub = sinon.stub(auth, "isAdmin");
// init express server that relies on stubbed `auth.isAdmin` reference
const app = require("../app.js");
it('this test is using auth.isAdmin that just calls .next()', () => {
// make middleware just pass
auth.isAdmin.callsFake((req, res, next) => next());
// ...
});
it('this test is using real auth.isAdmin implementation', () => {
// make middleware call real implementation
auth.isAdmin.callsFake(originalIsAdmin);
// ...
});