Skip to content

Commit 8809084

Browse files
authored
feat(material-experimental/mdc-table): add test harnesses (#20319)
Sets up test harnesses for the MDC-based table module.
1 parent 3854b66 commit 8809084

File tree

10 files changed

+422
-1
lines changed

10 files changed

+422
-1
lines changed

src/material-experimental/config.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ entryPoints = [
3535
"mdc-slider/testing",
3636
"mdc-snack-bar",
3737
"mdc-table",
38+
"mdc-table/testing",
3839
"mdc-tabs",
3940
"mdc-tabs/testing",
4041
"menubar",

src/material-experimental/mdc-card/testing/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ ng_test_library(
2626
["**/*.spec.ts"],
2727
exclude = [
2828
"**/*.e2e.spec.ts",
29-
"shared.spec.ts",
3029
],
3130
),
3231
deps = [
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ts_library(
6+
name = "testing",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
module_name = "@angular/material-experimental/mdc-table/testing",
12+
deps = [
13+
"//src/cdk/testing",
14+
],
15+
)
16+
17+
filegroup(
18+
name = "source-files",
19+
srcs = glob(["**/*.ts"]),
20+
)
21+
22+
ng_test_library(
23+
name = "unit_tests_lib",
24+
srcs = glob(["**/*.spec.ts"]),
25+
deps = [
26+
":testing",
27+
"//src/material-experimental/mdc-table",
28+
"//src/material/table/testing:harness_tests_lib",
29+
],
30+
)
31+
32+
ng_web_test_suite(
33+
name = "unit_tests",
34+
deps = [":unit_tests_lib"],
35+
)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {
10+
ComponentHarness,
11+
HarnessPredicate,
12+
ComponentHarnessConstructor,
13+
} from '@angular/cdk/testing';
14+
import {CellHarnessFilters} from './table-harness-filters';
15+
16+
/** Harness for interacting with an MDC-based Angular Material table cell. */
17+
export class MatCellHarness extends ComponentHarness {
18+
/** The selector for the host element of a `MatCellHarness` instance. */
19+
static hostSelector = '.mat-mdc-cell';
20+
21+
/**
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.
25+
*/
26+
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatCellHarness> {
27+
return getCellPredicate(MatCellHarness, options);
28+
}
29+
30+
/** Gets the cell's text. */
31+
async getText(): Promise<string> {
32+
return (await this.host()).text();
33+
}
34+
35+
/** Gets the name of the column that the cell belongs to. */
36+
async getColumnName(): Promise<string> {
37+
const host = await this.host();
38+
const classAttribute = await host.getAttribute('class');
39+
40+
if (classAttribute) {
41+
const prefix = 'mat-column-';
42+
const name = classAttribute.split(' ').map(c => c.trim()).find(c => c.startsWith(prefix));
43+
44+
if (name) {
45+
return name.split(prefix)[1];
46+
}
47+
}
48+
49+
throw Error('Could not determine column name of cell.');
50+
}
51+
}
52+
53+
/** Harness for interacting with an MDC-based Angular Material table header cell. */
54+
export class MatHeaderCellHarness extends MatCellHarness {
55+
/** The selector for the host element of a `MatHeaderCellHarness` instance. */
56+
static hostSelector = '.mat-mdc-header-cell';
57+
58+
/**
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.
63+
*/
64+
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatHeaderCellHarness> {
65+
return getCellPredicate(MatHeaderCellHarness, options);
66+
}
67+
}
68+
69+
/** Harness for interacting with an MDC-based Angular Material table footer cell. */
70+
export class MatFooterCellHarness extends MatCellHarness {
71+
/** The selector for the host element of a `MatFooterCellHarness` instance. */
72+
static hostSelector = '.mat-mdc-footer-cell';
73+
74+
/**
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.
79+
*/
80+
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatFooterCellHarness> {
81+
return getCellPredicate(MatFooterCellHarness, options);
82+
}
83+
}
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+
.addOption('columnName', options.columnName,
93+
(harness, name) => HarnessPredicate.stringMatches(harness.getColumnName(), name));
94+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export * from './public-api';
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export * from './table-harness';
10+
export * from './row-harness';
11+
export * from './cell-harness';
12+
export * from './table-harness-filters';
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10+
import {RowHarnessFilters, CellHarnessFilters} from './table-harness-filters';
11+
import {MatCellHarness, MatHeaderCellHarness, MatFooterCellHarness} from './cell-harness';
12+
13+
/** Text extracted from a table row organized by columns. */
14+
export interface MatRowHarnessColumnsText {
15+
[columnName: string]: string;
16+
}
17+
18+
/** Harness for interacting with an MDC-based Angular Material table row. */
19+
export class MatRowHarness extends ComponentHarness {
20+
/** The selector for the host element of a `MatRowHarness` instance. */
21+
static hostSelector = '.mat-mdc-row';
22+
23+
/**
24+
* Gets a `HarnessPredicate` that can be used to search for a table row with specific attributes.
25+
* @param options Options for narrowing the search
26+
* @return a `HarnessPredicate` configured with the given options.
27+
*/
28+
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatRowHarness> {
29+
return new HarnessPredicate(MatRowHarness, options);
30+
}
31+
32+
/** Gets a list of `MatCellHarness` for all cells in the row. */
33+
async getCells(filter: CellHarnessFilters = {}): Promise<MatCellHarness[]> {
34+
return this.locatorForAll(MatCellHarness.with(filter))();
35+
}
36+
37+
/** Gets the text of the cells in the row. */
38+
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
39+
return getCellTextByIndex(this, filter);
40+
}
41+
42+
/** Gets the text inside the row organized by columns. */
43+
async getCellTextByColumnName(): Promise<MatRowHarnessColumnsText> {
44+
return getCellTextByColumnName(this);
45+
}
46+
}
47+
48+
/** Harness for interacting with an MDC-based Angular Material table header row. */
49+
export class MatHeaderRowHarness extends ComponentHarness {
50+
/** The selector for the host element of a `MatHeaderRowHarness` instance. */
51+
static hostSelector = '.mat-mdc-header-row';
52+
53+
/**
54+
* Gets a `HarnessPredicate` that can be used to search for
55+
* a table header row with specific attributes.
56+
* @param options Options for narrowing the search
57+
* @return a `HarnessPredicate` configured with the given options.
58+
*/
59+
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatHeaderRowHarness> {
60+
return new HarnessPredicate(MatHeaderRowHarness, options);
61+
}
62+
63+
/** Gets a list of `MatHeaderCellHarness` for all cells in the row. */
64+
async getCells(filter: CellHarnessFilters = {}): Promise<MatHeaderCellHarness[]> {
65+
return this.locatorForAll(MatHeaderCellHarness.with(filter))();
66+
}
67+
68+
/** Gets the text of the cells in the header row. */
69+
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
70+
return getCellTextByIndex(this, filter);
71+
}
72+
73+
/** Gets the text inside the header row organized by columns. */
74+
async getCellTextByColumnName(): Promise<MatRowHarnessColumnsText> {
75+
return getCellTextByColumnName(this);
76+
}
77+
}
78+
79+
80+
/** Harness for interacting with an MDC-based Angular Material table footer row. */
81+
export class MatFooterRowHarness extends ComponentHarness {
82+
/** The selector for the host element of a `MatFooterRowHarness` instance. */
83+
static hostSelector = '.mat-mdc-footer-row';
84+
85+
/**
86+
* Gets a `HarnessPredicate` that can be used to search for
87+
* a table footer row cell with specific attributes.
88+
* @param options Options for narrowing the search
89+
* @return a `HarnessPredicate` configured with the given options.
90+
*/
91+
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatFooterRowHarness> {
92+
return new HarnessPredicate(MatFooterRowHarness, options);
93+
}
94+
95+
/** Gets a list of `MatFooterCellHarness` for all cells in the row. */
96+
async getCells(filter: CellHarnessFilters = {}): Promise<MatFooterCellHarness[]> {
97+
return this.locatorForAll(MatFooterCellHarness.with(filter))();
98+
}
99+
100+
/** Gets the text of the cells in the footer row. */
101+
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
102+
return getCellTextByIndex(this, filter);
103+
}
104+
105+
/** Gets the text inside the footer row organized by columns. */
106+
async getCellTextByColumnName(): Promise<MatRowHarnessColumnsText> {
107+
return getCellTextByColumnName(this);
108+
}
109+
}
110+
111+
112+
async function getCellTextByIndex(harness: {
113+
getCells: (filter?: CellHarnessFilters) => Promise<MatCellHarness[]>
114+
}, filter: CellHarnessFilters): Promise<string[]> {
115+
const cells = await harness.getCells(filter);
116+
return Promise.all(cells.map(cell => cell.getText()));
117+
}
118+
119+
async function getCellTextByColumnName(harness: {
120+
getCells: () => Promise<MatCellHarness[]>
121+
}): Promise<MatRowHarnessColumnsText> {
122+
const output: MatRowHarnessColumnsText = {};
123+
const cells = await harness.getCells();
124+
const cellsData = await Promise.all(cells.map(cell => {
125+
return Promise.all([cell.getColumnName(), cell.getText()]);
126+
}));
127+
cellsData.forEach(([columnName, text]) => output[columnName] = text);
128+
return output;
129+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {BaseHarnessFilters} from '@angular/cdk/testing';
9+
10+
/** A set of criteria that can be used to filter a list of cell harness instances. */
11+
export interface CellHarnessFilters extends BaseHarnessFilters {
12+
/** Only find instances whose text matches the given value. */
13+
text?: string | RegExp;
14+
15+
/** Only find instances whose column name matches the given value. */
16+
columnName?: string | RegExp;
17+
}
18+
19+
/** A set of criteria that can be used to filter a list of row harness instances. */
20+
export interface RowHarnessFilters extends BaseHarnessFilters {
21+
}
22+
23+
/** A set of criteria that can be used to filter a list of table harness instances. */
24+
export interface TableHarnessFilters extends BaseHarnessFilters {
25+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {MatTableModule} from '@angular/material-experimental/mdc-table';
2+
import {runHarnessTests} from '@angular/material/table/testing/shared.spec';
3+
import {MatTableHarness} from './table-harness';
4+
5+
describe('MDC-based MatTableHarness', () => {
6+
runHarnessTests(MatTableModule, MatTableHarness);
7+
});

0 commit comments

Comments
 (0)