---
title: "Testing Components In Angular: NO_ERRORS_SCHEMA, Stub Components, and ng-mocks"
date: "2024-07-13"
slug: "testing-components-in-angular-noerrorsschema-stub-components-and-ngmocks"
author: "Dany Paredes"
canonical: "https://danywalls.com/testing-components-in-angular-noerrorsschema-stub-components-and-ngmocks"
description: "Learn how to test Angular components with complex child dependencies. Compare NO_ERRORS_SCHEMA, manual stub components, and ng-mocks in both legacy and modern Standalone Angular."
---


When writing unit tests for isolated Angular components, testing is fast and predictable. The friction begins when your component relies on child components, which in turn depend on UI libraries (like Kendo UI or Angular Material), form modules, or HTTP services.

Suddenly, running a simple `it('should create')` test fails with `NullInjectorError` or `NG0304: 'app-child' is not a known element`.

> ⚡ **Using Modern Angular (v17+)?** Jump directly to [Modern Angular: Testing Standalone Components with `provideHttpClientTesting()`](#modern-angular-testing-standalone-components-with-providehttpclienttesting) to see how to configure modern TestBed setups cleanly.

In this guide, we will evaluate the three most common strategies to resolve child component dependencies in Angular tests: **`NO_ERRORS_SCHEMA`**, **Manual Stub Components**, and **`ng-mocks`**.

Let's start with our baseline testing scenario.

---

## 1. The Scenario: Parent Component with Deep Child Dependencies 🛍️

Imagine a parent component that displays a product catalog header and renders a child product list:

```typescript
// products.component.ts (Modern Standalone)
import { Component, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { ProductsService } from './products.service';
import { ProductsListComponent } from './products-list.component';

@Component({
  selector: 'app-products',
  standalone: true,
  imports: [AsyncPipe, ProductsListComponent],
  template: `
    <div class="products-container">
      @if (total$ | async; as total) {
        <h2>We have {{ total }} special offers today!</h2>
      }
      <app-products-list />
    </div>
  `
})
export class ProductsComponent {
  private readonly productsService = inject(ProductsService);
  readonly total$ = this.productsService.totalOffers$;
}
```

When you write a naive unit test with `TestBed`:

```typescript
beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [ProductsComponent]
  }).compileComponents();
});
```

The test runner immediately crashes with two common errors:
1. `NullInjectorError: No provider for HttpClient!` (triggered by `ProductsService`).
2. `NG0304: 'kendo-listview' is not a known element` (triggered deep inside `ProductsListComponent`).

Now let's examine why reaching for `NO_ERRORS_SCHEMA` is risky.

---

## 2. Approach 1: `NO_ERRORS_SCHEMA` (The Dangerous Shortcut) ⚠️

Importing `NO_ERRORS_SCHEMA` from `@angular/core` tells the Angular compiler: *"Ignore any unknown HTML tag or attribute and treat it as a generic HTML element."*

```typescript
import { TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ProductsComponent } from './products.component';

beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [ProductsComponent],
    schemas: [NO_ERRORS_SCHEMA] // 👈 Suppresses template compilation errors
  }).compileComponents();
});
```

### Why `NO_ERRORS_SCHEMA` is Dangerous:
- ❌ **Hides Real Template Bugs**: If you misspell a component tag (`<app-prodcut-list>`) or bind to a non-existent property (`[prduct]="item"`), your tests will still pass green.
- ❌ **False Sense of Security**: Reduces test coverage and lets production template errors slip into deployment.

Now let's look at a safer alternative: Manual Stub Components.

---

## 3. Approach 2: Manual Stub Components 🛡️

A stub component is a lightweight dummy class that shares the same CSS selector and inputs as the real child component, but with an empty template:

```typescript
import { Component, input } from '@angular/core';
import { Product } from './product.model';

@Component({
  selector: 'app-products-list',
  standalone: true,
  template: '<div class="stub-products-list">Mock Products List</div>'
})
export class ProductsListStubComponent {
  readonly products = input<Product[]>([]);
}
```

In your test setup, override the real component with the stub:

```typescript
beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [ProductsComponent]
  })
  .overrideComponent(ProductsComponent, {
    remove: { imports: [ProductsListComponent] },
    add: { imports: [ProductsListStubComponent] }
  })
  .compileComponents();
});
```

### Pros and Cons of Manual Stubs:
- ✅ **Pros**: Pure isolation, no third-party UI dependencies needed, real template validation.
- ❌ **Cons**: High maintenance cost. Whenever inputs or outputs change on child components, you must manually update every stub.

Now let's look at the best solution: automated mocking with `ng-mocks`.

---

## 4. Approach 3: Automated Mocking with `ng-mocks` 🚀

**[ng-mocks](https://ng-mocks.sudo.eu/)** is an open-source testing utility that automatically creates type-safe mocks of components, directives, pipes, and services in a single line.

Install it with:

```bash
npm install ng-mocks --save-dev
```

### Using `MockBuilder` and `MockRender`

Instead of manually crafting stubs or dealing with complex overrides, use `MockBuilder`:

```typescript
import { TestBed } from '@angular/core/testing';
import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { ProductsComponent } from './products.component';
import { ProductsListComponent } from './products-list.component';

describe('ProductsComponent with ng-mocks', () => {
  beforeEach(() => {
    return MockBuilder(ProductsComponent) // 1. Keep the component under test real
      .mock(ProductsListComponent)         // 2. Automatically mock the child component!
      .provide([provideHttpClient(), provideHttpClientTesting()]);
  });

  it('should create and render child mock cleanly', () => {
    const fixture = MockRender(ProductsComponent);
    const component = fixture.point.componentInstance;

    expect(component).toBeTruthy();
    // Verify that the mocked child exists in the DOM without errors
    expect(ngMocks.find(fixture, ProductsListComponent)).toBeTruthy();
  });
});
```

Now let's see how modern Angular (v17+) configures testing dependencies natively.

---

## 5. Modern Angular: Testing Standalone Components with `provideHttpClientTesting()` ⚡

In modern Angular (v17+), we no longer import `HttpClientTestingModule`. Instead, we use the functional provider `provideHttpClientTesting()` alongside `provideHttpClient()`:

```typescript
import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting, HttpTestingController } from '@angular/common/http/testing';
import { of } from 'rxjs';
import { ProductsComponent } from './products.component';
import { ProductsService } from './products.service';

describe('ProductsComponent (Modern Standalone)', () => {
  let serviceMock: jasmine.SpyObj<ProductsService>;

  beforeEach(async () => {
    serviceMock = jasmine.createSpyObj('ProductsService', [], {
      totalOffers$: of(15)
    });

    await TestBed.configureTestingModule({
      imports: [ProductsComponent],
      providers: [
        provideHttpClient(),
        provideHttpClientTesting(),
        { provide: ProductsService, useValue: serviceMock }
      ]
    }).compileComponents();
  });

  it('should display the total number of offers from service', () => {
    const fixture = TestBed.createComponent(ProductsComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;
    expect(compiled.querySelector('h2')?.textContent).toContain('15 special offers');
  });
});
```

---

## Strategy Comparison Matrix 📊

| Strategy | Setup Complexity | Maintenance Overhead | Bug Detection Safety | Best Use Case |
| :--- | :---: | :---: | :---: | :--- |
| **`NO_ERRORS_SCHEMA`** | Low | Low | ❌ Dangerous (Hides bugs) | Fast prototypes (avoid in production) |
| **Manual Stub Components** | Medium | High | ✅ Safe | Small apps with few child components |
| **`ng-mocks` (`MockBuilder`)** | Low | Very Low | ✅ Safe & Automated | Enterprise apps, complex UI libraries |
| **Provider Mocking (`useValue`)** | Low | Low | ✅ Strict | Service and dependency isolation |

---

## Recap 🛠️

When testing Angular components with child dependencies:
1. Avoid `NO_ERRORS_SCHEMA` in production test suites to prevent masking real template bugs.
2. Use **`ng-mocks` (`MockBuilder`)** for effortless, maintenance-free child component mocking.
3. In modern Angular (v17+), use **`provideHttpClientTesting()`** and standalone component imports for clean, fast unit tests.

For more Angular testing best practices, check out my articles on [How to Share Data Between Components in Angular](/how-to-share-data-between-components-in-angular) and [How to Handle and Catch Errors in RxJS and Angular](/how-to-handle-and-catch-errors-in-rxjs)!

