Unit Testing with Material List Test Harness (MatListHarness)
I recently stumbled across this guide on the Material testing harness and it changed my life (work life anyway). This is really a powerful feature for unit testing material components and I took to it immediately. I wish I had found it sooner.
The problem is that the guide lacked a little in specifics, so I thought I’d write a tutorial about how to use the testing harness to test a Material List (mat-list) component.
I had a pretty basic list to test. It will contain the list of drink sizes available for a restaurants online ordering system.
<mat-list
class="normal-list"
id="listMasterItems">
<mat-list-item *ngFor="let masterItem of settingsService.drinkSizes">
{{ masterItem }}
</mat-list-item>
</mat-list>
Unit Test Goals
My goals for unit testing this is for the list at the end to contain everything that is in the drinkSizes array, which is being mocked. Here is the test I ended up writing.
We need to start with a little setup…
let loader: HarnessLoader;
beforeEach(() => {
fixture = TestBed.createComponent(DrinkSizesComponent);
loader = TestbedHarnessEnvironment.loader(fixture);
});
Now to the actual testing. First, let’s get the harness for our list. Note the async and await.
it('should create', async() => {
const sizeList: MatListHarness = await loader.getHarness(MatListHarness);
Now I want to retrieve the items from the list.
const sizeItems: MatListItemHarness[] = await sizeList.getItems();
and verify that it is the right size. (DRINK_SIZE_LIST is an array constant defined as part of my mocking library.)
expect(sizeItems.length).toEqual(DRINK_SIZE_LIST.length);
Now that we’ve verified that there’s the right number of drink sizes, let’s verify that some of the ones supposed to be there are there. Since most of the methods in the test harness return promises, I had to do a little massaging to get at the values I needed. This will extract each of the text entries and store them in an array.
const foundSizes: string[] = [];
for (let ix = 0; ix < sizeItems.length; ++ix) {
const size: string = await sizeItems[ix].getText();
foundSizes.push(size);
}
And now all that’s left is to make sure that the array contains the entries I think should be there.
expect(foundSizes.indexOf(DRINK_SIZE2)).toBeGreaterThanOrEqual(0);
expect(foundSizes.indexOf(DRINK_SIZE20)).toBeGreaterThanOrEqual(0);
I test in this way so that my test doesn’t fail if I add more drink sizes to my mock later on.
So that’s it. Here is the complete test.
it('should create', async() => {
const sizeList: MatListHarness = await loader.getHarness(MatListHarness);
const sizeItems: MatListItemHarness[] = await sizeList.getItems();
expect(sizeItems.length).toEqual(DRINK_SIZE_LIST.length);
const foundSizes: string[] = [];
for (let ix = 0; ix < sizeItems.length; ++ix) {
const size: string = await sizeItems[ix].getText();
foundSizes.push(size);
}
expect(foundSizes.indexOf(DRINK_SIZE2)).toBeGreaterThanOrEqual(0);
expect(foundSizes.indexOf(DRINK_SIZE20)).toBeGreaterThanOrEqual(0);
});
Unit Testing with Material List Test Harness (MatListHarness)
And that’s it. So we used a MatListHarness to unit test our Material List, verify the number of items in it, and then verify the contents of the list.