Skip to main content

Auto Spy

ngMocks.autoSpy is useful when you want all mock methods to be spies.

Imagine the situation when a component calls a method of its dependency, and it should be covered by a test. The expect.toHaveBeenCalled accepts a spy, therefore, the method should be a spy, and that requires you to install the spy at the beginning of the test.

If you have more methods to assert, then you need to install more spies.

it('calls user.load', () => {
const userService = TestBed.inject(UserService);
spyOn(userService, 'init'); // why?
spyOn(userService, 'load'); // why?
spyOn(userService, 'set'); // why?

const fixture = TestBed.createComponent(UserComponent);
fixture.detectChanges();

expect(userService.init).toHaveBeenCalled();
expect(userService.load).toHaveBeenCalled();
expect(userService.set).toHaveBeenCalled();
});

The solution here is to use ngMocks.autoSpy. By default, all mock methods are empty functions which return undefined. With help of ngMocks.autoSpy, the methods will be spies.

So the test can look like:

it('calls user.load', () => {  
const fixture = TestBed.createComponent(UserComponent);
fixture.detectChanges();

const userService = TestBed.inject(UserService);
expect(userService.init).toHaveBeenCalled();
expect(userService.load).toHaveBeenCalled();
expect(userService.set).toHaveBeenCalled();
});

Installation

If we want automatically to spy all methods of services, components, directives and pipes in Angular tests, then add the next code to src/test.ts.

src/test.ts
import { ngMocks } from 'ng-mocks';

ngMocks.autoSpy('jasmine');
// // uncomment in case if existing tests are with spies already.
// jasmine.getEnv().allowRespy(true);

In case of jest add it to src/setup-jest.ts / src/test-setup.ts.

src/setup-jest.ts / src/test-setup.ts
import { ngMocks } from 'ng-mocks';

ngMocks.autoSpy('jest');

Custom spy

It might happen that you want to install your own spies for each method. For example, if you use another library, such as sinon.js.

In this case, you can provide your own callback which creates a spy:

ngMocks.autoSpy(spyName => {
return sinon.fake();
});

Change auto spy in a test

Pass default as the parameter, if we want to get the default behavior.

ngMocks.autoSpy('default');

Also, it remembers the calls, and we can reset to the previous config. It might be useful if we need to change auto spy behavior in a test via beforeEach or beforeAll, and restore it later in afterEach or afterAll without caring what it was.

beforeEach(() => ngMocks.autoSpy('jasmine'));
beforeEach(() => ngMocks.autoSpy('default'));
beforeEach(() => ngMocks.autoSpy('jasmine'));
afterEach(() => ngMocks.autoSpy('reset')); // now it is default
afterEach(() => ngMocks.autoSpy('reset')); // now it is jasmine
// out of calls, now it is default
afterEach(() => ngMocks.autoSpy('reset'));