Skip to content

Commit a6f4c74

Browse files
committed
feat(table): add test harness
Adds a test harness for `MatTable`, as well as the related row and cell directives.
1 parent 63653bb commit a6f4c74

File tree

6 files changed

+152
-170
lines changed

6 files changed

+152
-170
lines changed

src/material/table/testing/cell-harness.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,33 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
9+
import {
10+
ComponentHarness,
11+
HarnessPredicate,
12+
ComponentHarnessConstructor,
13+
} from '@angular/cdk/testing';
1014
import {CellHarnessFilters} from './table-harness-filters';
1115

1216
/** Harness for interacting with a standard Angular Material table cell. */
1317
export class MatCellHarness extends ComponentHarness {
18+
/** The selector for the host element of a `MatCellHarness` instance. */
1419
static hostSelector = '.mat-cell';
1520

1621
/**
17-
* Gets a `HarnessPredicate` that can be used to search for a cell with specific attributes.
22+
* Gets a `HarnessPredicate` that can be used to search for a table cell with specific attributes.
23+
* @param options Options for narrowing the search
24+
* @return a `HarnessPredicate` configured with the given options.
1825
*/
1926
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatCellHarness> {
20-
return new HarnessPredicate(MatCellHarness, options)
21-
.addOption('text', options.text,
22-
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
27+
return getCellPredicate(MatCellHarness, options);
2328
}
2429

25-
/** Gets a promise for the cell's text. */
30+
/** Gets the cell's text. */
2631
async getText(): Promise<string> {
2732
return (await this.host()).text();
2833
}
2934

30-
/** Gets the name of the column. */
35+
/** Gets the name of the column that the cell belongs to. */
3136
async getColumnName(): Promise<string> {
3237
const host = await this.host();
3338
const classAttribute = await host.getAttribute('class');
@@ -47,28 +52,41 @@ export class MatCellHarness extends ComponentHarness {
4752

4853
/** Harness for interacting with a standard Angular Material table header cell. */
4954
export class MatHeaderCellHarness extends MatCellHarness {
55+
/** The selector for the host element of a `MatHeaderCellHarness` instance. */
5056
static hostSelector = '.mat-header-cell';
5157

5258
/**
53-
* Gets a `HarnessPredicate` that can be used to search for a header cell with specific attributes
59+
* Gets a `HarnessPredicate` that can be used to search for
60+
* a table header cell with specific attributes.
61+
* @param options Options for narrowing the search
62+
* @return a `HarnessPredicate` configured with the given options.
5463
*/
5564
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatHeaderCellHarness> {
56-
return new HarnessPredicate(MatHeaderCellHarness, options)
57-
.addOption('text', options.text,
58-
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
65+
return getCellPredicate(MatHeaderCellHarness, options);
5966
}
6067
}
6168

6269
/** Harness for interacting with a standard Angular Material table footer cell. */
6370
export class MatFooterCellHarness extends MatCellHarness {
71+
/** The selector for the host element of a `MatFooterCellHarness` instance. */
6472
static hostSelector = '.mat-footer-cell';
6573

6674
/**
67-
* Gets a `HarnessPredicate` that can be used to search for a footer cell with specific attributes
75+
* Gets a `HarnessPredicate` that can be used to search for
76+
* a table footer cell with specific attributes.
77+
* @param options Options for narrowing the search
78+
* @return a `HarnessPredicate` configured with the given options.
6879
*/
6980
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatFooterCellHarness> {
70-
return new HarnessPredicate(MatFooterCellHarness, options)
71-
.addOption('text', options.text,
72-
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
81+
return getCellPredicate(MatFooterCellHarness, options);
7382
}
7483
}
84+
85+
86+
function getCellPredicate<T extends MatCellHarness>(
87+
type: ComponentHarnessConstructor<T>,
88+
options: CellHarnessFilters): HarnessPredicate<T> {
89+
return new HarnessPredicate(type, options)
90+
.addOption('text', options.text,
91+
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
92+
}

src/material/table/testing/row-harness.ts

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,83 +10,87 @@ import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
1010
import {RowHarnessFilters, CellHarnessFilters} from './table-harness-filters';
1111
import {MatCellHarness, MatHeaderCellHarness, MatFooterCellHarness} from './cell-harness';
1212

13-
/** Data extracted from the cells in a table row. */
14-
export type MatRowHarnessData = {
15-
columnName: string;
16-
text: string;
17-
}[];
18-
1913
/** Harness for interacting with a standard Angular Material table row. */
2014
export class MatRowHarness extends ComponentHarness {
15+
/** The selector for the host element of a `MatRowHarness` instance. */
2116
static hostSelector = '.mat-row';
2217

2318
/**
24-
* Gets a `HarnessPredicate` that can be used to search for a row with specific attributes.
19+
* Gets a `HarnessPredicate` that can be used to search for a table row with specific attributes.
20+
* @param options Options for narrowing the search
21+
* @return a `HarnessPredicate` configured with the given options.
2522
*/
2623
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatRowHarness> {
2724
return new HarnessPredicate(MatRowHarness, options);
2825
}
2926

30-
/** Gets all cells of the table row. */
27+
/** Gets a list of `MatCellHarness` for all cells in the row. */
3128
async getCells(filter: CellHarnessFilters = {}): Promise<MatCellHarness[]> {
3229
return this.locatorForAll(MatCellHarness.with(filter))();
3330
}
3431

35-
/** Gets the data of the cells in the footer row. */
36-
async getData(filter: CellHarnessFilters = {}): Promise<MatRowHarnessData> {
37-
return getCellData(await this.getCells(filter));
32+
/** Gets the text of the cells in the row. */
33+
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
34+
return getCellTextByIndex(this, filter);
3835
}
3936
}
4037

4138
/** Harness for interacting with a standard Angular Material table header row. */
4239
export class MatHeaderRowHarness extends ComponentHarness {
40+
/** The selector for the host element of a `MatHeaderRowHarness` instance. */
4341
static hostSelector = '.mat-header-row';
4442

4543
/**
46-
* Gets a `HarnessPredicate` that can be used to search for a header row with specific attributes.
44+
* Gets a `HarnessPredicate` that can be used to search for
45+
* a table header row with specific attributes.
46+
* @param options Options for narrowing the search
47+
* @return a `HarnessPredicate` configured with the given options.
4748
*/
4849
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatHeaderRowHarness> {
4950
return new HarnessPredicate(MatHeaderRowHarness, options);
5051
}
5152

52-
/** Gets all cells of the table header row. */
53+
/** Gets a list of `MatHeaderCellHarness` for all cells in the row. */
5354
async getCells(filter: CellHarnessFilters = {}): Promise<MatHeaderCellHarness[]> {
5455
return this.locatorForAll(MatHeaderCellHarness.with(filter))();
5556
}
5657

57-
/** Gets the data of the cells in the footer row. */
58-
async getData(filter: CellHarnessFilters = {}): Promise<MatRowHarnessData> {
59-
return getCellData(await this.getCells(filter));
58+
/** Gets the text of the cells in the header row. */
59+
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
60+
return getCellTextByIndex(this, filter);
6061
}
6162
}
6263

6364

6465
/** Harness for interacting with a standard Angular Material table footer row. */
6566
export class MatFooterRowHarness extends ComponentHarness {
67+
/** The selector for the host element of a `MatFooterRowHarness` instance. */
6668
static hostSelector = '.mat-footer-row';
6769

6870
/**
69-
* Gets a `HarnessPredicate` that can be used to search for a footer row with specific attributes.
71+
* Gets a `HarnessPredicate` that can be used to search for
72+
* a table footer row cell with specific attributes.
73+
* @param options Options for narrowing the search
74+
* @return a `HarnessPredicate` configured with the given options.
7075
*/
7176
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatFooterRowHarness> {
7277
return new HarnessPredicate(MatFooterRowHarness, options);
7378
}
7479

75-
/** Gets all cells of the table footer row. */
80+
/** Gets a list of `MatFooterCellHarness` for all cells in the row. */
7681
async getCells(filter: CellHarnessFilters = {}): Promise<MatFooterCellHarness[]> {
7782
return this.locatorForAll(MatFooterCellHarness.with(filter))();
7883
}
7984

80-
/** Gets the data of the cells in the footer row. */
81-
async getData(filter: CellHarnessFilters = {}): Promise<MatRowHarnessData> {
82-
return getCellData(await this.getCells(filter));
85+
/** Gets the text of the cells in the footer row. */
86+
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
87+
return getCellTextByIndex(this, filter);
8388
}
8489
}
8590

86-
/** Extracts the data from the cells in a row. */
87-
async function getCellData(cells: MatCellHarness[]): Promise<MatRowHarnessData> {
88-
return Promise.all(cells.map(async cell => ({
89-
text: await cell.getText(),
90-
columnName: await cell.getColumnName()
91-
})));
91+
async function getCellTextByIndex(harness: {
92+
getCells: (filter?: CellHarnessFilters) => Promise<MatCellHarness[]>
93+
}, filter: CellHarnessFilters): Promise<string[]> {
94+
const cells = await harness.getCells(filter);
95+
return Promise.all(cells.map(cell => cell.getText()));
9296
}

src/material/table/testing/shared.spec.ts

Lines changed: 25 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -87,105 +87,55 @@ export function runHarnessTests(
8787
expect(cellTexts).toEqual(['Hydrogen', 'H']);
8888
});
8989

90-
it('should be able to get the table data organized by columns', async () => {
90+
it('should be able to get the table text organized by columns', async () => {
9191
const table = await loader.getHarness(tableHarness);
92-
const data = await table.getColumnsData();
92+
const text = await table.getCellTextByColumnName();
9393

94-
expect(data).toEqual({
94+
expect(text).toEqual({
9595
position: {
96-
headerText: 'No.',
97-
footerText: 'Number of the element',
96+
headerText: ['No.'],
97+
footerText: ['Number of the element'],
9898
text: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
9999
},
100100
name: {
101-
headerText: 'Name',
102-
footerText: 'Name of the element',
101+
headerText: ['Name'],
102+
footerText: ['Name of the element'],
103103
text: [
104104
'Hydrogen', 'Helium', 'Lithium', 'Beryllium', 'Boron',
105105
'Carbon', 'Nitrogen', 'Oxygen', 'Fluorine', 'Neon'
106106
]
107107
},
108108
weight: {
109-
headerText: 'Weight',
110-
footerText: 'Weight of the element',
109+
headerText: ['Weight'],
110+
footerText: ['Weight of the element'],
111111
text: [
112112
'1.0079', '4.0026', '6.941', '9.0122', '10.811',
113113
'12.0107', '14.0067', '15.9994', '18.9984', '20.1797'
114114
]
115115
},
116116
symbol: {
117-
headerText: 'Symbol',
118-
footerText: 'Symbol of the element',
117+
headerText: ['Symbol'],
118+
footerText: ['Symbol of the element'],
119119
text: ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne']
120120
}
121121
});
122122
});
123123

124-
it('should be able to get the table data organized by rows', async () => {
124+
it('should be able to get the table text organized by rows', async () => {
125125
const table = await loader.getHarness(tableHarness);
126-
const data = await table.getRowsData();
127-
128-
expect(data).toEqual([
129-
[
130-
{text: '1', columnName: 'position'},
131-
{text: 'Hydrogen', columnName: 'name'},
132-
{text: '1.0079', columnName: 'weight'},
133-
{text: 'H', columnName: 'symbol'}
134-
],
135-
[
136-
{text: '2', columnName: 'position'},
137-
{text: 'Helium', columnName: 'name'},
138-
{text: '4.0026', columnName: 'weight'},
139-
{text: 'He', columnName: 'symbol'}
140-
],
141-
[
142-
{text: '3', columnName: 'position'},
143-
{text: 'Lithium', columnName: 'name'},
144-
{text: '6.941', columnName: 'weight'},
145-
{text: 'Li', columnName: 'symbol'}
146-
],
147-
[
148-
{text: '4', columnName: 'position'},
149-
{text: 'Beryllium', columnName: 'name'},
150-
{text: '9.0122', columnName: 'weight'},
151-
{text: 'Be', columnName: 'symbol'}
152-
],
153-
[
154-
{text: '5', columnName: 'position'},
155-
{text: 'Boron', columnName: 'name'},
156-
{text: '10.811', columnName: 'weight'},
157-
{text: 'B', columnName: 'symbol'}
158-
],
159-
[
160-
{text: '6', columnName: 'position'},
161-
{text: 'Carbon', columnName: 'name'},
162-
{text: '12.0107', columnName: 'weight'},
163-
{text: 'C', columnName: 'symbol'}
164-
],
165-
[
166-
{text: '7', columnName: 'position'},
167-
{text: 'Nitrogen', columnName: 'name'},
168-
{text: '14.0067', columnName: 'weight'},
169-
{text: 'N', columnName: 'symbol'}
170-
],
171-
[
172-
{text: '8', columnName: 'position'},
173-
{text: 'Oxygen', columnName: 'name'},
174-
{text: '15.9994', columnName: 'weight'},
175-
{text: 'O', columnName: 'symbol'}
176-
],
177-
[
178-
{text: '9', columnName: 'position'},
179-
{text: 'Fluorine', columnName: 'name'},
180-
{text: '18.9984', columnName: 'weight'},
181-
{text: 'F', columnName: 'symbol'}
182-
],
183-
[
184-
{text: '10', columnName: 'position'},
185-
{text: 'Neon', columnName: 'name'},
186-
{text: '20.1797', columnName: 'weight'},
187-
{text: 'Ne', columnName: 'symbol'}
188-
]
126+
const text = await table.getCellTextByIndex();
127+
128+
expect(text).toEqual([
129+
['1', 'Hydrogen', '1.0079', 'H'],
130+
['2', 'Helium', '4.0026', 'He'],
131+
['3', 'Lithium', '6.941', 'Li'],
132+
['4', 'Beryllium', '9.0122', 'Be'],
133+
['5', 'Boron', '10.811', 'B'],
134+
['6', 'Carbon', '12.0107', 'C'],
135+
['7', 'Nitrogen', '14.0067', 'N'],
136+
['8', 'Oxygen', '15.9994', 'O'],
137+
['9', 'Fluorine', '18.9984', 'F'],
138+
['10', 'Neon', '20.1797', 'Ne']
189139
]);
190140
});
191141
}

src/material/table/testing/table-harness-filters.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77
*/
88
import {BaseHarnessFilters} from '@angular/cdk/testing';
99

10+
/** A set of criteria that can be used to filter a list of cell harness instances. */
1011
export interface CellHarnessFilters extends BaseHarnessFilters {
12+
/** Only find instances whose text matches the given value. */
1113
text?: string | RegExp;
1214
}
1315

16+
/** A set of criteria that can be used to filter a list of row harness instances. */
1417
export interface RowHarnessFilters extends BaseHarnessFilters {
1518
}
1619

20+
/** A set of criteria that can be used to filter a list of table harness instances. */
1721
export interface TableHarnessFilters extends BaseHarnessFilters {
1822
}

0 commit comments

Comments
 (0)