Testing JavaScript middleware in Node.js is a crucial step to make sure that your middleware functions do what they're supposed to: handle incoming requests, process data, and pass control to the next middleware or route handler. Let's walk through how to test middleware using popular testing tools like Mocha, Chai, Sinon.
Before jumping into testing, we need to set up our development environment. First, ensure you have Node.js and npm installed. Then, initialize a new Node.js project and install the necessary dependencies.
mkdir middleware-testing
cd middleware-testing
npm init -y
npm install express mocha chai sinon supertest --save-dev
- `express`: A web framework for Node.js.
- `mocha`: A test framework for Node.js.
- `chai`: An assertion library for Node.js.
- `sinon`: Provides test spies, stubs, and mocks.
- `supertest`: For HTTP assertions in Node.js.
Let's create a simple middleware function to test. This middleware will log request details and validate a custom header.
Create a file named middleware.js
:
// middleware.js
function requestLogger(req, res, next) {
console.log(`${req.method} ${req.url}`);
next();
}
function validateHeader(req, res, next) {
const headerValue = req.headers['custom-header'];
if (!headerValue) {
return res.status(400).json({ error: 'Custom-Header is required' });
}
next();
}
module.exports = { requestLogger, validateHeader };
Now, create a test file named middleware.test.js
. We'll use Mocha, Chai, and Sinon for this.
// middleware.test.js
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const { requestLogger, validateHeader } = require('./middleware');
const express = require('express');
const request = require('supertest');
chai.use(sinonChai);
const expect = chai.expect;
describe('Middleware Tests', () => {
let app;
beforeEach(() => {
app = express();
});
describe('requestLogger', () => {
it('should log the request method and URL', (done) => {
const logSpy = sinon.spy(console, 'log');
app.use(requestLogger);
app.use((req, res) => res.send('OK'));
request(app)
.get('/test')
.end((err, res) => {
expect(logSpy).to.have.been.calledWith('GET /test');
logSpy.restore();
done();
});
});
});
describe('validateHeader', () => {
it('should return 400 if custom-header is missing', (done) => {
app.use(validateHeader);
app.use((req, res) => res.send('OK'));
request(app)
.get('/test')
.expect(400, {
error: 'Custom-Header is required',
}, done);
});
it('should pass to the next middleware if custom-header is present', (done) => {
app.use(validateHeader);
app.use((req, res) => res.send('OK'));
request(app)
.get('/test')
.set('custom-header', 'valid-header')
.expect(200, 'OK', done);
});
});
});
- **Setting Up the Test Environment**: We use Mocha's `describe` and `it` to structure our tests. `beforeEach` ensures a new Express app is created for each test.
- **requestLogger Tests**:
- We use Sinon to spy on `console.log` and verify it logs the correct details.
- Adding `requestLogger` middleware to the app, then making a request using Supertest.
- We check if `console.log` was called with the expected log message.
- **validateHeader Tests**:
- We test the case when the custom header is missing, expecting a 400 status code and an error message.
- We also test when the custom header is present, expecting the middleware to call the next middleware and return a 200 status code with an 'OK' response.
To run the tests, you need to add a test script to your package.json
:
"scripts": {
"test": "mocha"
}
Then, run the tests with:
npm test
You'll see output indicating all tests have passed.
By following this guide, you can make sure that your middleware functions behave correctly in various situations. This will help you keep your codebase robust and reliable.