nest icon indicating copy to clipboard operation
nest copied to clipboard

Jest spy doesn't work on Microservices Controller (EventPattern) E2E Tests

Open elton-okawa opened this issue 1 year ago • 1 comments
trafficstars

Is there an existing issue for this?

  • [X] I have searched the existing issues

Current behavior

  1. Spying on Controller instance - handler is called but spy does not track it
  2. Spying on Controller prototype before app is initialized - handler is not called
  3. Spying on Controller prototype after app is initialized - handler is called but spy does not track it

Minimum reproduction code

https://github.com/elton-okawa/nestjs-spy-controller-issue

Steps to reproduce

npm install

// run all tests
npm run test:e2e

// run individual tests (better to see logs)
npm run test:e2e -- -t 'should spy controller instance'
npm run test:e2e -- -t 'should spy controller prototype before init'
npm run test:e2e -- -t 'should spy controller prototype after init'

Expected behavior

From a similar issue comment: https://github.com/nestjs/nest/issues/8790#issuecomment-994480901 (As the comment suggests, I couldn't find any related issue besides this one)

Long story short: you can spy on/mock service methods. You can't spy on/mock controller methods (annotated methods) after your app is initialized (execution context is created).

I understood that it's possible to spy/mock annotated methods as long as you do it before the app is initialized, so behavior (1) and (3) is expected to fail, but not (2)

Package

  • [ ] I don't know. Or some 3rd-party package
  • [ ] @nestjs/common
  • [X] @nestjs/core
  • [X] @nestjs/microservices
  • [ ] @nestjs/platform-express
  • [ ] @nestjs/platform-fastify
  • [ ] @nestjs/platform-socket.io
  • [ ] @nestjs/platform-ws
  • [X] @nestjs/testing
  • [ ] @nestjs/websockets
  • [ ] Other (see below)

Other package

No response

NestJS version

10.3.8

Packages versions

[System Information]
OS Version     : Linux 5.15.146.1-microsoft-standard-WSL2
NodeJS Version : v20.11.1
NPM Version    : 10.2.4

[Nest CLI]
Nest CLI Version : 10.3.2

[Nest Platform Information]
platform-express version : 10.3.8
microservices version    : 10.3.8
schematics version       : 10.1.1
testing version          : 10.3.8
common version           : 10.3.8
core version             : 10.3.8
cli version              : 10.3.2

Node.js version

20.11.1

In which operating systems have you tested?

  • [ ] macOS
  • [ ] Windows
  • [X] Linux

Other

  1. Spying on Controller instance - handler is called but spy does not track it
[Nest] 47442  - 04/21/2024, 7:28:41 AM   DEBUG [E2E Test] Producing message...
[Nest] 47442  - 04/21/2024, 7:28:41 AM   DEBUG [E2E Test] Message produced successfully!
[Nest] 47442  - 04/21/2024, 7:28:41 AM   DEBUG [E2E Test] Waiting "message to be consumed" for 10000ms...
[Nest] 47442  - 04/21/2024, 7:28:41 AM     LOG [AppService] Message received: "spy controller instance"
[Nest] 47442  - 04/21/2024, 7:28:51 AM   DEBUG [E2E Test] Finished waiting for "message to be consumed"
[Nest] 47442  - 04/21/2024, 7:28:51 AM   DEBUG [E2E Test] Message should be consumed at this point
...

  ● AppController (e2e) › controller › should spy controller instance

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      60 |       await produceEventAndWait(producer, 'spy controller instance');
      61 |
    > 62 |       expect(handlerSpy).toHaveBeenCalledTimes(1);
         |                          ^
      63 |     });
      64 |
      65 |     it('should spy controller prototype before init', async () => {

      at Object.<anonymous> (test/app.e2e-spec.ts:62:26)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 5 skipped, 6 total
Snapshots:   0 total
Time:        44.32 s, estimated 249 s
Ran all test suites with tests matching "should spy controller instance".
  1. Spying on Controller prototype before app is initialized - handler is not called
[Nest] 48666  - 04/21/2024, 7:31:55 AM   DEBUG [E2E Test] Producing message...
[Nest] 48666  - 04/21/2024, 7:31:55 AM   DEBUG [E2E Test] Message produced successfully!
[Nest] 48666  - 04/21/2024, 7:31:55 AM   DEBUG [E2E Test] Waiting "message to be consumed" for 10000ms...
[Nest] 48666  - 04/21/2024, 7:32:05 AM   DEBUG [E2E Test] Finished waiting for "message to be consumed"
[Nest] 48666  - 04/21/2024, 7:32:05 AM   DEBUG [E2E Test] Message should be consumed at this point
...


  ● AppController (e2e) › controller › should spy controller prototype before init

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      72 |       );
      73 |
    > 74 |       expect(handlerSpy).toHaveBeenCalledTimes(1);
         |                          ^
      75 |     });
      76 |
      77 |     it('should spy controller prototype after init', async () => {

      at Object.<anonymous> (test/app.e2e-spec.ts:74:26)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 5 skipped, 6 total
Snapshots:   0 total
Time:        51.975 s
Ran all test suites with tests matching "spy controller prototype before init".
  1. Spying on Controller prototype after app is initialized - handler is called but spy does not track it
[Nest] 49480  - 04/21/2024, 7:33:57 AM   DEBUG [E2E Test] Producing message...
[Nest] 49480  - 04/21/2024, 7:33:57 AM   DEBUG [E2E Test] Message produced successfully!
[Nest] 49480  - 04/21/2024, 7:33:57 AM   DEBUG [E2E Test] Waiting "message to be consumed" for 10000ms...
[Nest] 49480  - 04/21/2024, 7:33:57 AM     LOG [AppService] Message received: "spy controller prototype after init"
[Nest] 49480  - 04/21/2024, 7:34:07 AM   DEBUG [E2E Test] Finished waiting for "message to be consumed"
[Nest] 49480  - 04/21/2024, 7:34:07 AM   DEBUG [E2E Test] Message should be consumed at this point
...

 ● AppController (e2e) › controller › should spy controller prototype after init

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      84 |       );
      85 |
    > 86 |       expect(handlerSpy).toHaveBeenCalledTimes(1);
         |                          ^
      87 |     });
      88 |   });
      89 | });

      at Object.<anonymous> (test/app.e2e-spec.ts:86:26)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 5 skipped, 6 total
Snapshots:   0 total
Time:        44.39 s, estimated 52 s
Ran all test suites with tests matching "spy controller prototype after init".

elton-okawa avatar Apr 21 '24 12:04 elton-okawa

This is the root of the issue. The function is not called on the instance, but rather on the prototype https://github.com/nestjs/nest/blob/master/packages/microservices/listener-metadata-explorer.ts#L50

esahin90 avatar Jun 25 '24 09:06 esahin90