We’ve all been there: You’re writing your code, chugging along, when suddenly the mere thought of the amount of unit tests you’ll have to write paralyzes you. Sure, you know they’re important — they help you and others understand your code, they check edge cases, they even force you to improve your code (because very often testable code = better code). So why do we balk at writing specs, delaying them till the last possible minute or skipping them outright?

Because, to be totally frank, testing sucks.

But why does it suck? Well, there are a couple of reasons: testing takes up valuable time, it requires its own skill set, and it requires a lot of boilerplate. Let’s examine this last point closer:

Just look at this example of an Angular test. It’s a very simple, very basic test. It just checks that the value you pass to the className input is indeed added to the classlist of a DOM element in the tested component’s template. And yet, look at the sheer volume of boilerplate code we need to add just to test this:

And this is not an isolated incident — pretty much anything you want to test using the Angular framework will end up being bogged down with a ton of boilerplate, and 99% of it will be identical. But there’s a solution.

Introducing Spectator

As the saying goes, “better to light one candle than curse the darkness”. And in this case, the candle lighter was Datorama’s very own Netanel Basal. He created Spectator, a library that runs as an additional layer on top of the Angular testing framework. We here at Datorama have been using it in a production environment for over a year, and making sure we, along with other contributors, add to it any additional features we require (in fact, only last month support for Jest mocking was added 😎).

Testing Components

By way of introduction, here is the first Spectator example — the exact same test, but with less than half the boilerplate:

createTestComponentFactory is a Spectator method which gets the component class you’re testing, and returns a factory function, letting you generate a Spectator component for that class.

What happened to the Testbed ? The Fixture ? The answer is Spectator handles all of those behind the scenes so that you don’t have to, making the remaining code much easier and more intuitive to read. You want to set an input value? Simply call the Spectator method setInput . You want to reach a DOM element in the component’s template? Simply call the Spectator method query , which works like the JavaScript querySelector method, receiving a css selector as its parameter.

Finally, we can see here the first example of the many custom matchers Spectator has to offer; toHaveClass checks that the class you give it exists in the element classlist.

Testing Advanced Components & Directives

Not all components are born equal. Some of the more complex ones require an equally complex testing set-up. This is where we can use Spectator’s createHostComponentFactory method. Similarly to createTestComponentFactory , this will generate a factory function. The difference is that here you give the method the template of a host component (which contains the component or directive you’re testing) as a parameter. This is particularly useful for components which contain ng-content, as this method allows you to determine what that content is without additional mocking.

Here’s an example of such a component being tested with spectator: datoAccordionGroupComponent has ng-content in its original template, which is replaced here with test elements. Those elements can then be utilised to further test the component’s functionality:

Triggering Events

Similarly, we can also test directives this way. In this example, we test the HighlightDirective , which we expect to change the background color of its host component when it’s hovered over. For that we’ll use another feature of Spectator — the ability to trigger event. In this case we can call dispatchMouseEvent for the element, triggering first the mouseover event, and then the mouseout event, and checking (using another custom matcher, toHaveStyle ), that the background color changed accordingly.

Testing Services

Let’s examine this AuthService ; It has a method called isLoggedIn which returns true, unless the DI DateService has an expired timestamp:

Before Spectator came along, what were our options, if we wanted to test this service? Well, we could mock a DateService in order to add it to the TestBed providers, which might take a while, depending on how many of its methods we’ll need in the spec, and their desired return values. Or we could inject the actual DateService , which might prove tricky, since it might have dependencies of its own we’ll have to deal with. Either option isn’t ideal as it would take additional effort. But Spectator offers a third, simpler option:

Once we add the service to the mocks array, Spectator will provide us with a mocked version of it, which will have all of the service’s original methods, now wrapped in spies. This enables us to get the injected service and treat all of its methods as spied upon, enabling us to determine their behavior in each individual test.

But Wait, There’s More!

Here are a few more things you can find in Spectator:

We’ve touched on a couple of the custom Jasmine matchers Spectator offers, but there are many more (toHaveClass, toBeDisabled, etc.). Basically, if there’s a common matching condition, chances are Spectator has the matcher for it (and if you don’t find a matcher you’d like to have, feel free to reach out to us 🙂).

Spectator offers built-in support for entry components, so that even dynamic components that go undeclared can be tested (see an example here).

As we’ve seen in the case of mouse events, Spectator can trigger input events — including keyboard events, and touch events.

Spectator offers built-in support for component-level providers.

It has methods providing out-of-the-box mocking for services, components, and directives.

It has additional support for testing services performing http calls, in the form of the createHTTPFactory method. You can read more about that here.

In Summary

With all this functionality, it’s no wonder that Spectator is a popular choice among programmers, with over 124K downloads so far, as well as making the Angular Top 10 Open Source of the Month list (4/18). So why not give it a try and see for yourself how it can simplify and streamline your tests? You can get it here.

Happy holidays and may all your specs be green!

🎅✅

Follow me on Medium to read more about Angular, Akita, JS!