5

I created a NodeJs http server in TypeScript and I've unit tested everything with Jest, except the base class, the server itself:

import { createServer} from 'http';
export class Server {

    public startServer() {
        createServer(async (req, res) => {
            if(req.url == 'case1') { 
               // do case1 stuff
            }
            if(req.url == 'case2') { 
               // do case2 stuff
            }
            res.end();
        }).listen(8080);
    }
}

I'm trying this approach:

import { Server } from '../../../src/app/Server/Server';
import * as http from 'http';
describe('Server test suite', () => {

    function fakeCreateServer() {
        return {}
    }

    test('start server', () => {
        const serverSpy = jest.spyOn(http, 'createServer').mockImplementation(fakeCreateServer);
        const server = new Server().startServer();
        expect(serverSpy).toBeCalled();
    });
});

Is there a way a can create a valid fake implementation for the 'createServer' method? And maybe simulate some requests? Thanks a lot!

Barosanu240
  • 725
  • 8
  • 15

2 Answers2

5

What logic do you want to test here?

Such a simple server is declarative enough to keep it without unit tests.

If you want to test that createServer is invoked just mock http module by jest.mock('http');

Such expressions are lifted up by jest to give them precedence over regular imports. https://jestjs.io/docs/en/mock-functions#mocking-modules

import { Server } from '../../../src/app/Server/Server';
import * as http from 'http';

jest.mock('http', () => ({
  createServer: jest.fn(() => ({ listen: jest.fn() })),
}));

describe('Server', () => {

    it('should create server on port 8080', () => {
        const server = new Server().startServer();
        expect(http.createServer).toBeCalled();
    });
});
  • 1
    Hi! Thanks a lot for the response. I edited the code to be more clear. In the implementation I do different stuff based on the req object I receive, and that is basically what I want to test. Is there a way to sent a mock req object in that test? – Barosanu240 Jul 23 '20 at 07:34
  • 1
    If I understand correctly, if you need test each handler separately. Just move handler functions outside of http stiff (createServer and so on). And test those handlers as pure functions. After that apply some declarative approach to map handlers on urls. I do not think that it makes much sense to test declarative code. – Alexander Alexandrov Aug 01 '20 at 21:09
2

Maybe you should approach your class and tests a little bit differently.

Nodejs http.createServer returns a server instance. The server instance has a property listening (true if the server is listening for the requests), so you could return the server instance from the startServer method and test server.listening property.

Also, if you want to test for different responses and requests to your server, I would suggest you use supertest

// server.js - it also works with plain HTTP
const app = express();

app.get('/user', function(req, res) {
  res.status(200).json({ name: 'john' });
});

module.export = app

// test.js
const request = require('supertest');
const app = require('./server.js')

describe('GET /user', function() {
  it('responds with json', function(done) {
    request(app)
      .get('/user')
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200, done);
  });
});
Ivan V.
  • 7,593
  • 2
  • 36
  • 53