How to unit test an Angular service?

Yesterday, we covered how to unit test an Angular pipe. Services are a bit more complex to test because they usually have dependencies that need to be injected. Let’s consider this example:

All the service does is rely on the HttpClient to make requests to a server. In a unit test, we don’t want to have a server up and running for the test to work. Instead, we want to focus on CartService only and replace all its dependencies with fake implementations called mocks.

Replacing a dependency with a mock requires some dependency injection config, which is why the setup of a service test is different. Here is what Angular CLI generates for us automatically:

We can see that the test relies on a TestBed object to create a testing module and then inject CartService in our test. TestBed is an Angular utility that enables custom dependency injection in unit tests. We are going to use TestBed to replace our real HttpClient with a fake one.

The simplest fake implementation we can create to satisfy our unit test is the following:

The above mock object has hardcoded methods that return the same Observables for each HTTP request. The next step is to configure our TestBed so our test uses that mock instead of the real HttpClient:

At this point, our test setup is ready. We can start writing actual test cases. We want to test getCartContents and make sure that it returns an empty array. The challenge at that point is that our method returns an Observable, which means we have to subscribe to it and then test the result:

The above test works! We got the Observable from our mock and checked the empty array. The test passes. That said, when working with Observables, it is recommended to use the async function as follows to make sure that the test waits long enough before completing:

Note that async has to be passed as a parameter to the test function (first line of code) and then called as the last line in our subscribe callback function.

There are other approaches to testing services that rely on the HttpClient. This one is the most straightforward, but if you’re interested, I have another tutorial that uses the official Angular mock API for the HttpClient.

Rollbar: Error tracking and reporting

Whenever we deploy a web application to production, one of the challenges is that our code will run on several different machines in different locations. When a user reports an error, we cannot access their browser console or stack trace unless the user is techy enough to share that information with us.

Of course, we can create a generic error handler and try to reproduce an issue in our environment, but this can be challenging as none of these options give us eyes on what is going on in that user’s specific browser.

This is where Rollbar shines. Rollbar is a library that can report Javascript errors to a server and create alerts/statistics/tracking of those errors over time:

In the above screenshot alone, there is a wealth of information that we would never get with console.log. For instance, the first error has happened 412 times on 72 different machines (IPs), and the last occurrence was three days ago.

Such a screen can help you identify if a new release solved an issue for all users or created a new one. Even better, Rollbar supports different environments so you can check production or pre-prod, or staging environments for those errors, as well as filter by level, activity, etc. :

Each error contains the browser info, locale, screen definition, stack trace, and more. Errors can also be assigned to developers for further investigation and marked as fixed or muted if the error is irrelevant.

All in all, once people start using Rollbar, it’s almost impossible to stop using it. You can see an Angular demo on Stackblitz here and read this quick set-up tutorial from the Rollbar documentation.

Lazy-loading with defer (new RFC)

We’ve talked about lazy loading and performance a few times in this newsletter. The Angular team is working on a new feature that will expand the scope and flexibility of lazy-loading in Angular using a new primitive with a syntax similar to the one introduced in the control flow RFC:

The above code would lazy-load the calendar component whenever that block is rendered in a template. And it gets better: We can also add conditions on when to render, how much time to wait before doing so, or even a combination of several predefined conditions/triggers:

The above code means that the calendar component would be loaded if the user interacts with the page or after 5 seconds.

We will be able to provide a placeholder and a loading template, too – those would be displayed before and during lazy-loading, respectively:

This new defer block is in the request for comments (RFC) phase, which means the Angular team is gathering feedback from all of us on this idea. There is no timeline yet as to when the feature will be available. Feel free to add your thoughts and contribute here. The more excitement is shown on Github, the higher the Angular team will prioritize the feature.

Updates from ng-conf 2023

I’m writing this message up in the air over the desertic landscapes of Nevada as I’m flying back to California from ng-conf 2023. It has been two days filled with lots of information, and I will unpack some of the major announcements in more detail in the following newsletters.

For now, I’ll focus on some rapid-fire news grouped by topic:

RxJs

  • RxJs 8 is coming out soon, and it will be 30% smaller than RxJs 7 and 60% smaller than RxJs 6!
  • Will have support for async / await syntax for Observables.
  • We will have some new syntactic sugar for chaining operators using a rx() function. Code such as obs$.pipe(map(...), filter(...)) will be writable as rx(obs$, map(...), filter(...)). Optional, yet good to know.

NgRx

  • Support for a Signal Store is coming soon

Endbridge

Other cool news

  • Bard, Google’s response to ChatGPT, is built with Angular!
  • Analog.js is a meta-framework for Angular apps. It supports server-side rendering, static pages, back-end APIs, and regular Angular front-end code all in one project, all in Javascript. Similar to Next.js for React. Analog is still a work in progress but looks promising.

New control flow RFC

One of the major announcements on day 1 of ng-conf was the control flow request for comments (RFC).

We’re all familiar with ngFor, ngIf, ngSwitch, and their syntaxes can get tricky at times.

Now what if ngIf was replaced with:

And what if the new syntax supported much more than ngIf, such as else if and even readable else cases:

The goal of the Angular team is to introduce syntaxes that are closer to regular Javascript and remove the need for these structural directives.

for loops would look like this and even support a empty template. All current ngFor local variables would be available automatically with no need for variable aliasing, too:

Finally, ngSwitch would become the following:

Angular CLI would perform the syntax updates throughout your Angular code, so there is no need to worry about rewriting those templates. You can find all the reasons why the Angular team decided on these syntaxes compared to other options in the RFC. You’re, of course, welcome to add your comments and suggestions to the list.

What’s new in Angular 16.1?

Angular 16.1 was released just in time for ng-conf 2023 (side note: If you’re in Salt Lake City, feel free to come to meet me and say hi – you’ll get a sticker and a $20 coupon for my video courses or certification exams).

There are three new features in Angular 16.1:

Transform option for @Input()

We can now have a function that transforms an input value to make it fit the needs of a component. Say, for instance, your input value is an object, and you want to extract one property out of it or return a boolean value if it passes a given check; then transform is what you need:

This simple example (code here) illustrates what can be done with the new option.

Support for Typescript 5.1

There isn’t a ton of new things in Typescript 5.1, mostly that now we can have setters and getters that use different types and have functions that return undefined.

Support for fetch() in HttpClient

This is in developer preview. You can enable it in the configuration of your HttpClient as follows:

I’m not sure there are any benefits of using it right now, but it might open the door to integrations with other HTTP providers built on top of fetch. Wait and see.

In any case, I’ll report my takeaways from ng-conf in the newsletter during the next few days. Exciting days ahead!

How to improve performance with pure pipes

Earlier in this newsletter, we saw that calling a method in a component template is an anti-pattern. The antidote to that anti-pattern is to use a pure pipe.

By default, all pipes we use in Angular are pure. Custom pipes are also pure by default. The only way to make a pipe impure is to add the config option pure: false to its decorator:

What is a pure pipe?

A pure pipe is one that Angular will execute only when there is a pure change to its input value. It is automatically optimized for performance since it is executed only when needed.

A pure change is either a change to a primitive input value (such as string, number, or boolean), or a changed object reference (such as Date, Array, or Object).

In other words, if we consider the following use case:

Here are some examples of pure and impure changes in variables:

With all that information, we are now equipped to call a formatting function in a template by using a pipe (said function would be called in the transform method of the pipe). We know that the function would run only when the input value changes (purely), which allows us to decide when we want that pipe to be executed again by making either a pure or an impure change to the input value.

Finally, we can double-check that our pipe is working as expected using the Angular profiler to make sure that the pipe doesn’t run more often than expected.

RxJs and Signals interoperability

Angular 16 introduced several features related to the brand-new Angular Signals, which include two functions enabling RxJs interoperability.

toObservable()

The name says it all. toObservable() takes a Signal and returns its data as an Observable:

This new Observable gets updated every time the underlying Signal value is updated. We can subscribe to it using the async pipe, for instance (demo code here):

toSignal()

toSignal() does the opposite of toObservable(). It turns an Observable into a Signal. Since Signals are different from Observables (a Signal always has a value right from the start – an Observable does not), the default behavior of toObservable() is to return a Signal that supports undefined as a default value:

This can be changed by providing an initial value as follows:

ngFor local variables

We use the ngFor directive so often that it’s easy to forget or even ignore some of its most powerful features.

For instance, it’s fairly common to access the index of an item in the array we’re working with, but there are five more local variables that can be used:

  • index: number: The index of the current item in the iterable.
  • count: number: The length of the iterable.
  • first: boolean: True when the item is the first item in the iterable.
  • last: boolean: True when the item is the last item in the iterable.
  • even: boolean: True when the item has an even index in the iterable.
  • odd: boolean: True when the item has an odd index in the iterable.

The syntax to use those local variables is as follows – and you can use as many as you want in a single ngFor directive like so:

Using a loading template with ngrxLet

A while back, I wrote about how ngrxLet is an improved version of the async pipe. I also covered how to use skeleton loaders with Angular.

Today, let’s look at how we can use these two tools to display a “loading” template while an observable is waiting for data.

As a reminder, here is how ngrxLet can be used to track different observable events:

In the above code snippet, we receive the values emitted by the number$ observable in a variable n. We would receive any error in a variable e. We would receive the completion status (true or false) in a variable c.

Here is how we can pass a custom loading template to ngrxLet using a template reference variable:

Of course, the loading template can be customized with anything you want, including a skeleton loader or an animated gif image. That feature is called a suspense template, and an observable is in a suspense state until it emits its first event (next, error, or complete as covered here).