Library / SDK
help-me-mom/ng-mocks avatar
help-me-mom/ng-mocks

ng-mocks turns an Angular TestBed full of boilerplate into one MockBuilder call

Angular testing library for mocking components, directives, pipes, services and facilitating TestBed setup

1,160 stars121 forksTypeScriptMIT

At a glance

What is it?
A testing library that mocks components, directives, pipes, modules, services and injection tokens, and supports every Angular version from 5 to 22 with Jasmine and Jest, and Angular 20 and up with Vitest. The real mechanism is a whitelist builder that keeps what you name and mocks the rest, which is a different default from Angular's own TestBed.
Who is it for?
Adopt ng-mocks if your Angular test suite is drowning in TestBed configuration, if you want one mocking approach that works across Angular versions, or if you need to mock a dependency without remembering which of the six Mock* helpers applies. Do not adopt it if your team has already settled on a working TestBed convention, because the value is in removing boilerplate you already maintain, not in replacing a stable setup.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

MockBuilder is a whitelist, which reverses the TestBed default

The library's headline features are mocking components, directives, pipes, modules, services and tokens, reducing boilerplate in tests, and giving access to declarations through a simple interface.

The mechanism that does the work is MockBuilder, and the difference from stock Angular is the direction of the default. The README's example says the configuration mocks everything in ProfileModule except ProfileComponent and ReactiveFormsModule.

ts
return MockBuilder(
  ProfileComponent,
  ProfileModule,
).keep(ReactiveFormsModule);

Angular's own TestBed asks you to declare what you want real and list what you want mocked. MockBuilder asks you to name what you want real and mocks everything else. That inversion is the whole idea, and it scales better, because a test that pulls in a module with fifty declarations needs two lines here rather than fifty mock entries.

The README shows the old-fashioned equivalent right below it, in a comment, and the contrast is instructive.

ts
// return TestBed.configureTestingModule({
//   imports: [
//     MockModule(SharedModule), // mock
//     ReactiveFormsModule, // real
//   ],
//   declarations: [
//     ProfileComponent, // real
//     MockPipe(CurrencyPipe), // mock
//     MockDirective(HoverDirective), // mock
//   ],
//   providers: [
//     MockProvider(AuthService), // mock
//   ],
// }).compileComponents();

The named helpers still exist and still work. MockModule, MockPipe, MockDirective, MockProvider and the rest are what you reach for when you want one specific thing mocked rather than a whole scope, and the example directory at the repository root has a folder for each of them, including MockActivatedRoute, MockSanitizer, MockObservable, MockReactiveForms, MockFormBindings and MockForms, which tells you the range of Angular features the library covers.

MockRender replaces createComponent and keeps the details right

The rendering helper is where the library earns its keep in component tests, and the README explains what it does beyond creating a component.

ts
const fixture = MockRender(ProfileComponent);

expect(
  fixture.point.componentInstance,
).toEqual(jasmine.any(ProfileComponent));

MockRender is described as an advanced version of TestBed.createComponent. It respects all lifecycle hooks, respects onPush change detection, and creates a wrapper component with a template like `<app-root ...allInputs></profile>` and renders it. The lifecycle hooks are mentioned twice in the same description, which is a hint that this is the thing people got wrong before.

The onPush point is the substantive one. A test that renders a component and then mutates an input usually needs `fixture.detectChanges()` at exactly the right moment, and a component with onPush change detection will silently not update if you get that wrong. If the wrapper component drives change detection for the rendered subject, the test stops depending on when you call it.

The fixture object is also richer than the stock one. `fixture.point.componentInstance` reaches the component under test through the wrapper, which is how you get at the instance when the component is not the root of the fixture. That is a small interface detail that removes a category of awkward casts from a test suite.

MockInstance is the other helper you will use constantly, and the example directory has a folder for it. It configures mocks after creation, and the README's setup snippet also uses it in the other direction, with MockInstance.scope() to reset customisations after each test, so a mock configured in one spec does not leak into the next.

Global setup replaces per-test configuration

The setup file is where the library asks you to put its global configuration, and the two options there are the ones that decide whether the library feels invisible.

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,
}));

The file location depends on the runner: `src/test.ts` for Jasmine, `src/setup-jest.ts` or `src/test-setup.ts` for Jest, and `src/setup-vitest.ts` for Vitest, where the README also points at the native Angular setup instructions.

`autoSpy` is the first option and it is a strong default. Every method in a mock declaration or provider is automatically spied on at creation, which means you can assert that a method was called without writing a spy in every test. The argument is the runner name, which is how one codebase can support Jasmine, Jest and Vitest with the same library.

`defaultMock` is the second. It customises a mock globally so you do not copy the same stub into every spec. The example gives a service with two observable properties replaced by EMPTY, which is the common case of a service that would otherwise need a subject in every test. The README also notes that automatic resetting can be enabled in the test file instead of calling MockInstance.scope() per test, which is the other way to avoid state leaking between specs.

The compatibility table is the honest engineering document

The README leads with a matrix of what has been tested, and it is a more useful artifact than a marketing claim. The table covers Angular 5 through 22, and the ng-mocks column says latest for every row, so the same release supports the whole range.

The columns are jasmine, jest, vitest, ivy, standalone, signals and defer. Jasmine and Jest are supported across the entire range from Angular 5 to 22. Vitest appears from Angular 20 upwards, and there is a specific note explaining why: Angular 20's native Vitest support is zoneless-only because its supported Zone.js version has no Vitest patch. That is the kind of note that saves a team an afternoon, because the symptom otherwise looks like a library bug.

Ivy is supported from Angular 9, standalone from Angular 14, signals from Angular 16, and defer absent below Angular 17. The signals row is worth noting: an Angular version can support the language feature while the testing library does not yet support it, and the table is where that shows up.

The maintenance picture is active. v14.18.1 was published on 2026-09-18, v14.18.0 on 2026-09-15 and v14.17.6 on 2026-09-10, and the last push to the repository was on 2026-10-19 with the repository not archived. The version is on the 14 line, which is a long-lived line for a library of this kind.

The library is MIT licensed, published to npm as `ng-mocks`, with documentation at ng-mocks.sudo.eu, a changelog, a Discord-style Gitter room, and a Stack Overflow tag for questions.

The repository is a multi-version test matrix, not a single package

The repository layout explains the scale of the testing effort better than any badge does.

There are separate test directories: `tests/`, `tests-e2e/`, `tests-failures/`, `tests-performance/` and `e2e/`. The `tests-failures/` directory is the one that tells you the most, because it holds the cases where a mock is expected to fail in a particular way, which is what makes the error messages of a mocking library trustworthy.

The `examples/` directory contains a folder per public API, and the list is long: MockActivatedRoute, MockBuilder, MockComponent, MockDirective-Attribute, MockDirective-Structural, MockFormBindings, MockForms, MockHostDirective, MockInitializationLogic, MockInstance, MockModule, MockObservable, MockPipe, MockProvider, MockReactiveForms, MockRender, MockSanitizer, MockViewChild, and a set of Test* directories for the testing helpers. Each of those is a runnable example, which is a form of documentation that stays correct because it is compiled.

The build pipeline is where the Angular version matrix lives. The `spread` script runs `libs/compat-spread/spread.sh`, and the `libs/` directory holds the library alongside the compatibility spread tooling, with `test-spread.conf` and `test-spread-app.conf` at the root configuring it. The idea is that the same source is tested against many Angular versions, which is exactly what the README's compatibility table claims and what makes the claim credible.

Everything runs through Docker Compose. The `compose.yml` defines an `ng-mocks` service on a Puppeteer Node image with the repository mounted, plus separate `docs-build`, `docs` and `e2e` services, and an `a5es5` service on an older Node 8 image for the Angular 5 end of the range. The caching of the puppeteer, node-gyp and npm directories as named volumes keeps repeated runs fast.

Unit tests run under Karma, with `karma start` as the test script and a webpack config at the root, and there is a Docker-based path for the end to end tests plus a `compose.sh` wrapper. Formatting is Prettier with a staged hook through pretty-quick, linting is ESLint with a flat config, and releases go through semantic-release with commitlint enforcing the commit format, and Renovate handles dependency updates.

Editorial conclusion

Adopt ng-mocks if your Angular test suite is drowning in TestBed configuration, if you want one mocking approach that works across Angular versions, or if you need to mock a dependency without remembering which of the six Mock* helpers applies. Do not adopt it if your team has already settled on a working TestBed convention, because the value is in removing boilerplate you already maintain, not in replacing a stable setup. Verify first that your Angular version and test runner appear in the compatibility table, that the runner is configured in the setup file with the right autoSpy argument, and that your global defaultMock customisations do not leak between test files.

Frequently asked questions

What is the difference between MockBuilder and TestBed.configureTestingModule?

MockBuilder works as a whitelist. You name the component under test and the module it belongs to, and it mocks everything else, keeping only what you explicitly keep, such as .keep(ReactiveFormsModule). TestBed asks you to declare each real and mocked dependency one by one.

Which Angular versions and test runners does ng-mocks support?

The README table lists Angular 5 through 22 with the latest ng-mocks for all of them, with Jasmine and Jest supported across the whole range. Vitest is listed from Angular 20 upwards, because Angular 20's native Vitest support is zoneless-only since its supported Zone.js version has no Vitest patch.

How do I configure ng-mocks globally?

Put the configuration in the setup file for your runner, src/test.ts for Jasmine, src/setup-jest.ts or src/test-setup.ts for Jest, and src/setup-vitest.ts for Vitest. Call ngMocks.autoSpy with the runner name so mock methods are spied on creation, and use ngMocks.defaultMock to customise a mock globally.

What does MockRender add over TestBed.createComponent?

MockRender is an advanced version of createComponent that respects all lifecycle hooks and onPush change detection, and creates a wrapper component with a template like <app-root ...allInputs></profile>. The subject component is reachable through fixture.point.componentInstance.

How do I stop mock customisations leaking between test files?

Call MockInstance.scope() in a beforeEach to reset customisations after each test, or enable automatic resetting in the test file as the README describes. The same setup file is where ngMocks.defaultMock customisations are declared.

Official sources

  1. help-me-mom/ng-mocks on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/help-me-mom-ng-mocks.svg)](https://hysenlabs.com/projects/help-me-mom-ng-mocks)

Was this useful?