Skip to main content

Mock components, services and more out of annoying dependencies in Angular tests

chat on gitter npm version build status coverage status language grade

ng-mocks is a testing library which helps with mocking services, components, directives, pipes and modules in tests for Angular applications. When we have a noisy child component, or any other annoying dependency, ng-mocks has tools to turn these declarations into their mocks, keeping interfaces as they are, but suppressing their implementation.

The current version of ng-mocks has been tested and can be used with:

  • Angular 12 (Jasmine, Jest, Ivy, es5, es2015)
  • Angular 11 (Jasmine, Jest, Ivy, es5, es2015)
  • Angular 10 (Jasmine, Jest, Ivy, es5, es2015)
  • Angular 9 (Jasmine, Jest, Ivy, es5, es2015)
  • Angular 8 (Jasmine, Jest, es5, es2015)
  • Angular 7 (Jasmine, Jest, es5, es2015)
  • Angular 6 (Jasmine, Jest, es5, es2015)
  • Angular 5 (Jasmine, Jest, es5, es2015)

In the header menu we can find preconfigured sandboxes, where we could check all the features. To focus on a particular one, simply prefix it with fdescribe or fit.

Also, there is a brief summary with the latest changes in CHANGELOG.

Quick Navigation#

Very short introduction#

Global configuration for mocks in src/test.ts. In case of jest src/setup-jest.ts should be used.

src/test.ts
// All methods in mock declarations and providers// will be automatically spied on their creation.// https://ng-mocks.sudo.eu/extra/auto-spyngMocks.autoSpy('jasmine'); // or jest
// ngMocks.defaultMock helps to customize mocks// globally. Therefore, we can avoid copy-pasting// among tests.// https://ng-mocks.sudo.eu/api/ngMocks/defaultMockngMocks.defaultMock(AuthService, () => ({  isLoggedIn$: EMPTY,  currentUser$: EMPTY,}));

An example of a spec for a profile edit component.

src/profile.component.spec.ts
// Let's imagine that there is a ProfileComponent// and it has 3 text fields: email, firstName,// lastName, and a user can edit them.// In the following test suite, we would like to// cover behavior of the component.describe('profile', () => {  // First of all, we would like to reuse the same  // TestBed in every test.  // ngMocks.faster suppresses reset of TestBed  // after each test and allows to use TestBed,  // MockBuilder and MockRender in beforeAll.  // https://ng-mocks.sudo.eu/api/ngMocks/faster  ngMocks.faster();
  // Let's declare TestBed in beforeAll  // instead of beforeEach.  // The code mocks everything in SharedModule  // and provides a mock AuthService.  beforeAll(() => {    return TestBed.configureTestingModule({      imports: [        MockModule(SharedModule), // mock        ReactiveFormsModule, // real      ],      declarations: [        MockComponent(AvatarComponent), // mock        ProfileComponent, // real      ],      providers: [        MockProvider(AuthService), // mock      ],    }).compileComponents();  });
  // A test to ensure that ProfileComponent  // can be created.  it('should be created', () => {    // MockRender is an advanced version of    // TestBed.createComponent.    // It respects all lifecycle hooks,    // onPush change detection, and creates a    // wrapper component with a template like    // <app-root ...allInputs></profile>    // https://ng-mocks.sudo.eu/api/MockRender    const fixture = MockRender(ProfileComponent);
    expect(fixture.point.componentInstance).toEqual(      jasmine.any(ProfileComponent),    );  });
  // A test to ensure that the component listens  // on ctrl+s hotkey.  it('saves on ctrl+s hot key', () => {    // A fake profile.    const profile = {      email: '[email protected]',      firstName: 'testFirst2',      lastName: 'testLast2',    };
    // A spy to track save calls.    // MockInstance helps to configure mock    // providers, declarations and modules    // before their initialization and usage.    // https://ng-mocks.sudo.eu/api/MockInstance    const spySave = MockInstance(      StorageService,      'save',      jasmine.createSpy('StorageService.save'),    );
    // Renders <profile [profile]="params.profile">    // </profile>.    // https://ng-mocks.sudo.eu/api/MockRender    const { point } = MockRender(      ProfileComponent,      { profile }, // bindings    );
    // Let's change the value of the form control    // for email addresses with a random value.    // ngMocks.change finds a related control    // value accessor and updates it properly.    // https://ng-mocks.sudo.eu/api/ngMocks/change    ngMocks.change(      '[name=email]', // css selector      '[email protected]', // an email address    );
    // Let's ensure that nothing has been called.    expect(spySave).not.toHaveBeenCalled();
    // Let's assume that there is a host listener    // for a keyboard combination of ctrl+s,    // and we want to trigger it.    // ngMocks.trigger helps to emit events via    // simple interface.    // https://ng-mocks.sudo.eu/api/ngMocks/trigger    ngMocks.trigger(point, 'keyup.control.s');
    // The spy should be called with the user    // and the random email address.    expect(spySave).toHaveBeenCalledWith({      email: '[email protected]',      firstName: profile.firstName,      lastName: profile.lastName,    });  });});

Extra#

If you like ng-mocks, please support it:

Thank you!

P.S. Feel free to contact us if you need help.