Andrei Ivascu
Andrei Ivascu

Reputation: 1284

Unable to test Angular service with Console constructor parameter

I am trying to implement a logging service as the name service implies. A concrete implementation of the logging service will be resolved at initialization time. This concrete implementation is using the console to log the messages. I need the Console in the constructor to be able to mock it without affecting the global console object.

I had the same test run on Jasmine and it would pass just fine. Also it works fine in the application, so I think it has something to do with Jest or its configuration.

I am trying to inject the Console interface into my Angular service like this:

export class ConsoleLoggerService implements LoggerService {
   constructor(public console: Console) { }
}

When I try to run my test:

describe('ConsoleLoggerService', () => {
  let service: ConsoleLoggerService;
  let consoleMock: Console;

  beforeEach(async(() => {
    consoleMock = {
      log(message?: any, ...optionalParams: any[]) { }
    } as Console;
    service = new ConsoleLoggerService(consoleMock);
  }));
  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

I get this error

  ● Test suite failed to run

    ReferenceError: Console is not defined

       9 | export class ConsoleLoggerService implements LoggerService {
      10 |
    > 11 |   constructor(public console: Console) { }
         |                               ^

In my understanding the Console interface comes from @types/node and should be available globally. Why does my test fail then?

I am using Angular 9, Jest 24.9 and Nx 9 for my workspace.

Upvotes: 1

Views: 351

Answers (1)

Derrick Awuah
Derrick Awuah

Reputation: 399

If you want to test that console log was hit use jest to mock it. In your test you could do something like this:

it('console.log the text "hello"', () => {
  console.log = jest.fn();

  // call some function here that will end up doing your logging

  // The first argument of the first call to the function was 'hello'
  expect(console.log.mock.calls[0][0]).toBe('hello');
});

If you're just injecting it like that for testing purposes I would recommend just using jest to mock it like above.

If you have to keep injecting it like that you can use the testbed to provide a fake provider:

beforeEach(() => {
    TestBed.configureTestingModule({
        // MockConsole would be some fake class that you create
        providers: [{provide: Console, useClass: MockConsole }]
    });
    service = TestBed.get(CgonsoleLoggerService);
});

Upvotes: 1

Related Questions