0

Forgive me if this is something you shouldn't do, but I've looked around to see what is possible.

I want to verify that my express app has a middleware called/used for the app.

import express from 'express';
import cors from 'cors';

const app = express();

app.use(cors()); // <----- I WANT TO TEST THIS

app.get('/', (_req, res) => res.send({ hello: 'world' });

app.listen(5000, () => console.log(`Listening on port 5000`));

export default app;

Potential jest test

import app from './index.ts';

// This is a poor attempt to try and get this to work
test('test if CORS is implemented', () => {
   const mockCors = jest.mock('cors');

   const myApp = app;

   expect(mockCors).toHaveBeenCalledTimes(1);
});

If anyone has the solution and if I should not be doing this, what is the reason behind it?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
codingwithmanny
  • 1,126
  • 8
  • 20

1 Answers1

4

My guess is that you don't actually care that cors is called. Your client won't say to you "I want the cors middleware to be called". All the client should care about is the service that is provided, not how it's implemented. Your tests should do the same. If you decide one day to use another module for CORS, your tests shouldn't need to change, why would they?

My (personal) preferred approach is exactly that. Testing that given some input, my programs gives me the output I desire. Everything inside the program can be changed, as long as the behavior does not change. That will give you peace of mind when refactoring.

Also, for testing an Express app, you don't need a server, you just need the app. Actually starting the server can add complexity to your tests, since they might be hanging if you forget to close the server after them.

So in this example, the very first thing I would do is move everything you have in index.ts into a file called app.ts, and remove this line:

app.listen(5000, () => console.log(`Listening on port 5000`));

And in index.ts, only have this:

import app from './app.ts';
// Start the server
app.listen(5000, () => console.log(`Listening on port 5000`));

Then, I would use Supertest along with Jest, to make requests to that app:

npm i -D supertest

And then, in your test file, test what matters to the client:

import request from 'supertest';
import app from './app.js'; // Just import the app, not the server

describe("myApp", () => {
  it('should implement CORS', async() => {
    const { headers } = await request(app).get('/');
    expect(headers['access-control-allow-origin']).toEqual('*');
  });
});
blex
  • 24,941
  • 5
  • 39
  • 72
  • I like the folder structure, but I do want to check if `cors` is called. My thinking behind it, and not that it's solely cors, but to see if a developer disabled or commented out a middleware by accident when they should have implemented it. Is that valid or is that not a good idea for a particular reason? – codingwithmanny Jul 03 '20 at 11:57
  • I think it depends on the middleware. For CORS, since the feature provided is right here in the request response, I think testing that response is a better approach. But if you have another middleware that, for example, logs requests to an external database, then yes, mocking it makes more sense – blex Jul 03 '20 at 12:07
  • Would you have an example for that implementation? Would be super grateful if you did. Additionally, do you find that there is redundancy in using something like `Postman` and `supertest`? – codingwithmanny Jul 03 '20 at 12:08
  • 1
    I don't have a solution off the top of my head right now, although [this](https://stackoverflow.com/a/58113577/1913729) might be a track to explore. The tricky part here is that `cors()` is called as soon as you import your module. So you may need to mock it before you do `import...`. As for Supertest & Postman, yes, that would be redundent (2 testing codebases to maintain would not be very pleasant ) – blex Jul 03 '20 at 12:54