Skip to main content

How to mock components in Angular tests

A mock component in Angular tests can be created by MockComponent function. The mock component respects the interface of its original component, but all its methods are dummies.

To create a mock component, simply pass its class into MockComponent function.

TestBed.configureTestingModule({
declarations: [
// for a single component
MockComponent(Component),

// for a set of components
...MockComponents(Component1, Component2),
],
});

The class of a mock component has:

  • the same selector
  • the same inputs and outputs with alias support
  • signal inputs which stay callable when declared with input() or input.required()
  • templates with pure <ng-content> tags to allow transclusion
  • support for @ContentChild and @ContentChildren
  • support for ControlValueAccessor, Validator and AsyncValidator
  • support for exportAs
  • support for standalone components
tip

Information about mocking FormControl, ControlValueAccessor, Validator and AsyncValidator is in a different section.

Simple example​

Let's pretend that in our Angular application TargetComponent depends on a child component of DependencyComponent and we want to use its mock object in a test.

Usually beforeEach looks like:

describe('Test', () => {
let component: TargetComponent;
let fixture: ComponentFixture<TargetComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
// our component for testing
TargetComponent,

// the annoying dependency
DependencyComponent,
],
});

fixture = TestBed.createComponent(TargetComponent);
component = fixture.componentInstance;
});
});

To create a mock child component, simply pass its class into MockComponent:

TestBed.configureTestingModule({
declarations: [
TargetComponent,

// profit
MockComponent(DependencyComponent),
],
});

Or be like a pro and use MockBuilder, its .mock method and MockRender:

describe('Test', () => {
beforeEach(() => {
// DependencyComponent is a declaration or imported somewhere in ItsModule.
return MockBuilder(TargetComponent, ItsModule);
});

it('should create', () => {
const fixture = MockRender(TargetComponent);
expect(fixture.point.componentInstance).toBeDefined();
});
});

Signal inputs​

Starting with Angular 17, inputs can be declared with input() and input.required(). MockComponent preserves them as signals instead of replacing them with ordinary properties. Angular updates their values through template bindings, including bindings that use input aliases.

@Component({
selector: 'child',
standalone: true,
template: '',
})
class ChildComponent {
public readonly name = input.required<string>({
alias: 'displayName',
});
}

@Component({
imports: [ChildComponent],
standalone: true,
template: '<child [displayName]="name" />',
})
class TargetComponent {
public readonly name = 'test';
}

beforeEach(() => MockBuilder(TargetComponent));

const fixture = MockRender(TargetComponent);
const child = ngMocks.findInstance(ChildComponent);

expect(child.name()).toEqual(fixture.point.componentInstance.name);

The template uses the input alias, while the mock instance is read through the original property name. For details about binding signal inputs on the component rendered by MockRender, see ComponentRef.setInput and signal inputs.

Mocks do not run the original component's constructor or field initializers. Angular stores transforms supplied to input() or input.required() on the initialized signal, without exposing them in reflected input metadata. A mock therefore receives the raw bound value without running that transform; for example, a bound string '2' remains a string. Decorator-based @Input({ transform: ... }) transforms are preserved through their reflected metadata. Use .keep(ChildComponent) when the test needs the real component's initialization or signal-input transform.

Standalone components​

Starting Angular 14, it provides support for standalone components. They are supported by ng-mocks. To mock a standalone component, you need to call MockComponent in imports:

TestBed.configureTestingModule({
imports: [
// for a single component
MockComponent(StandaloneComponent),

// for a set of components
...MockComponents(Standalone1Component, Standalone2Component),
],
declarations: [
// our component for testing
TargetComponent,
],
});

MockBuilder also supports standalone components and allows to mock their imports only for shallow rendering.

Advanced example​

An advanced example about mocking components. Please, pay attention to comments in the code.

https://github.com/help-me-mom/ng-mocks/blob/main/examples/MockComponent/test.spec.ts
describe('MockComponent', () => {
beforeEach(() => {
return MockBuilder(TargetComponent, ItsModule);
});

it('sends the correct value to the child input', () => {
const fixture = MockRender(TargetComponent);
const component = fixture.point.componentInstance;

// The same as
// fixture.debugElement.query(
// By.css('child')
// ).componentInstance
// but properly typed.
const mockComponent =
ngMocks.find<ChildComponent>('child').componentInstance;

// Let's pretend that DependencyComponent has 'someInput' as
// an input. MyComponent sets its value via
// `[someInput]="value"`. The input's value will be passed into
// the mock component so we can assert on it.
component.value = 'foo';
fixture.detectChanges();

// Thanks to ng-mocks, this is type safe.
expect(mockComponent.someInput).toEqual('foo');
});

it('does something on an emit of the child component', () => {
const fixture = MockRender(TargetComponent);
const component = fixture.point.componentInstance;

// The same as
// fixture.debugElement.query(
// By.directive(DependencyComponent)
// ).componentInstance
// but properly typed.
const mockComponent = ngMocks.findInstance(ChildComponent);

// Again, let's pretend DependencyComponent has an output
// called 'someOutput'. MyComponent listens on the output via
// `(someOutput)="trigger($event)"`.
// Let's install a spy and trigger the output.
ngMocks.stubMember(
component,
'trigger',
jasmine.createSpy(),
// in case of jest
// jest.fn(),
);
mockComponent.someOutput.emit({
payload: 'foo',
});

// Assert on the effect.
expect(component.trigger).toHaveBeenCalledWith({
payload: 'foo',
});
});

it('renders something inside of the child component', () => {
const localFixture = MockRender<ChildComponent>(`
<child>
<p>inside content</p>
</child>
`);

// We can access html directly asserting on some side effect.
const mockNgContent = localFixture.point.nativeElement.innerHTML;
expect(mockNgContent).toContain('<p>inside content</p>');
});

it('renders ContentChild of the child component', () => {
const fixture = MockRender<ChildComponent>(`
<child>
<ng-template #something>
<p>inside template</p>
</ng-template>
<p>inside content</p>
</child>
`);

// Injected ng-content rendered everything except templates.
const mockNgContent = fixture.point.nativeElement.innerHTML;
expect(mockNgContent).toContain('<p>inside content</p>');
expect(mockNgContent).not.toContain('<p>inside template</p>');

// Let's render the template. First, we need to assert that
// componentInstance is a MockedComponent<T> to access
// its `__render` method. `isMockOf` function helps here.
const mockComponent = fixture.point.componentInstance;
ngMocks.render(
mockComponent,
ngMocks.findTemplateRef('something'),
);

// The rendered template is wrapped by <div data-key="something">.
// We can use this selector to assert exactly its content.
const mockNgTemplate =
ngMocks.find(ChildComponent).nativeElement.innerHTML;
expect(mockNgTemplate).toContain('<p>inside template</p>');
});
});