Skip to content

Start and stop server with supertest

I have the following server class :

import express, { Request, Response } from 'express';

export default class Server {
  server: any;

  exp: any;

  constructor() {
    this.exp = express();
    this.exp.get('/', (_req: Request, res: Response) => {
      res.json('works');
    });
  }

  start(): void {
    this.server = this.exp.listen(3000);
  }

  stop(): void {
    this.server.close();
  }
}

I’m using supertest for end-to-end testing. I wish to start my application beforeAll tests and stop it when the tests are done.

It’s easy to do that using beforAll and afterAll where I can just once instanciate the Server class and call the start and close methods.

But as I have 10+ controllers to test, I want to avoid to start and stop the server during each test file.

I found on the documentation the setupFiles and setupFilesAfterEnv but I can’t stop the server since the instance is not “shared” in the two files.

This is an example of 1 test file :

import supertest from 'supertest';

describe('Album Test', () => {
   let app: App;

   beforeAll(async (done) => {
     app = new App();

     await app.setUp(); // database connection (not mentionned in the preivous example)
     done();
   });

   afterAll(async (done) => {
     await app.close();

     app.server.stop();
     done();
   });

  const api = supertest('http://localhost:3000');

  it('Hello API Request', async () => {
    const result = await api.get('/v1/user');
    expect(result.status).toEqual(200);
    ...
  });
});

This works totally fine but I’m duplicating this beforeAll and afterAll methods in every test file. Is there a way to declare it only once ?

Thanks

Answer

You could use setupFiles to set up test fixtures globally. You can assign variables that you want to use in multiple test files to Node.js global object.

E.g.

app.ts:

import express, { Request, Response } from 'express';

export default class Server {
  server: any;

  exp: any;

  constructor() {
    this.exp = express();
    this.exp.get('/', (_req: Request, res: Response) => {
      res.json('works');
    });
  }

  start(): void {
    this.server = this.exp.listen(3000);
  }

  stop(): void {
    this.server.close();
  }
}

app.setup.js:

const App = require('./app').default;

beforeAll(() => {
  global.app = new App();
  global.app.exp.set('test setup', 1);
  console.log('app setup');
});

afterAll(() => {
  console.log('app stop');
});

jest.config.js:

module.exports = {
  preset: 'ts-jest/presets/js-with-ts',
  testEnvironment: 'node',
  setupFilesAfterEnv: [
    './jest.setup.js',
    '/Users/ldu020/workspace/github.com/mrdulin/react-apollo-graphql-starter-kit/stackoverflow/61659975/app.setup.js',
  ],
  testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
  verbose: true,
};

a.controller.test.js:

describe('controller a', () => {
  it('should pass', () => {
    console.log('test setup:', global.app.exp.get('test setup'));
    expect(1 + 1).toBe(2);
  });
});

b.controller.test.js:

describe('controller b', () => {
  it('should pass', () => {
    console.log('test setup:', global.app.exp.get('test setup'));
    expect(1 + 1).toBe(2);
  });
});

unit test results:

 PASS  stackoverflow/61659975/a.controller.test.js
  controller a
    ✓ should pass (5ms)

  console.log
    app setup

      at Object.<anonymous> (stackoverflow/61659975/app.setup.js:6:11)

  console.log
    app setup

      at Object.<anonymous> (stackoverflow/61659975/app.setup.js:6:11)

  console.log
    test setup: 1

      at Object.<anonymous> (stackoverflow/61659975/b.controller.test.js:3:13)

  console.log
    test setup: 1

      at Object.<anonymous> (stackoverflow/61659975/a.controller.test.js:3:13)

  console.log
    app stop

      at Object.<anonymous> (stackoverflow/61659975/app.setup.js:10:11)

  console.log
    app stop

      at Object.<anonymous> (stackoverflow/61659975/app.setup.js:10:11)

 PASS  stackoverflow/61659975/b.controller.test.js
  controller b
    ✓ should pass (3ms)

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        6.749s, estimated 12s