How to test usage of @angular/material (Angular Material) in Angular applications
Angular Material
is a UI library with a lot of UI components.
Below you can find information how to test a component which uses Angular Material
.
The next example will be based on usage of mat-table
.
Let's assume, that a component uses mat-table
like that:
<table mat-table [dataSource]="dataSource">
<!-- Position Column -->
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef>No.</th>
<td mat-cell *matCellDef="let element">
{{ element.position }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table>
A test of such a template requires to:
- mock
mat-table
- assert passed inputs
- assert templates for Position column
- assert the rest of templates
Information about testing ng-template
and its TemplateRef
is taken from the ngMocks.render.
Spec file
With MockBuilder
, our spec file needs a single line to provide mocks:
beforeEach(() => MockBuilder(TargetComponent, TargetModule));
Where TargetComponent
is a component which uses mat-table
,
and TargetModule
is its module.
Testing inputs of mat-table
In this test we need to verify that mat-table
data from out component's instance.
The tools from ng-mocks
we need:
MockRender
: to renderTargetComponent
and get its instancengMocks.reveal
: to find a debug element ofMatTable
ngMocks.input
: to get an input's value
it('binds inputs', () => {
// Rendering TargetComponent and accessing its instance.
const targetComponent =
MockRender(TargetComponent).point.componentInstance;
// Looking for a debug element of `MatTable`.
const tableEl = ngMocks.reveal(['mat-table']);
// Asserting bound properties.
expect(ngMocks.input(tableEl, 'dataSource')).toBe(
targetComponent.dataSource,
);
});
Testing matColumnDef and matCellDef templates
To test the ng-template
,
we should find TemplateRef
which belongs to matColumnDef
and matCellDef
attributes,
render them, and assert the rendered html.
The tools from ng-mocks
we need:
MockRender
: to renderTargetComponent
and get its instancengMocks.reveal
: to find debug elements ofmat-table
andng-container
ngMocks.formatHtml
: to get html of ang-container
ngMocks.render
: to render the templates
it('provides correct template for matColumnDef="position"', () => {
MockRender(TargetComponent);
// looking for the table and container
const tableEl = ngMocks.reveal(['mat-table']);
const containerEl = ngMocks.reveal(['matColumnDef', 'position']);
// checking that there are no artifacts around
expect(ngMocks.formatHtml(containerEl)).toEqual('');
// checking header
const headerEl = ngMocks.reveal(containerEl, [
'matHeaderCellDef',
]);
ngMocks.render(tableEl.componentInstance, headerEl);
expect(ngMocks.formatHtml(headerEl)).toEqual(
'<th mat-header-cell="">No.</th>',
);
// checking cell
const cellEl = ngMocks.reveal(containerEl, ['matCellDef']);
ngMocks.render(tableEl.componentInstance, cellEl, {
position: 'testPosition',
});
expect(ngMocks.formatHtml(cellEl)).toEqual(
'<td mat-cell=""> testPosition </td>',
);
});
Testing mat-header-row template
The approach to test mat-header-row
is the same as above.
We need to find which directive belongs to mat-header-row
,
it is MatHeaderRowDef
.
The tools from ng-mocks
we need:
ngMocks.findInstance
: to find the instance ofMatHeaderRowDef
it('provides correct template for mat-header-row', () => {
const targetComponent =
MockRender(TargetComponent).point.componentInstance;
const tableEl = ngMocks.reveal(['mat-table']);
// checking that there are no artifacts around
expect(ngMocks.formatHtml(tableEl)).toEqual('');
const header = ngMocks.findInstance(tableEl, MatHeaderRowDef);
expect(header.columns).toBe(targetComponent.displayedColumns);
ngMocks.render(tableEl.componentInstance, header);
expect(ngMocks.formatHtml(tableEl)).toContain(
'<tr mat-header-row=""></tr>',
);
});
Testing mat-row template
The approach to test mat-row
is the same as above.
We need to find which directive belongs to mat-row
,
it is MatRowDef
.
it('provides correct template for mat-row', () => {
const targetComponent =
MockRender(TargetComponent).point.componentInstance;
const tableEl = ngMocks.reveal(['mat-table']);
// checking that there are no artifacts around
expect(ngMocks.formatHtml(tableEl)).toEqual('');
const row = ngMocks.findInstance(tableEl, MatRowDef);
expect(row.columns).toBe(targetComponent.displayedColumns);
ngMocks.render(tableEl.componentInstance, row);
expect(ngMocks.formatHtml(tableEl)).toContain(
'<tr mat-row=""></tr>',
);
});