2

I have Nest.js app, where certain provider is injected into another provider:

    export class AppService {
      public constructor(private readonly appInnerService: AppInnerService) {}
    }

AppService has a method publish which calls appInnerService send method. I created unit tests for AppService, where I want to mock AppInnerService provider:

      describe('App service', () => {
          let appService: AppService;
          const appInnerService = {
            send: jest.fn(),
          };
        
          beforeAll(async () => {
            const moduleRef = await Test.createTestingModule({
              providers: [AppService, AppInnerService],
            })
              .overrideProvider(AppInnerService)
              .useValue(appInnerService)
              .compile();
        
            appService = moduleRef.get<AppService>(AppService);
          });
    
          it('should work', () => {
            appService.publish({});
    
            expect(appInnerService.send).toHaveBeenCalled();
          });
        }

Above code doesn't work, AppInnerService isn't injected into AppService, instead undefined is passed to constructor. Why above test isn't working and how can I fix it (without manually creating AppService class with mocked service, I want to use testing module created by @nestjs/testing package)?

Michael Härtl
  • 8,428
  • 5
  • 35
  • 62
Furman
  • 2,017
  • 3
  • 25
  • 43
  • Why use `overrideProvider` instead of a [custom provider](https://docs.nestjs.com/fundamentals/custom-providers) for `AppInnerService` – Jay McDoniel Oct 13 '21 at 15:02
  • It doesn't matter, it still doesn't work. I tried different combinations: custom provider, importing whole module in Test.createTestingModule and then overriding all providers except for tested one, result is always the same, AppInnerService isn't injected into AppService – Furman Oct 13 '21 at 21:51
  • `AppService` is `@Injectable()`, right? – Jay McDoniel Oct 13 '21 at 21:54
  • . Well I was just about to reply "yes, of course", but I inspected my full code just to be absolutely sure, and it turned out that I had a typo in my code. Instead of "@Injectable()" above my class declaration I had just "Injectable()". Anyway BIG thank you, I wasted nearly half of my workday just trying to solve this :( – Furman Oct 13 '21 at 22:00

2 Answers2

2

For closure on the problem: AppService needed to be decorated with @Injectable() to get typescript to reflect the constructor parameter metadata. With just Injectable() as was there, it's just a function call and not a decorator, so the metadata was not reflected and Nest could not act upon it.

Jay McDoniel
  • 57,339
  • 7
  • 135
  • 147
  • 2
    I'm having the same issue here, and unfortunately both modules/services has `@Injectable()`. Any idea of possible issues? – jNewbie Aug 09 '22 at 05:06
0

I had the same issue, and both services have @Injectable() and not Injectable().

Setting emitDecoratorMetadata ts config option to true solve the issue!