Nest: E2E Test: server.close is not a function

Created on 8 Dec 2017  路  6Comments  路  Source: nestjs/nest

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior


I wrote an e2e test for my application. Where I create my Nest module in the before method and close the module in after.

describe('Application e2e', () => {
  const server = express();
  let app: INestApplication;

  before(async () => {
    const module = await Test.createTestingModule({
      modules: [ApplicationModule],
    })
      .compile();
    app = module.createNestApplication(server);
    await app.init();
  });

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

 // tests...

This works fine but as soon as I add a WebSocketGateway the the module, I get the following error:

TypeError: server.close is not a function
      at servers.forEach (node_modules/@nestjs/websockets/socket-module.js:42:48)
      at Map.forEach (native)
      at SocketModule.close (node_modules/@nestjs/websockets/socket-module.js:42:17)
      at NestApplication.close (node_modules/@nestjs/core/nest-application.js:118:48)
      at Context.after (src/modules/tournament/tests/teamorder.e2e-spec.ts:35:15)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

Expected behavior


The module should close successfully.

Minimal reproduction of the problem with instructions


It seems like an easy to fix error but I will create an example if needed.

Environment


Nest version: 4.4.2


For Tooling issues:
- Node version: 8.6.0  
- Platform:  Mac 

Others:

Thanks for this very great project!

type question 馃檶

Most helpful comment

And no code was ever sent...

All 6 comments

Hi @hpop,
I can't reproduce this issue. Could you share more code?

I am a bit busy at the moment but I will send you some code till the end of the week.

And no code was ever sent...

I am seeing a very similar issue.

"before all" hook:
     TypeError: instance.onModuleInit is not a function
      at iterare_1.default.map.filter.filter.forEach.instance (node_modules\@nestjs\core\nest-application.js:206:43)
      at IteratorWithOperators.forEach (node_modules\iterare\src\iterate.ts:174:13)
      at NestApplication.callModuleInitHook (node_modules\@nestjs\core\nest-application.js:206:14)
      at modules.forEach.module (node_modules\@nestjs\core\nest-application.js:197:18)
      at Map.forEach (<anonymous>)
      at NestApplication.callInitHook (node_modules\@nestjs\core\nest-application.js:196:17)
      at NestApplication.<anonymous> (node_modules\@nestjs\core\nest-application.js:78:18)
      at Generator.next (<anonymous>)
      at fulfilled (node_modules\@nestjs\core\nest-application.js:4:58)
      at <anonymous>

and

       "after all" hook:
     TypeError: instance.onModuleDestroy is not a function
      at iterare_1.default.map.filter.filter.forEach.instance (node_modules\@nestjs\core\nest-application.js:223:43)
      at IteratorWithOperators.forEach (node_modules\iterare\src\iterate.ts:174:13)
      at NestApplication.callModuleDestroyHook (node_modules\@nestjs\core\nest-application.js:223:14)
      at modules.forEach.module (node_modules\@nestjs\core\nest-application.js:214:18)
      at Map.forEach (<anonymous>)
      at NestApplication.callDestroyHook (node_modules\@nestjs\core\nest-application.js:213:17)
      at NestApplication.close (node_modules\@nestjs\core\nest-application.js:164:14)
      at Object.<anonymous> (src\room\rooms.controller.spec.ts:90:15)
      at Generator.next (<anonymous>)
      at src\room\rooms.controller.spec.ts:7:71
      at new Promise (<anonymous>)
      at __awaiter (src\room\rooms.controller.spec.ts:3:12)
      at Context.after (src\room\rooms.controller.spec.ts:89:20)

My nest core version is 4.6.0 and my nest testing version is 4.6.6.

describe.only('e2e tests', () => {
  let server;
  let app: INestApplication;
  let mockRoomService: RoomService;

  before(async () => {
    mockRoomService = mock(RoomService);
    when(mockRoomService.findAll()).thenReturn(Promise.resolve([] as any));

    const module = await Test.createTestingModule({
      components: [RoomService],
      controllers: [RoomController, RoomsController],
    })
    .overrideComponent(RoomService)
    .useValue(instance(mockRoomService))
    .compile();

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

  it('/GET', (done) => {
    request(server)
      .get('/')
      .then((response) => {
        expect(response).to.equal([]);
        done();
      })
      .catch(done);
  });

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

@kamilmysliwiec, I'm seeing the exact same issue as the OP. E2E tests that create an application from a module that uses a WebSocketGateway throw an error on app.close().

core.module.ts

import { Module } from '@nestjs/common';
import { DeviceGateway } from './device.gateway';

@Module({
    components: [DeviceGateway]
})
export class CoreModule {}

device.gateway.ts

of note here: of all the lifecycle methods implemented, only afterInit is executed

import {
    OnGatewayConnection, OnGatewayDisconnect,
    OnGatewayInit,
    SubscribeMessage,
    WebSocketGateway,
    WebSocketServer,
    WsResponse
} from '@nestjs/websockets';
import * as config from 'config';

// App listens on 9000, WS listens on 9001
@WebSocketGateway({ port: config.Ws.port, namespace: 'ws/devices' })
export class DeviceGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
    // I am executed
    afterInit(server:any)
    {
        console.log('After Init');
    }

    // I am never executed
    handleConnection(client:any)
    {
        console.log('On Connection');
    }

    // I am never executed
    handleDisconnect(client:any)
    {
        console.log('On Disconnect');
    }
}

iambroken.e2e.ts

import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { CoreModule } from '../../../src/core/core.module';
import * as config from 'config';
import * as SocketIOClient from 'socket.io-client';
import Socket = SocketIOClient.Socket;

describe('IAmBroken (e2e)', () =>
{
    let app:INestApplication,
    module:TestingModule,
        socket:any;

    before(async () =>
    {
        module = await Test.createTestingModule({
            imports: [CoreModule]
    }).compile();

    app = module.createNestApplication();
    await app.init();
        socket = SocketIOClient.connect(`ws://localhost:${config.Ws.port}`, { forceNew: true });
    });

    after(function(done)
    {
        // I cause BIG problems
        app.close();
        done();
    });

    it('connects and disconnects without error', () =>
    {
        socket.on('connect', () =>
        {
            expect(socket.connected).to.eq(true);

            socket.on('disconnect', (s:string) =>
            {
                expect(socket.connected).to.eq(false);
                expect(s).to.eq('io client disconnect');
            });

            socket.close();
        });
    });
});

The above test fails as long as the DeviceGateway is included in the CoreModule. This actually means that all tests are failing as long as the DeviceGateway is included. Here is the stack:

2) IAmBroken (e2e)
       "after all" hook:
     TypeError: server.close is not a function
      at servers.forEach (node_modules/@nestjs/websockets/socket-module.js:42:48)
      at Map.forEach (<anonymous>)
      at SocketModule.close (node_modules/@nestjs/websockets/socket-module.js:42:17)
      at NestApplication.close (node_modules/@nestjs/core/nest-application.js:176:48)
      at Context.<anonymous> (e2e/core/jobs/iambroken.e2e.ts:26:7)

If I get rid of app.close() in the after all hook above, the test passes, but as I mentioned, only the afterInit lifecycle hook is ever executed. handleDisconnect and handleConnection never execute.

I would venture that I'm missing something important in your websockets package, but I can't find an answer in the docs. I'd really appreciate some guidance here.

Update

On closer inspection, I don't think it's me. If I don't use a namespace in my WebSocketGateway, everything works as expected. If I do, when nest calls SocketModule.close there is no server with my namespace, hence the above error.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

thohoh picture thohoh  路  3Comments

yanshuf0 picture yanshuf0  路  3Comments

KamGor picture KamGor  路  3Comments

menme95 picture menme95  路  3Comments

2233322 picture 2233322  路  3Comments