Skip to main content

Mock components, services, and more to simplify Angular testing

chat on gitter npm version build status coverage status

ng-mocks is a testing library that helps with mocking services, components, directives, pipes and modules in tests for Angular applications. When you 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:

angularng-mocksjasminejestvitestivystandalonesignalsdefer
22latestyesyesyesyesyesyesyes
21latestyesyesyesyesyesyesyes
20latestyesyesyesyesyesyesyes
19latestyesyesyesyesyesyes
18latestyesyesyesyesyesyes
17latestyesyesyesyesyesyes
16latestyesyesyesyesyes
15latestyesyesyesyes
14latestyesyesyesyes
13latestyesyesyes
12latestyesyesyes
11latestyesyesyes
10latestyesyesyes
9latestyesyesyes
8latestyesyes
7latestyesyes
6latestyesyes
5latestyesyes

Angular 20's native Vitest support is zoneless-only because its supported Zone.js version has no Vitest patch.

The header menu contains preconfigured sandboxes, where you can explore the features. To focus on a particular one, simply prefix it with fdescribe or fit.

There is also a brief summary of the latest changes in CHANGELOG.

Quick Navigation​

Very short introduction​

Put the global configuration for mocks in the setup file for your test runner. For Jasmine, use src/test.ts. For Jest, use src/setup-jest.ts / src/test-setup.ts. For Vitest, use src/setup-vitest.ts and follow the native Angular setup.

src/test.ts
// All methods in mock declarations and providers
// will be automatically spied on their creation.
// https://ng-mocks.sudo.eu/extra/auto-spy
ngMocks.autoSpy('jasmine');
// In setup-jest.ts: ngMocks.autoSpy('jest');
// In setup-vitest.ts: ngMocks.autoSpy('vitest');

// ngMocks.defaultMock helps to customize mocks
// globally. Therefore, we can avoid copy-pasting
// among tests.
// https://ng-mocks.sudo.eu/api/ngMocks/defaultMock
ngMocks.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 the behavior of the component.
describe('profile:builder', () => {
// Helps to reset customizations after each test.
// Alternatively, you can enable
// automatic resetting in test.ts.
MockInstance.scope();

// Let's configure TestBed via MockBuilder.
// The code below says to mock everything in
// ProfileModule except ProfileComponent and
// ReactiveFormsModule.
beforeEach(() => {
// The result of MockBuilder should be returned.
// https://ng-mocks.sudo.eu/api/MockBuilder
return MockBuilder(ProfileComponent, ProfileModule)
.keep(ReactiveFormsModule);
// // or the old-fashioned way
// return TestBed.configureTestingModule({
// imports: [
// MockModule(SharedModule), // mock
// ReactiveFormsModule, // real
// ],
// declarations: [
// ProfileComponent, // real
// MockPipe(CurrencyPipe), // mock
// MockDirective(HoverDirective), // mock
// ],
// 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>
// and renders it.
// It also respects all lifecycle hooks.
// 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 = {
firstName: 'testFirst2',
lastName: 'testLast2',
};

// A spy to track save calls.
// MockInstance helps 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(),
// or, for Jest
// jest.fn(),
);

// 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 profile
// and the random email address.
expect(spySave).toHaveBeenCalledWith({
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.