'NestJS Share e2e server between test suites

I'm using NestJS test module to mock the nest app and I want to share this app among various test suites.
Here's my setup:

test
  |_ helpers
    |_ testApp.ts
  |_ e2e
    |_ users.e2e-test.ts
  |_ beforeAll.e2e-test.ts

testApp.ts

import { Test } from '@nestjs/testing';
import { DatabaseModule } from '../../src/database/database.module';
import { UserModule } from '../../src/user/user.module';

let app: any;
export async function initServer() {
  const fixture = await Test.createTestingModule({
    imports: [
      DatabaseModule,
      UserModule,
    ],
  }).compile();
  app = fixture.createNestApplication();

  await app.init();
}
export default app;

beforeAll.e2e-test.ts

import { initServer } from './helpers/testApp';

before(async () => {
  await initServer();
});

users.e2e-test.ts

import * as request from 'supertest';
import * as chai from 'chai';
const expect = chai.expect;

import { UserType } from '../../src/user/enum/user-types.enm';
import app from '../helpers/testApp';

const admin = {
  email: '[email protected]',
  password: '123',
  type: UserType.ADMIN
};
describe.only('Creating User with customized permissions', async () => {
  it('User should be able to sign in', async () => {
    request(app.getHttpServer())
      .post('/auth/signin')
      .send({ email: admin.email, password: '123' })
      .end((_, res) => {
        expect(res.status).to.equal(200);
      });
  });
});

So basically I want to share the NestApplication instance among various test suites but I'm getting the app as undefined in the test case and it's giving the following error:
TypeError: Cannot read property 'getHttpServer' of undefined

Is there any way to do this? Or should I initialize a new NestApplication in each test suite?

I'm using mocha as a test runner.



Solution 1:[1]

I had the same issue. It's my solution

my jest-e2e.json

{
  "moduleFileExtensions": ["js", "json", "ts"],
  "rootDir": ".",
  "testEnvironment": "node",
  "testRegex": ".e2e-spec.ts$",
  "transform": {
    "^.+\\.(t|j)s$": "ts-jest"
  },
  "setupFilesAfterEnv": ["<rootDir>/setup.ts"]
}

my setup.ts

export let app: NestExpressApplication;

async function initServer() {
  const moduleRef = await Test.createTestingModule({
    imports: [
      AppModule,
      AuthModule,
      UsersModule
    ],

  }).compile();

  app = moduleRef.createNestApplication<NestExpressApplication>();
  app.useGlobalInterceptors(new TransformationInterceptor);
  app.useGlobalInterceptors(new TransformError);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      transform: true,
      forbidNonWhitelisted: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  );

  const configService = app.get(ConfigService);
  //added for custom validator
  useContainer(app.select(AppModule), { fallbackOnErrors: true });
  await app.init();
  await app.listen(3002);
  
}

global.beforeAll(async () => { 
  await initServer();  
});

my test (auth.e2e-spec.ts)

import {app} from '../setup';

Solution 2:[2]

Try this.

beforeAll(async () => {
  const module = await Test.createTestingModule({
    providers: [
      MyTestsService,
      {
        provide: getRepositoryToken(Warehouse),
        useValue: myTestsService
      }
    ],
    controllers: [MyTestsController], // <-- this will fix problem of getHttpServer
  })
    .overrideProvider(MyTestsService)
    .useValue(myTestsService)
    .compile();

  app = module.createNestApplication();
  await app.init();
});

Solution 3:[3]

So having this folder structure for my test I'm going to show you how I exported my app between different test suits and I hope this might help you because I've been fighting against the same problem for nearly half an hour.

    __test__
  |_ category.e2e-test.ts
  |_ test-conf.ts
**test-conf.ts**
   export default async function initTestServer() {
   let app: INestApplication;

  const moduleRef = await Test.createTestingModule({
    imports: [AppModule],
  }).compile();

  return moduleRef.createNestApplication();
}
**category.e2e-test.ts**
describe('CategoryController', () => {
    let app: INestApplication;

    beforeAll(async () => {
        app = await initTestServer();
        await app.init();
    });

    it('/ (GET)', async () => {
        const response = await request(app.getHttpServer())
            .get('/category')
            .expect(200)
        expect(response.body.length).toBeGreaterThan(0);
        expect(typeof response.body).toBeDefined();
        expect(response.body).toBeInstanceOf(Object);
        expect(Array.isArray(response.body)).toBeTruthy();
    });

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

For the moment this solve my issue but I should warning you that my tests are running against my development DB so if you want to run your test against your testing DB you should include the configuration four your testing DB inside the moduleRef of the file test-conf.ts. If you don't know how to do it leave me a comment and I show you. Now you're ready to import your initTestServer() function wherever you want and have multiple test suites.

I hope this has helped !

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 monkeyUser
Solution 2 Binh Ho
Solution 3 Pau Llinas Amat