Skip to main content

How to mock directives in Angular tests

A mock directive in Angular tests can be created by MockDirective function. The mock directive has the same interface as its original directive, but all its methods are dummies.

In order to create a mock directive, pass the original directive into MockDirective function.

TestBed.configureTestingModule({  declarations: [    // for a single directive    MockDirective(Directive),
    // for a set of directives    ...MockDirectives(Directive1, Directive2),  ],});

A mock directive has:

  • support for attribute and structural directives
  • the same selector
  • the same Inputs and Outputs with alias support
  • support for @ContentChild and @ContentChildren
  • support for ControlValueAccessor, Validator and AsyncValidator
  • supports exportAs
tip

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

Simple example#

Let's assume that an Angular application has TargetComponent that depends on DependencyDirective directive, and we would like to use its mock object in order to facilitate unit tests.

Usually a test looks like:

describe('Test', () => {  let component: TargetComponent;  let fixture: ComponentFixture<TargetComponent>;
  beforeEach(() => {    TestBed.configureTestingModule({      declarations: [        // our component for testing        TargetComponent,
        // the annoying dependency        DependencyDirective,      ],    });
    fixture = TestBed.createComponent(TargetComponent);    component = fixture.componentInstance;  });});

To turn a directive into a mock directive, simply pass its original class into MockDirective:

TestBed.configureTestingModule({  declarations: [    TargetComponent,
    // profit    MockDirective(DependencyDirective),  ],});

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

describe('Test', () => {  beforeEach(() => {    return MockBuilder(TargetComponent).mock(DependencyDirective);  });
  it('should create', () => {    const fixture = MockRender(TargetComponent);    expect(fixture.point.componentInstance).toBeDefined();  });});

Advanced example with attribute directives#

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

describe('MockDirective:Attribute', () => {  beforeEach(() => {    return MockBuilder(TestedComponent).mock(DependencyDirective);  });
  it('sends the correct value to the input', () => {    const fixture = MockRender(TestedComponent);    const component = fixture.point.componentInstance;
    // The same as    // fixture.debugElement.query(    //   By.css('span')    // ).injector.get(DependencyDirective)    // but easier and more precise.    const mockDirective = ngMocks.get(      ngMocks.find('span'),      DependencyDirective,    );
    // Let's pretend DependencyDirective has 'someInput'    // as an input. TestedComponent sets its value via    // `[someInput]="value"`. The input's value will be passed into    // the mock directive so we can assert on it.    component.value = 'foo';    fixture.detectChanges();
    // Thanks to ng-mocks, this is type safe.    expect(mockDirective.someInput).toEqual('foo');  });
  it('does something on an emit of the child directive', () => {    const fixture = MockRender(TestedComponent);    const component = fixture.point.componentInstance;
    // The same as    // fixture.debugElement.query(    //   By.css('span')    // ).injector.get(DependencyDirective)    // but easier and more precise.    const mockDirective = ngMocks.get(      ngMocks.find('span'),      DependencyDirective,    );
    // Again, let's pretend DependencyDirective has an output called    // 'someOutput'. TestedComponent listens on the output via    // `(someOutput)="trigger($event)"`.    // Let's install a spy and trigger the output.    spyOn(component, 'trigger');    mockDirective.someOutput.emit();
    // Assert on the effect.    expect(component.trigger).toHaveBeenCalled();  });});

Advanced example with structural directives#

An advanced example of mocking structural directives in Angular tests. Please, pay attention to comments in the code.

important

It is important to render a structural directive with the right context first, if we want to assert on its nested elements.

describe('MockDirective:Structural', () => {  // IMPORTANT: by default structural directives are not rendered.  // Because they might require a context which should be provided.  // Usually a developer knows the context and can render it  // manually with proper setup.  beforeEach(() => {    return MockBuilder(TestedComponent).mock(DependencyDirective, {      // render: true, // <-- a flag to render the directive by default    });  });
  it('renders content of the child structural directive', () => {    const fixture = MockRender(TestedComponent);
    // Let's assert that nothing has been rendered inside of    // the structural directive by default.    expect(fixture.nativeElement.innerHTML).not.toContain('>content<');
    // And let's render it manually now.    const mockDirective = ngMocks.findInstance(DependencyDirective);    ngMocks.render(mockDirective, mockDirective);
    // The content of the structural directive should be rendered.    expect(fixture.nativeElement.innerHTML).toContain('>content<');  });});