Angular testing
Tests in general
- we create testing module
- used to mock services/components
- mock at the border of the system - http requests, window etc
- we use Spectator framework
Testing module
- depends what you test
createTestComponentFactory({
component: DocumentsCheckComponent,
declarations: [DocumentIconComponent],
providers: [CalculatorService],
mocks: [SessionService]
imports: [MaterialModule]
});
const spectator = createService({
service: AuthService,
providers: [CalculatorService],
mocks: [DateService]
});
service:
component:
Services
Testing services
- https://netbasal.gitbook.io/spectator/services
- spectator.get<Service>(Service)
- prepare state
- call tested method
describe("AuthService", () => {
const spectator = createService({
service: AuthService,
mocks: [DateService]
});
it("should not be logged in", () => {
const dateService = spectator.get<DateService>(DateService);
dateService.isExpired.and.returnValue(true);
expect(spectator.service.isLoggedIn()).toBeFalsy();
});
});
Http services
- called data services in spectator
describe('HttpClient testing', () => {
let http = createHTTPFactory<TodosDataService>(TodosDataService);
it('can test HttpClient.post', () => {
let { dataService, controller, expectOne } = http();
dataService.saveToDo({id: 1}).subscribe();
const req = expectOne('todos', HTTPMethod.POST);
expect(req.request.body['id']).toEqual(1);
});
});
Pipes
Testing pipes
- just a class with method
describe('HumanizeAccountPipe', () => {
let pipe: HumanizeAccountPipe;
beforeEach(() => pipe = new HumanizeAccountPipe());
it('converts account no to human readable form', () => {
expect(
pipe.transform({
accountNo: '0000000000000123',
accountBank: '0100'
})
).toBe('123/0100');
});
});
Component testing
- whitebox testing
- access to the component class
- blackbox testing
- with wrapping host component
- like in ember
Whitebox testing
- https://netbasal.gitbook.io/spectator/components
- access to component instance
let spectator: Spectator<ButtonComponent>;
const createComponent = createTestComponentFactory(ButtonComponent);
beforeEach(() => spectator = createComponent());
it('should have a success class by default', () => {
expect(spectator.query('button')).toHaveClass('success');
});
it('should emit the $event on click', () => {
spectator = createComponent({}, false);
let output;
spectator.output<{ type: string }>('click').subscribe(result => output = result);
spectator.component.onClick({ type: 'click' });
spectator.detectChanges();
expect(output).toEqual({ type: 'click' });
});
Blackbox testing
- https://netbasal.gitbook.io/spectator/components/with-custom-host
- access only to inputs/services
- has to use DOM for interactions
@Component({ selector: 'custom-host', template: '' })
class CustomHostComponent {
title = 'Custom HostComponent';
}
describe('With Custom Host Component', function () {
let host: SpectatorWithHost<ZippyComponent, CustomHostComponent>;
const createHost = createHostComponentFactory({
component: ZippyComponent,
host: CustomHostComponent
});
it('should display the host component title', () => {
host = createHost(`<zippy [title]="title"></zippy>`);
expect(host.query('.zippy__title')).toHaveText('Custom HostComponent');
});
});
detectChanges
- used to initialise component
- used when property changes to update DOM​
// whitebox
spectator.detectChanges();
// blackbox
host.detectChanges();
Initial change detection
- triggers ngOnInit hook
- by default triggered by Spectator automatically
- can be disabled
// whitebox
spectator = createComponent({}, false);
// blackbox
host = createHost(
'<app-applications-header></app-applications-header>',
false
);
Testing observables
= also @Output()
Subscribe first
- disable initial change detection
- subscribe
- do stuff
let emittedValue!: CommonCheck;
host
.output<CommonCheck>('checked')
.subscribe(value => (emittedValue = value));
host.detectChanges();
expect(emittedValue).toEqual(...);
Useful tips
mockComponents
- when tested component has complicated child components
import { MockComponent } from 'ng-mocks';
describe('DocumentsCheckComponent', () => {
const createComponent = createTestComponentFactory({
component: DocumentsCheckComponent,
declarations: [MockComponent(DocumentIconComponent)],
imports: [MaterialModule]
});
)};
Feature flags
const createComponent = createTestComponentFactory({
component: StepsComponent,
declarations: [...],
imports: [...],
mocks: [...],
providers: [
mockFeatureFlagsService({
'admin-unified-dashboard-blocking-buttons': true,
'admin-unified-dashboard-phase-3': true
})
]
});
- ​provide mockFeatureFlagsService
"Type checking requires all properties"
- PROBLEM: you cannot assign a property because type is complex and you would need to come up with all properties
- SOLUTION: create object with properties you need and cast to any
component.loan = {
id: 5
} as any;
Angular testing
By Martin Nuc
Angular testing
- 455