How to test a standalone directive in Angular application
Here you can find how to test a standalone directive.
A standalone directive has the same feature set as a regular directive.
The only possible dependencies for a standalone directive are root services and tokens.
In a unit test, developers prefer to mock such dependencies.
MockBuilder
helps to configure TestBed
in such the way.
Let's image we have the next standalone directive:
@Directive({
selector: 'standalone',
standalone: true,
})
class StandaloneDirective implements OnInit {
@Input() public readonly name: string | null = null;
constructor(public readonly rootService: RootService) {}
ngOnInit(): void {
this.rootService.trigger(this.name);
}
}
As we can see, the standalone directive injects RootService
, and, ideally, the service should be mocked.
To configure TestBed
for that you need to use the next code:
beforeEach(() => {
return MockBuilder(StandaloneDirective);
});
Under the hood it marks StandaloneDirective
as kept
and sets shallow and export flags:
beforeEach(() => {
return MockBuilder().keep(StandaloneDirective, {
shallow: true,
export: true,
});
});
Now all dependencies of StandaloneDirective
are mocks,
and the properties, methods, injections of the directive are available for testing.
If you need to keep a dependency, simply call .keep
with it.
For example, if we wanted to keep RootService
then the code would look like:
beforeEach(() => {
return MockBuilder(StandaloneDirective).keep(RootService);
});
Live example
import {
Directive,
Injectable,
Input,
OnInit,
} from '@angular/core';
import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
// A root service we want to mock.
@Injectable({
providedIn: 'root',
})
class RootService {
trigger(name: string | null) {
// does something very cool
return name;
}
}
// A standalone directive we are going to test.
@Directive({
selector: 'standalone',
standalone: true,
})
class StandaloneDirective implements OnInit {
@Input() public readonly name: string | null = null;
constructor(public readonly rootService: RootService) {}
ngOnInit(): void {
this.rootService.trigger(this.name);
}
}
describe('TestStandaloneDirective', () => {
beforeEach(() => {
return MockBuilder(StandaloneDirective);
});
it('renders dependencies', () => {
// Rendering the directive.
MockRender(StandaloneDirective, {
name: 'test',
});
// Asserting that StandaloneDirective calls RootService.trigger.
const rootService = ngMocks.findInstance(RootService);
// it's possible because of autoSpy.
expect(rootService.trigger).toHaveBeenCalledWith('test');
});
});