Introduction to Spectator

Jason Warner
ngconf
Published in
5 min readJun 23, 2021

This is part 3 of a series. Part 1 and part 2 are about @ngrx/component-store. They go over the code used in this part. They are not necessary and the code can be found on GitHub for this part.

One of the important parts of software development is proving that our code is correct. A powerful tool to accomplish this task is automated testing. There are many forms of automated testing, but the most common is unit testing. Properly written unit tests can prove code correct and improve the quality of deployed software.

In Angular, there are many ways to test our applications. The two most common are to manually instantiate the subject under test or to use the TestBed. Manually instantiating the subject under test will almost always make tests that run faster. The reason for this is that test frameworks add overhead to your tests. There is a setup and teardown that needs to take place between each test. Test frameworks simplify a lot of the overhead and extra code needed to make tests run. There are tradeoffs and benefits to both approaches.

If you choose to use a test framework, I find Spectator to be superior to TestBed. To be fair, Spectator actually wraps TestBed and fixes some settings to make TestBed tests run faster. There are some other benefits too. From their GitHub page:

Spectator helps you get rid of all the boilerplate grunt work, leaving you with readable, sleek and streamlined unit tests.

Getting rid of boilerplate is a big part of the appeal of Spectator. Spectator has built-in mocking and makes writing HTTP tests easier. The downside to Spectator is that it is another library to add to your project and it requires you to learn a new testing tool. Another issue that I have encountered with Spectator is that the documentation is lacking in some areas. You will need to experiment to get tests working. Despite these issues, I have found Spectator to be an amazing tool and worth adding to my projects.

Adding Spectator to Your Project

You can use yarn or npm to add Spectator to your project.

yarn add @ngneat/spectator --dev

or

npm install @ngneat/spectator --save-dev

Converting Our First Component To Spectator

Now that we’ve added Spectator to our project, let’s convert a component test from TestBed to Spectator tests. We will convert the EditDisplayComponent . This component is very simple and the tests are really basic. This will allow us to focus on the changes needed to convert to Spectator. Here is the file using the Angular TestBed:

As you can see, this is a very simple test file. One thing I would like to point out is the use of the ng-mocks library to mock dependent components. I highly recommend this library for mocking dependencies. It allows you to not have to use CUSTOM_ELEMENTS_SCHEMA or import components into your tests. This allows you to isolate this component to be a true unit test.

Now let's look at what this file looks like when converted to Spectator.

The first thing to notice is on line 7. Here we use the createComponentFactory() method to set up the component to be tested. It matches the object used in TestBed.configureTestingModule() fairly closely. There are some special properties that can be used in advanced scenarios, but we won’t explore those in this introduction.

The createComponent() method created by the factory returns a Spectator<EditDisplayComponent> this object has properties to access the fixture, component , element and other useful objects. Notice on line 31 that createComponent() takes a configuration object. In this example, we use it to set the props on the component, but you can override providers in this method or turn of automatic detectChanges . There is a lot of power in this simple method.

Spectator also has some very powerful HTML matchers. You can see one used on line 33. I find that HTML matchers are often the most brittle tests, but for situations like this component, they can be very useful.

Testing HTTP Services

Spectator has some really nice helpers for testing services that make HTTP calls. Let’s look at the tests for the StarWarsApiService to see some of the ways we can HTTP services.

In this example, we use createHttpFactory() from Spectator to create the createService() factory. This takes care of setting up all the HTTP testing boilerplate. The returned type from this function is a SpectatorHttp<StarWarsApiService> . This gives us access to a lot of useful functions for testing our HTTP service.

Our first test on line 36 just tests to make sure that the proper URL is called by our service. We do this on line 39 by using the expectOne() method and passing the expected URL and HTTP request type. This doesn’t do anything until we call flush() on line 41. Notice that we can return the data that is expect in the flush() method. Notice on line 37 that we can get access to the service under test on the spectator object.

Our second test on line 44 makes sure the we add the index as our psuedo-id. We set up the expectations and then we call flush() with the test data on line 53. This call to flush() causes our tests to run and we can test that we get the expected results.

The final test on line 58 is a common test of a function that returns an observable. This test shows how services can be tested using Spectator.

We have explored some simple test cases using Spectator. I use Spectator instead of TestBed in my tests now because of the many benefits that Spectator provides. In the next part, we will look into how Spectator can make testing component store and components that rely on a component store much easier.

Now that you’ve read this article and learned a thing or two (or ten!), let’s kick things up another notch!
Take your skills to a whole new level by joining us in person for the world’s first MAJOR Angular conference in over 2 years! Not only will You be hearing from some of the industry’s foremost experts in Angular (including the Angular team themselves!), but you’ll also get access to:

  • Expert panels and Q&A sessions with the speakers
  • A friendly Hallway Track where you can network with 1,500 of your fellow Angular developers, sponsors, and speakers alike.
  • Hands-on workshops
  • Games, prizes, live entertainment, and be able to engage with them and a party you’ll never forget

We’ll see you there this August 29th-Sept 2nd, 2022. Online-only tickets are available as well.
https://2022.ng-conf.org/

--

--

Jason Warner
ngconf
Writer for

I enjoy everything related to code and being a dev. However, my only skills are showing up and being lucky and I'm not sure if luck is a talent.