Skip to content

Commit

Permalink
feat(table): add test harness (#17799)
Browse files Browse the repository at this point in the history
* feat(table): add test harness

Adds a test harness for `MatTable`, as well as the related row and cell directives.

* feat(table): add test harness

Adds a test harness for `MatTable`, as well as the related row and cell directives.
  • Loading branch information
crisbeto authored and andrewseguin committed Dec 19, 2019
1 parent abe9e9c commit a30094b
Show file tree
Hide file tree
Showing 12 changed files with 655 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/material/config.bzl
Expand Up @@ -51,6 +51,7 @@ entryPoints = [
"sort/testing",
"stepper",
"table",
"table/testing",
"tabs",
"tabs/testing",
"toolbar",
Expand Down
49 changes: 49 additions & 0 deletions src/material/table/testing/BUILD.bazel
@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])

load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")

ts_library(
name = "testing",
srcs = glob(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
module_name = "@angular/material/table/testing",
deps = [
"//src/cdk/testing",
],
)

filegroup(
name = "source-files",
srcs = glob(["**/*.ts"]),
)

ng_test_library(
name = "harness_tests_lib",
srcs = ["shared.spec.ts"],
deps = [
":testing",
"//src/cdk/testing",
"//src/cdk/testing/testbed",
"//src/material/table",
],
)

ng_test_library(
name = "unit_tests_lib",
srcs = glob(
["**/*.spec.ts"],
exclude = ["shared.spec.ts"],
),
deps = [
":harness_tests_lib",
":testing",
"//src/material/table",
],
)

ng_web_test_suite(
name = "unit_tests",
deps = [":unit_tests_lib"],
)
92 changes: 92 additions & 0 deletions src/material/table/testing/cell-harness.ts
@@ -0,0 +1,92 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {
ComponentHarness,
HarnessPredicate,
ComponentHarnessConstructor,
} from '@angular/cdk/testing';
import {CellHarnessFilters} from './table-harness-filters';

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

/**
* Gets a `HarnessPredicate` that can be used to search for a table cell with specific attributes.
* @param options Options for narrowing the search
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatCellHarness> {
return getCellPredicate(MatCellHarness, options);
}

/** Gets the cell's text. */
async getText(): Promise<string> {
return (await this.host()).text();
}

/** Gets the name of the column that the cell belongs to. */
async getColumnName(): Promise<string> {
const host = await this.host();
const classAttribute = await host.getAttribute('class');

if (classAttribute) {
const prefix = 'mat-column-';
const name = classAttribute.split(' ').map(c => c.trim()).find(c => c.startsWith(prefix));

if (name) {
return name.split(prefix)[1];
}
}

throw Error('Could not determine column name of cell.');
}
}

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

/**
* Gets a `HarnessPredicate` that can be used to search for
* a table header cell with specific attributes.
* @param options Options for narrowing the search
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatHeaderCellHarness> {
return getCellPredicate(MatHeaderCellHarness, options);
}
}

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

/**
* Gets a `HarnessPredicate` that can be used to search for
* a table footer cell with specific attributes.
* @param options Options for narrowing the search
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: CellHarnessFilters = {}): HarnessPredicate<MatFooterCellHarness> {
return getCellPredicate(MatFooterCellHarness, options);
}
}


function getCellPredicate<T extends MatCellHarness>(
type: ComponentHarnessConstructor<T>,
options: CellHarnessFilters): HarnessPredicate<T> {
return new HarnessPredicate(type, options)
.addOption('text', options.text,
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
}
9 changes: 9 additions & 0 deletions src/material/table/testing/index.ts
@@ -0,0 +1,9 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

export * from './public-api';
12 changes: 12 additions & 0 deletions src/material/table/testing/public-api.ts
@@ -0,0 +1,12 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

export * from './table-harness';
export * from './row-harness';
export * from './cell-harness';
export * from './table-harness-filters';
96 changes: 96 additions & 0 deletions src/material/table/testing/row-harness.ts
@@ -0,0 +1,96 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
import {RowHarnessFilters, CellHarnessFilters} from './table-harness-filters';
import {MatCellHarness, MatHeaderCellHarness, MatFooterCellHarness} from './cell-harness';

/** Harness for interacting with a standard Angular Material table row. */
export class MatRowHarness extends ComponentHarness {
/** The selector for the host element of a `MatRowHarness` instance. */
static hostSelector = '.mat-row';

/**
* Gets a `HarnessPredicate` that can be used to search for a table row with specific attributes.
* @param options Options for narrowing the search
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatRowHarness> {
return new HarnessPredicate(MatRowHarness, options);
}

/** Gets a list of `MatCellHarness` for all cells in the row. */
async getCells(filter: CellHarnessFilters = {}): Promise<MatCellHarness[]> {
return this.locatorForAll(MatCellHarness.with(filter))();
}

/** Gets the text of the cells in the row. */
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
return getCellTextByIndex(this, filter);
}
}

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

/**
* Gets a `HarnessPredicate` that can be used to search for
* a table header row with specific attributes.
* @param options Options for narrowing the search
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatHeaderRowHarness> {
return new HarnessPredicate(MatHeaderRowHarness, options);
}

/** Gets a list of `MatHeaderCellHarness` for all cells in the row. */
async getCells(filter: CellHarnessFilters = {}): Promise<MatHeaderCellHarness[]> {
return this.locatorForAll(MatHeaderCellHarness.with(filter))();
}

/** Gets the text of the cells in the header row. */
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
return getCellTextByIndex(this, filter);
}
}


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

/**
* Gets a `HarnessPredicate` that can be used to search for
* a table footer row cell with specific attributes.
* @param options Options for narrowing the search
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: RowHarnessFilters = {}): HarnessPredicate<MatFooterRowHarness> {
return new HarnessPredicate(MatFooterRowHarness, options);
}

/** Gets a list of `MatFooterCellHarness` for all cells in the row. */
async getCells(filter: CellHarnessFilters = {}): Promise<MatFooterCellHarness[]> {
return this.locatorForAll(MatFooterCellHarness.with(filter))();
}

/** Gets the text of the cells in the footer row. */
async getCellTextByIndex(filter: CellHarnessFilters = {}): Promise<string[]> {
return getCellTextByIndex(this, filter);
}
}

async function getCellTextByIndex(harness: {
getCells: (filter?: CellHarnessFilters) => Promise<MatCellHarness[]>
}, filter: CellHarnessFilters): Promise<string[]> {
const cells = await harness.getCells(filter);
return Promise.all(cells.map(cell => cell.getText()));
}

0 comments on commit a30094b

Please sign in to comment.