Skip to content

Commit 85f596b

Browse files
authored
feat(material/table): add harness for "no data" row (#32075)
Adds a harness for the "no data" row to make it easier to interact with in tests.
1 parent 6d73df0 commit 85f596b

File tree

5 files changed

+81
-4
lines changed

5 files changed

+81
-4
lines changed

goldens/material/table/testing/index.api.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ export class MatHeaderRowHarness extends _MatRowHarnessBase<typeof MatHeaderCell
5858
static with<T extends MatHeaderRowHarness>(this: ComponentHarnessConstructor<T>, options?: RowHarnessFilters): HarnessPredicate<T>;
5959
}
6060

61+
// @public
62+
export class MatNoDataCellHarness extends _MatCellHarnessBase {
63+
static hostSelector: string;
64+
static with(options?: CellHarnessFilters): HarnessPredicate<MatNoDataCellHarness>;
65+
}
66+
67+
// @public
68+
export class MatNoDataRowHarness extends _MatRowHarnessBase<typeof MatHeaderCellHarness, MatHeaderCellHarness> {
69+
// (undocumented)
70+
protected _cellHarness: typeof MatNoDataCellHarness;
71+
static hostSelector: string;
72+
static with<T extends MatNoDataRowHarness>(this: ComponentHarnessConstructor<T>, options?: RowHarnessFilters): HarnessPredicate<T>;
73+
}
74+
6175
// @public
6276
export class MatRowHarness extends _MatRowHarnessBase<typeof MatCellHarness, MatCellHarness> {
6377
// (undocumented)
@@ -89,6 +103,7 @@ export class MatTableHarness extends ContentContainerComponentHarness<string> {
89103
getCellTextByIndex(): Promise<string[][]>;
90104
getFooterRows(filter?: RowHarnessFilters): Promise<MatFooterRowHarness[]>;
91105
getHeaderRows(filter?: RowHarnessFilters): Promise<MatHeaderRowHarness[]>;
106+
getNoDataRow(filter?: RowHarnessFilters): Promise<MatNoDataRowHarness | null>;
92107
getRows(filter?: RowHarnessFilters): Promise<MatRowHarness[]>;
93108
// (undocumented)
94109
_headerRowHarness: typeof MatHeaderRowHarness;

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,18 @@ export class MatFooterCellHarness extends _MatCellHarnessBase {
9999
return _MatCellHarnessBase._getCellPredicate(this, options);
100100
}
101101
}
102+
103+
/** Harness for interacting with an Angular Material table cell inside a "no data" row. */
104+
export class MatNoDataCellHarness extends _MatCellHarnessBase {
105+
/** The selector for the host element of a `MatNoDataCellHarness` instance. */
106+
static hostSelector = '.mat-no-data-cell';
107+
108+
/**
109+
* Gets a `HarnessPredicate` that can be used to search for a table cell with specific attributes.
110+
* @param options Options for narrowing the search
111+
* @return a `HarnessPredicate` configured with the given options.
112+
*/
113+
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatNoDataCellHarness> {
114+
return _MatCellHarnessBase._getCellPredicate(this, options);
115+
}
116+
}

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
MatCellHarness,
1818
MatFooterCellHarness,
1919
MatHeaderCellHarness,
20+
MatNoDataCellHarness,
2021
} from './cell-harness';
2122
import {CellHarnessFilters, RowHarnessFilters} from './table-harness-filters';
2223

@@ -122,3 +123,26 @@ export class MatFooterRowHarness extends _MatRowHarnessBase<
122123
return new HarnessPredicate(this, options);
123124
}
124125
}
126+
127+
/** Harness for interacting with an Angular Material table "no data" row. */
128+
export class MatNoDataRowHarness extends _MatRowHarnessBase<
129+
typeof MatHeaderCellHarness,
130+
MatHeaderCellHarness
131+
> {
132+
/** The selector for the host element of a `MatNoDataRowHarness` instance. */
133+
static hostSelector = '.mat-mdc-no-data-row';
134+
protected _cellHarness = MatNoDataCellHarness;
135+
136+
/**
137+
* Gets a `HarnessPredicate` that can be used to search for a table header row with specific
138+
* attributes.
139+
* @param options Options for narrowing the search
140+
* @return a `HarnessPredicate` configured with the given options.
141+
*/
142+
static with<T extends MatNoDataRowHarness>(
143+
this: ComponentHarnessConstructor<T>,
144+
options: RowHarnessFilters = {},
145+
): HarnessPredicate<T> {
146+
return new HarnessPredicate(this, options);
147+
}
148+
}

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Component} from '@angular/core';
1+
import {Component, signal} from '@angular/core';
22
import {ComponentFixture, TestBed} from '@angular/core/testing';
33
import {HarnessLoader, parallel} from '@angular/cdk/testing';
44
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
@@ -176,11 +176,24 @@ describe('MatTableHarness', () => {
176176
symbol: 'H',
177177
});
178178
});
179+
180+
it('should be able to get the "no data" row', async () => {
181+
const table = await loader.getHarness(MatTableHarness);
182+
expect(await table.getNoDataRow()).toBe(null);
183+
184+
fixture.componentInstance.dataSource.set([]);
185+
const row = await table.getNoDataRow();
186+
const cells = await row?.getCells();
187+
188+
expect(row).toBeTruthy();
189+
expect(cells?.length).toBe(1);
190+
expect(await cells?.[0].getText()).toBe('No data');
191+
});
179192
});
180193

181194
@Component({
182195
template: `
183-
<table mat-table [dataSource]="dataSource">
196+
<table mat-table [dataSource]="dataSource()">
184197
<ng-container matColumnDef="position">
185198
<th mat-header-cell *matHeaderCellDef>No.</th>
186199
<td mat-cell *matCellDef="let element">{{element.position}}</td>
@@ -208,13 +221,17 @@ describe('MatTableHarness', () => {
208221
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
209222
<tr mat-footer-row *matFooterRowDef="displayedColumns"></tr>
210223
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
224+
225+
<tr *matNoDataRow>
226+
<td>No data</td>
227+
</tr>
211228
</table>
212229
`,
213230
imports: [MatTableModule],
214231
})
215232
class TableHarnessTest {
216233
displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
217-
dataSource = [
234+
dataSource = signal([
218235
{position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
219236
{position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
220237
{position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
@@ -225,5 +242,5 @@ class TableHarnessTest {
225242
{position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
226243
{position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
227244
{position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
228-
];
245+
]);
229246
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import {
1616
MatFooterRowHarness,
1717
MatHeaderRowHarness,
18+
MatNoDataRowHarness,
1819
MatRowHarness,
1920
MatRowHarnessColumnsText,
2021
} from './row-harness';
@@ -64,6 +65,11 @@ export class MatTableHarness extends ContentContainerComponentHarness<string> {
6465
return this.locatorForAll(this._footerRowHarness.with(filter))();
6566
}
6667

68+
/** Gets the "no data" row in the table, if any. */
69+
async getNoDataRow(filter: RowHarnessFilters = {}): Promise<MatNoDataRowHarness | null> {
70+
return this.locatorForOptional(MatNoDataRowHarness.with(filter))();
71+
}
72+
6773
/** Gets the text inside the entire table organized by rows. */
6874
async getCellTextByIndex(): Promise<string[][]> {
6975
const rows = await this.getRows();

0 commit comments

Comments
 (0)