How to unit test an Angular pipe?

Alain Chautard
Angular Training
Published in
4 min readJun 20, 2023

--

This tutorial is for people new to unit testing with Angular. We will start with unit tests for a pipe because pipes are the easiest way to get started: They have little to no dependencies, and testing multiple different inputs and expecting different outputs is intuitive.

The pipe we’re about to test is called CurrencyRenderer and works as follows:

{{8.00 | currencyRenderer}}  // displays $8
{{9.55 | currencyRenderer}} // displays $9.55

The pipe supports two optional parameters: currency and exchange rate.

{{8 | currencyRenderer: 'EUR' :1.20}}  // displays €6.67
{{8 | currencyRenderer: 'GBP' : 1.42}} // displays £5.63

In case you’re curious about how the pipe is written, here is its source code — it’s adding some behavior to the existing CurrencyPipe from the Angular framework:

import { Pipe, PipeTransform } from '@angular/core';
import {CurrencyPipe} from '@angular/common';

@Pipe({
name: 'currencyRenderer'
})
export class CurrencyRendererPipe implements PipeTransform {

transform(value: number,currency= 'USD',exchangeRate= 1): string | null {
return new CurrencyPipe('en-US')
.transform(value / exchangeRate, currency, 'symbol','1.0-2');
}
}
Angular Certification Exam

The default unit test

When we create a new Angular object (component, pipe, directive, service) with the Angular CLI, a default unit test is automatically generated in a .spec.ts file. In the case of our pipe, this default unit test looks like this:

import { CurrencyRendererPipe } from './currency-renderer.pipe';

describe('CurrencyRendererPipe', () => {

it('create an instance', () => {
const pipe = new CurrencyRendererPipe();
expect(pipe).toBeTruthy();
});
})

The test does almost nothing: It creates a pipe and then… checks that it exists!

A few important things to know so far:

  • The describe() function in a unit test is a way to group unit tests by theme / feature (here, all unit tests for CurrencyRendererPipe)
  • The it() function is an individual unit test
  • Both describe() and it() take a string as a first parameter. That string is meant to describe what the current test is all about. The second parameter is a function containing the actual test code.

Adding a first meaningful test

To add a new test, we add a new it() function and make that function test a different scenario. To get started, let’s check that our pipe formats US dollars properly:

describe('CurrencyRendererPipe', () => {

it('create an instance', () => {
const pipe = new CurrencyRendererPipe();
expect(pipe).toBeTruthy();
});

it('formats USD amounts properly', () => {
const pipe = new CurrencyRendererPipe();
expect(pipe.transform(8)).toBe("$8");
expect(pipe.transform(9.55)).toBe("$9.55");
})

})

We are setting expectations for each test using the expect() function. Usually, we expect a returned value to equal a given string or number. That said, there are plenty of other matcher functions, such as toBeGreaterThan() or toBeUndefined().

Testing different scenarios amounts to adding more it() functions with different inputs and outputs. Here is a test that would test another currency with an exchange rate:

 it('formats GBP amounts properly', () => {
const pipe = new CurrencyRendererPipe();
expect(pipe.transform(8, "GBP", 2)).toBe("£4");
})

Running tests and focusing on specific tests or groups of tests

Running tests with the Angular CLI is as easy as running the command:

ng test

Karma will then run all unit tests found in .spec.ts files and display the result in a browser as follows:

The ng test command is convenient, but it will run all unit tests, which can take some time if you have hundreds or thousands of them. If you want to focus on a subset of tests, you can prefix your describe() or it() functions with the following:

  • f for focus — meaning run those functions and ignore the other ones
  • x for exclude — meaning ignore those functions and run the other ones

Here is an example of running one describe() function and ignoring one of the tests in it:

// Focus on that describe() thanks to fdescribe()
fdescribe('CurrencyRendererPipe', () => {

it('create an instance', () => {
const pipe = new CurrencyRendererPipe();
expect(pipe).toBeTruthy();
});

it('formats USD amounts properly', () => {
const pipe = new CurrencyRendererPipe();
expect(pipe.transform(8)).toBe("$8");
expect(pipe.transform(9.55)).toBe("$9.55");
});

// Ignore that test thanks to xit()
xit('formats GBP amounts properly', () => {
const pipe = new CurrencyRendererPipe();
expect(pipe.transform(8, "GBP", 2)).toBe("£4");
})

});

That’s it for this first tutorial. Let me know in the comments if you have any questions or want more examples for testing services, components, etc.

The second part, “How to unit test an Angular service?” has been published as part of my free Daily Angular Newsletter.

I might start a series on those topics.

My name is Alain Chautard. I am a Google Developer Expert in Angular and a consultant and trainer at Angular Training where I help web development teams learn and become comfortable with Angular.

If you need any help with web development, feel free to get in touch!

If you enjoyed this article, please clap for it or share it. Your help is always appreciated. You can also subscribe to my articles, and subscribe to my Daily Angular Newsletter to receive useful daily tips.

--

--