loading...
Cover image for Simplify your Angular Component testing

Simplify your Angular Component testing

achimoraites profile image Achilles Moraites ・2 min read

Components are everywhere in our apps and testing them is part of our daily software development process.

But here are some good news: Testing should not be hard!

There are 3 types of tests for our Components:

  • Isolated (fastest)
  • Shallow (fast)
  • Deep (not so fast)

In this tutorial we will explore Isolated tests

Isolated Tests

Those are the less utilized tests in Angular testing yet the most fast and simple to use.

In those kinds of tests we treat the Component as a simple class.
Testing classes is easy, we can call their methods and verify the results.

Note that we just test the class functionality and NOT anything in the DOM.

Case 1 (simple) the component has no dependencies

Here is our component:

// explorer.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-explorer',
  templateUrl: './explorer.component.html',
  styleUrls: ['./explorer.component.scss']
})
export class ExplorerComponent implements OnInit {

  explorerName: string;
  location: string;
  constructor() { }

  ngOnInit() {
  }

  getLocation(location) {
    this.location = `Your location is ${location}`;
  }

}

Here we perform tests:

// explorer.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { ExplorerComponent } from './explorer.component';



describe('Isolated ExplorerComponent Tests', () => {
  let component: ExplorerComponent;
  beforeEach(() => {
    component = new  ExplorerComponent();
 });

  it('should set the correct location', () => {
   component.getLocation('Mars');
   expect(component.location).toContain('Mars');
 });

});

We can test it just like any other class!

Case 2 : the component has dependencies

here is our service:

// explorer.service.ts

import { Injectable } from '@angular/core';
import { of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ExplorerService {

  constructor() { }

  getExplorer() {
    return of('Josh the Lost');
  }

  getLocation() {
    return 'The dark side of the moon';
  }
}

our component:

// explorer.component.ts

import { Component, OnInit } from '@angular/core';
import { ExplorerService } from './services/explorer.service';

@Component({
  selector: 'app-explorer',
  templateUrl: './explorer.component.html',
  styleUrls: ['./explorer.component.scss']
})
export class ExplorerComponent implements OnInit {

  explorerName: string;
  location: string;
  constructor(
    private explorerService: ExplorerService
  ) { }

  ngOnInit() {
    this.explorerService.getExplorer().subscribe(data => {
      this.explorerName = data;
    });
  }

  getLocation(location) {
    this.location = `Your location is ${location}`;
  }

}

our tests:

// explorer.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { ExplorerComponent } from './explorer.component';
import { of } from 'rxjs';



describe('Isolated ExplorerComponent Tests', () => {
  let component: ExplorerComponent;
  // create a spyObject to simplify our mock service creation
  const mockExplorerService = jasmine.createSpyObj(['getExplorer']);
  // set the getExplorer method to return an Observable just like the real one
  mockExplorerService.getExplorer.and.returnValue(of('Dave the brave'));

  beforeEach(() => {
    component = new  ExplorerComponent(mockExplorerService);
 });

  it('should set the correct location', () => {
   component.getLocation('Mars');
   expect(component.location).toContain('Mars');
 });

  it('should set the correct explorer', () => {
  // trigger
  component.ngOnInit();

  expect(component.explorerName).toEqual('Dave the brave');
  // verify that getExplorer from the service has been called
  expect(mockExplorerService.getExplorer).toHaveBeenCalled();
});

});

Conclusion

Using Isolated tests we can test functionality with a simple way that is performant and easy to understand.

Note that this approach is great for testing just the component (class) code and is not meant to replace TestBed in any way.
We can just combine different kinds of tests to compliment our testing efforts :)

Happy testing !!!

Photo by Rodolfo Clix from Pexels

Discussion

pic
Editor guide