Skip to main content

How to test a host directive in Angular application

Let's imagine we have a component with a host directive which adds the name attribute.

The code of the directive:

@Directive({
selector: 'host',
standalone: true,
})
class HostDirective {
@HostBinding('attr.name') @Input() input?: string;
}

The code of the component:

@Component({
selector: 'target',
hostDirectives: [
{
directive: HostDirective,
inputs: ['input'],
},
],
template: 'target',
})
class TargetComponent {
// tons of logic we want to ignore
}

The component can be heavy, and, in an ideal test, the logic of the component should be ignored, so the focus would stay on the directive and how it behaves.

MockBuilder knows how to mock the component and how to keep one or some of its host directives as they are.

In order to do so, the host directive should be kept, and its component should be mocked:

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

Profit!

To access the directive in a test, ngMocks.findInstnace can be used.

it('keeps host directives', () => {
const fixture = MockRender(TargetComponent, { input: 'test' });

const directive = ngMocks.findInstance(HostDirective);
expect(directive.input).toEqual('test');
expect(ngMocks.formatHtml(fixture)).toContain(' name="test"');
});

Live example

https://github.com/help-me-mom/ng-mocks/blob/master/examples/TestHostDirective/test.spec.ts
import {
Component,
Directive,
HostBinding,
Input,
} from '@angular/core';

import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';

@Directive({
selector: 'host',
standalone: true,
})
class HostDirective {
@HostBinding('attr.name') @Input() input?: string;

public hostTestHostDirective() {}
}

@Component({
selector: 'target',
hostDirectives: [
{
directive: HostDirective,
inputs: ['input'],
},
],
template: 'target',
})
class TargetComponent {
public targetTestHostDirective() {}
}

describe('TestHostDirective', () => {
beforeEach(() => MockBuilder(HostDirective, TargetComponent));

it('keeps host directives', () => {
const fixture = MockRender(TargetComponent, { input: 'test' });

const directive = ngMocks.findInstance(HostDirective);
expect(directive.input).toEqual('test');
expect(ngMocks.formatHtml(fixture)).toContain(' name="test"');
});
});