Unit testing Express auth middleware in isolation
isolating and unit-testing middleware.
build fake req/res, use a spy/mock for next and res methods, assert next called on valid token and 401 sent on invalid.
WHAT THIS TESTS Whether the candidate knows that middleware is a plain function and can be tested in isolation with mocked Express objects, distinguishing fast unit tests from heavier integration tests.
A GOOD ANSWER COVERS Express middleware has the signature (req, res, next), so you can call it directly with fabricated objects rather than booting an HTTP server. Build a fake req containing only what the middleware reads, for example headers.authorization. Build a fake res where status and json (and send) are mock functions; make status return res so chaining like res.status(401).json(...) works. Provide next as a mock function. Then exercise each branch: with a valid token (stub jwt.verify to return a payload, or sign a real test token), assert that next was called once with no arguments and that req.user was populated; with a missing or malformed token, assert that res.status was called with 401 and that next was not called. Stub the JWT library so the test does not depend on real signing keys or time. Tools like jest mocks or sinon spies, or helpers such as node-mocks-http, make building these doubles easy.
COMMON WRONG ANSWERS Only writing integration tests through a real server when the question asks for isolated unit testing. Forgetting to assert whether next was or was not called, which is the core behavior. Not making res chainable, so the test throws. Verifying the real JWT signature instead of stubbing it, making tests brittle.
LIKELY FOLLOW-UPS How do you test the error branch where next(err) is called? When prefer supertest integration tests instead? How do you avoid coupling to the JWT library internals?
ONE CONCRETE EXAMPLE const req = { headers: { authorization: 'Bearer good' } }; const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; const next = jest.fn(); after stubbing jwt.verify to return { id: 1 }, call auth(req, res, next) and assert next was called and req.user.id is 1. In a second test with no header, assert res.status was called with 401 and next was never called.
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.