No more 💩 angular unit test / #1 Component template

Alexandre - Nov 14 '19 - - Dev Community

⚠️ Use ng-mocks in your unit tests
More details after about this lib. Just keep in mind that it's awesome.

Standard first

I love use standard. Angular makes the choice to use Karma/Jasmine, so I continue to use it.

😇 YES, Jest is also a great challenger and a powerful tool to write and execute your unit tests

Testing your components

There are two things to test with your components.

  • Template (.html)
  • Logic (.ts).

Testing template

What can be tested and needed to be tested ?

  • All Angular directive *ngIf, *ngFor, ...
  • All inputs @Input()
  • All outputs @Output()

🤔 Why we need to test *ngIf for example ?

Image in your commit #1 you add *ngIf in your template without tests. Someone commit the #2 and erase by accident the conditional directive. No test cover this regression.

🔥 Use MockRender from ng-mocks to create your component fixture.

import { TestBed } from '@angular/core/testing';
import { YourComponent } from './your-component.component.ts';
import { MockRender } from 'ng-mocks';

describe('YourComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [YourComponent]
    });
  });

  it('should create', () => {
    const fixture = MockRender(`<your-component></your-component>`);
    expect(fixture.componentInstance).toBeTruthy();
  });

  it('should display description', () => {
    const fixture = MockRender(
      `<your-component [description]="description"></your-component>`,
      { description: 'hello world' }
    );
    fixture.detectChanges();

    const descriptionEl = fixture.debugElement.query(By.css('.description');
    expect(descriptionEl.nativeElement.innerHTML).toEqual('hello world');
  });
});
Enter fullscreen mode Exit fullscreen mode

🚀 To improve performance and to scope your unit test, use MockComponent from ng-mocks

With this method, child components become black box.

import { TestBed } from '@angular/core/testing';
import { YourComponent } from './your-component.component.ts';
import { YourChildComponent } from './your-child-component.component.ts';
import { MockRender, MockComponent } from 'ng-mocks';

describe('YourComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [YourComponent, MockComponent(YourChildComponent)]
    });
  });

  it('should trigger data', () => {
    let receivedData = null;
    const fixture = MockRender(
        `<my-component (getData)="getData($event)></my-component>`,
        { getData: data => receivedData = data; }
    );
    fixture.detectChanges();

    const triggerDataEl = fixture.debugElement.query(By.css('.trigger-data'));
    const childComponent: YourChildComponent = triggerDataEl.componentInstance;
    childComponent.triggerData.emit('hello world');
    fixture.detectChanges();

    expect(receivedData).toEqual('hello world');
  });
});
Enter fullscreen mode Exit fullscreen mode

In this example, we trigger the output from the child component. And get an output from our component.

Testing logic

In the next post.

I hope this article can helps you in your development. 🐼

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .