Contents

How to Use Spectator to Test your Angular Components

How to Use Spectator to Test your Angular Components

A how-to guide using a sample app.

https://cdn-images-1.medium.com/max/800/1*xM9LIkTrN8ydWgRrz0x1_A.jpeg

Source: Unsplash

I’ve been usingSpectatorto test my Angular apps. It’s my go-to test tool in my current company and personal projects. Its features are enough to explain why.

https://cdn-images-1.medium.com/max/800/1*z-7xjss7h-1XH5ic8YHkGg.png Spectator’s features from github.com/ngneat/spectator.

In this post, I will walk you through how to use Spectator to test an Angular app with a component using a service. There is good documentation around how to use Spectator. However, this post will focus on using it in a sample Angular app. Hopefully, this will help you to quickly start using Spectator tests in your existing app. My post assumes that you havesomeexperience building Angular apps with RxJS.

The sample app

We will add Spectator tests to a modified version of a sample app from one of my previous blog postsHow to Automatically Unsubscribe Multiple Observables in Angular.

To quickly recap.

How it looks like

We have a web app with two GitHub search boxes, one for searching repositories and another to search for users.

https://cdn-images-1.medium.com/max/800/1*o8JjtdiFc7g8nXdPtHtXVw.png Screenshot of the sample web app by the author.

The search results are then displayed below the search boxes.

https://cdn-images-1.medium.com/max/800/1*yIqSQGqrs10oVP9rBj4BUQ.png Screenshot of the sample web app by the author.

How it works under the hood

Let’s do a quick recap of how our sample app works under the hood.

Our web app will call the GitHub Search API after we enter a text in any of the search boxes. To achieve this, we need to subscribe to our formControls valueChanges observable.

https://cdn-images-1.medium.com/max/800/1*K4VE7j7y26Ssx7dGOYWNZQ.png AppComponent and GithubService.

View Code on GitHub Gist

Source code example on GitHub by the author.

The linethis.searchSubject$.next(searchString)“emits” the signal to call the GitHub search API.

View Code on GitHub Gist

Source code example on GitHub by the author.

Our results will be rendered in our template.

<div *ngFor="let result of results$ | async"> 
  <div> 
    <a [href]="result.html_url" target="_blank">{{ result.name || result.login }}</a> 
  </div>
</div>

Installing spectator

Installation is straightforward. From their docs:

NPM

npm install @ngneat/spectator --save-dev

Yarn

yarn add @ngneat/spectator --dev

Setting up spectator

In our unit test fileapp.component.spec.ts, we will import our component and spectator dependencies.

Setup the component factory

Our tests will needSpectatorandcreateComponentFactoryfrom the Spectator package.

import { AppComponent } from './app.component';
import { Spectator, createComponentFactory } from '@ngneat/spectator';

Initialize our component factory usingcreateComponentFactory.

let spectator: Spectator<AppComponent>;
const createComponent = createComponentFactory(AppComponent);

Create our component factory before each test.

beforeEach(() => spectator = createComponent());

Import dependencies

OurAppComponentdepends onGithubServiceto call GitHub’s API.

import { GithbService } from './github.service';

DeclareGithubServiceas a provider when we create our spectator component.

const createComponent = createComponentFactory({ 
  component: AppComponent, 
  providers: [ 
    { 
      provide: GithubService, 
      useValue: {} 
    } 
  ], 
});

We will get a similar error message in the screenshot below if we don’t import the component’s dependencies like ourGithubServiceabove.

https://cdn-images-1.medium.com/max/800/1*24Ho8i15k-DPs15lGy-QkA.png Error message when there’s a missing dependency in the unit test file.

Verify that it works

We can verify that our basic setup is working by adding a test that will check if our component was created successfully.

it('should create', () => { 
  expect(spectator.component).toBeTruthy();
});

Our basic setup will look like the following. We can now run a test that checks if a spectator component is successfully created.

View Code on GitHub Gist

Source code example by the author.

Use init methods for unit testing

My sample app initializes all the observables inngOnInit. Let’s rewrite this first to make our app easier to test.

View Code on GitHub Gist

Source code example on GitHub by the author.

We will move ourformControlobservable subscriptionssearchUsersFormControlandsearchRepoesFormControlinto separate methodsinitSearchUsers()andinitSearchRepos(), respectively.

Below is for search users, it will be similar for search repositories.

View Code on GitHub Gist

this.initSearchUsers() will be called from ngOnInit().

Our methodsinitSearchUsers()andinitSearchRepos()will be called fromngOnInit().

ngOnInit(): void { 
  //... 
  this.initSearchUsers(); 
  this.initSearchRepos(); 
}

Add tests to our component

Our component is easier to test after we have introducedinitSearchUsers()andinitSearchRepos()to break down ourngOnInitdeclarations. The tests will be similar for both methods. I will add tests forinitSearchUsers()only as an example.

Assert emitted values from the observables

When testing observables, sometimes we will need to declare the assertions first within thesubscribecallback before we even call the method that we want to test.

To test thatinitSearchUsers()is working properly, two assertions must be satisfied:

  1. The search value that’s being typed as an input tosearchUsersFormControlshould trigger thesearchSubject$observable. If the search value is empty, then it shouldn’t trigger thesearchSubject$observable.
  2. Search results are emitted from theresults$observable.

We will subscribe tosearchSubject$to check if the emitted value is correct. Whatever the search value that’s being typed as an input tosearchUsersFormControlshould trigger thesearchSubject$observable:

spectator.component.searchSubject$.subscribe(res => { 
  expect(res).toBe(searchTerm); 
  done(); 
});

We will do the same thing with theresults$observable. Our component will return the search results based on the search type: repositories or users.

For example, if we have a mock that returns 100 results for user search.

spectator.component.results$.subscribe(res => { 
  expect(res.total_count).toBe(100); 
  done(); 
});

Then we should expect our user search’s total result to be 100.

Mock the service

After our assertions are set up in our observables, let’s mock our service’s search results. Mocking services using Spectator is straightforward.

Start by injecting the service.

const githubService = spectator.inject(GithubService);

Then, assign the mock return value.

githubService.searchUsers.andReturn(of({ 
  total_count: 100, 
}));

Call the methods

By having our assertions and mock in place, we are now ready to call the methods that we want to test. This is whereinitSearchUsersandinitSearchReposcome in handy.

Initialize oursearchUsersFormControlobservable.

spectator.component.initSearchUsers();

And finally set the value of oursearchUsersFormControl. As if a user is typing a search text into our search input.

spectator.component.searchUsersFormControl.setValue(searchTerm);

Here is our complete test file.

View Code on GitHub Gist

Try it yourself

The code is available on GitHub.

After cloning the repo, install the packages.

npm install

And run the tests.

ng test

You should get a similar output below.

https://cdn-images-1.medium.com/max/800/1*68mUXe9VI4wEOJuP2RZltQ.png

If you like this story, you might also enjoy my other stories about Angular:

More content atPlainEnglish.io. Sign up for ourfree weekly newsletter. Follow us onTwitterandLinkedIn. Join ourcommunity Discord.