diff --git a/src/material-experimental/config.bzl b/src/material-experimental/config.bzl index 3e4010824d92..96075650f220 100644 --- a/src/material-experimental/config.bzl +++ b/src/material-experimental/config.bzl @@ -10,6 +10,7 @@ entryPoints = [ "mdc-chips", "mdc-chips/testing", "mdc-core", + "mdc-core/testing", "mdc-dialog", "mdc-dialog/testing", "mdc-form-field", diff --git a/src/material-experimental/mdc-core/testing/BUILD.bazel b/src/material-experimental/mdc-core/testing/BUILD.bazel new file mode 100644 index 000000000000..f8eeb913d884 --- /dev/null +++ b/src/material-experimental/mdc-core/testing/BUILD.bazel @@ -0,0 +1,35 @@ +load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "testing", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), + module_name = "@angular/material-experimental/mdc-core/testing", + deps = [ + "//src/cdk/testing", + ], +) + +filegroup( + name = "source-files", + srcs = glob(["**/*.ts"]), +) + +ng_test_library( + name = "unit_tests_lib", + srcs = glob(["**/*.spec.ts"]), + deps = [ + ":testing", + "//src/material-experimental/mdc-core", + "//src/material/core/testing:harness_tests_lib", + ], +) + +ng_web_test_suite( + name = "unit_tests", + deps = [":unit_tests_lib"], +) diff --git a/src/material-experimental/mdc-core/testing/index.ts b/src/material-experimental/mdc-core/testing/index.ts new file mode 100644 index 000000000000..676ca90f1ffa --- /dev/null +++ b/src/material-experimental/mdc-core/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'; diff --git a/src/material-experimental/mdc-core/testing/optgroup-harness-filters.ts b/src/material-experimental/mdc-core/testing/optgroup-harness-filters.ts new file mode 100644 index 000000000000..67acebb9992a --- /dev/null +++ b/src/material-experimental/mdc-core/testing/optgroup-harness-filters.ts @@ -0,0 +1,13 @@ +/** + * @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 {BaseHarnessFilters} from '@angular/cdk/testing'; + +export interface OptgroupHarnessFilters extends BaseHarnessFilters { + labelText?: string | RegExp; +} diff --git a/src/material-experimental/mdc-core/testing/optgroup-harness.spec.ts b/src/material-experimental/mdc-core/testing/optgroup-harness.spec.ts new file mode 100644 index 000000000000..ebd2d61c43c8 --- /dev/null +++ b/src/material-experimental/mdc-core/testing/optgroup-harness.spec.ts @@ -0,0 +1,7 @@ +import {MatOptionModule} from '@angular/material-experimental/mdc-core'; +import {runHarnessTests} from '@angular/material/core/testing/optgroup-shared.spec'; +import {MatOptgroupHarness} from './optgroup-harness'; + +describe('MDC-based MatOptgroupHarness', () => { + runHarnessTests(MatOptionModule, MatOptgroupHarness as any); +}); diff --git a/src/material-experimental/mdc-core/testing/optgroup-harness.ts b/src/material-experimental/mdc-core/testing/optgroup-harness.ts new file mode 100644 index 000000000000..695067af1146 --- /dev/null +++ b/src/material-experimental/mdc-core/testing/optgroup-harness.ts @@ -0,0 +1,51 @@ +/** + * @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 {OptgroupHarnessFilters} from './optgroup-harness-filters'; +import {MatOptionHarness} from './option-harness'; +import {OptionHarnessFilters} from './option-harness-filters'; + +/** Harness for interacting with an MDC-based `mat-optgroup` in tests. */ +export class MatOptgroupHarness extends ComponentHarness { + /** Selector used to locate option group instances. */ + static hostSelector = '.mat-mdc-optgroup'; + private _label = this.locatorFor('.mat-mdc-optgroup-label'); + + /** + * Gets a `HarnessPredicate` that can be used to search for a `MatOptgroupHarness` that meets + * certain criteria. + * @param options Options for filtering which option instances are considered a match. + * @return a `HarnessPredicate` configured with the given options. + */ + static with(options: OptgroupHarnessFilters = {}) { + return new HarnessPredicate(MatOptgroupHarness, options) + .addOption('labelText', options.labelText, + async (harness, title) => + HarnessPredicate.stringMatches(await harness.getLabelText(), title)); + } + + /** Gets the option group's label text. */ + async getLabelText(): Promise { + return (await this._label()).text(); + } + + /** Gets whether the option group is disabled. */ + async isDisabled(): Promise { + return (await (await this.host()).getAttribute('aria-disabled')) === 'true'; + } + + /** + * Gets the options that are inside the group. + * @param filter Optionally filters which options are included. + */ + async getOptions(filter: OptionHarnessFilters = {}): Promise { + return this.locatorForAll(MatOptionHarness.with(filter))(); + } +} + diff --git a/src/material-experimental/mdc-core/testing/option-harness-filters.ts b/src/material-experimental/mdc-core/testing/option-harness-filters.ts new file mode 100644 index 000000000000..2f0c1dfbe2fb --- /dev/null +++ b/src/material-experimental/mdc-core/testing/option-harness-filters.ts @@ -0,0 +1,14 @@ +/** + * @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 {BaseHarnessFilters} from '@angular/cdk/testing'; + +export interface OptionHarnessFilters extends BaseHarnessFilters { + text?: string | RegExp; + isSelected?: boolean; +} diff --git a/src/material-experimental/mdc-core/testing/option-harness.spec.ts b/src/material-experimental/mdc-core/testing/option-harness.spec.ts new file mode 100644 index 000000000000..52f2a8f89928 --- /dev/null +++ b/src/material-experimental/mdc-core/testing/option-harness.spec.ts @@ -0,0 +1,7 @@ +import {MatOptionModule, MatOption} from '@angular/material-experimental/mdc-core'; +import {runHarnessTests} from '@angular/material/core/testing/option-shared.spec'; +import {MatOptionHarness} from './option-harness'; + +describe('MDC-based MatOptionHarness', () => { + runHarnessTests(MatOptionModule, MatOptionHarness as any, MatOption); +}); diff --git a/src/material-experimental/mdc-core/testing/option-harness.ts b/src/material-experimental/mdc-core/testing/option-harness.ts new file mode 100644 index 000000000000..840ae4b79020 --- /dev/null +++ b/src/material-experimental/mdc-core/testing/option-harness.ts @@ -0,0 +1,62 @@ +/** + * @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 {OptionHarnessFilters} from './option-harness-filters'; + +/** Harness for interacting with an MDC-based `mat-option` in tests. */ +export class MatOptionHarness extends ComponentHarness { + /** Selector used to locate option instances. */ + static hostSelector = '.mat-mdc-option'; + + /** + * Gets a `HarnessPredicate` that can be used to search for a `MatOptionsHarness` that meets + * certain criteria. + * @param options Options for filtering which option instances are considered a match. + * @return a `HarnessPredicate` configured with the given options. + */ + static with(options: OptionHarnessFilters = {}) { + return new HarnessPredicate(MatOptionHarness, options) + .addOption('text', options.text, + async (harness, title) => + HarnessPredicate.stringMatches(await harness.getText(), title)) + .addOption('isSelected', options.isSelected, + async (harness, isSelected) => await harness.isSelected() === isSelected); + + } + + /** Clicks the option. */ + async click(): Promise { + return (await this.host()).click(); + } + + /** Gets the option's label text. */ + async getText(): Promise { + return (await this.host()).text(); + } + + /** Gets whether the option is disabled. */ + async isDisabled(): Promise { + return (await this.host()).hasClass('mdc-list-item--disabled'); + } + + /** Gets whether the option is selected. */ + async isSelected(): Promise { + return (await this.host()).hasClass('mdc-list-item--selected'); + } + + /** Gets whether the option is active. */ + async isActive(): Promise { + return (await this.host()).hasClass('mat-mdc-option-active'); + } + + /** Gets whether the option is in multiple selection mode. */ + async isMultiple(): Promise { + return (await this.host()).hasClass('mat-mdc-option-multiple'); + } +} diff --git a/src/material-experimental/mdc-core/testing/public-api.ts b/src/material-experimental/mdc-core/testing/public-api.ts new file mode 100644 index 000000000000..5566e1c7c558 --- /dev/null +++ b/src/material-experimental/mdc-core/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 './option-harness'; +export * from './option-harness-filters'; +export * from './optgroup-harness'; +export * from './optgroup-harness-filters'; diff --git a/src/material/core/testing/option-harness.spec.ts b/src/material/core/testing/option-harness.spec.ts index 8edf7f8a3a39..31aa0a5cd180 100644 --- a/src/material/core/testing/option-harness.spec.ts +++ b/src/material/core/testing/option-harness.spec.ts @@ -1,7 +1,7 @@ -import {MatOptionModule} from '@angular/material/core'; +import {MatOptionModule, MatOption} from '@angular/material/core'; import {runHarnessTests} from './option-shared.spec'; import {MatOptionHarness} from './option-harness'; describe('Non-MDC-based MatOptionHarness', () => { - runHarnessTests(MatOptionModule, MatOptionHarness); + runHarnessTests(MatOptionModule, MatOptionHarness, MatOption); }); diff --git a/src/material/core/testing/option-shared.spec.ts b/src/material/core/testing/option-shared.spec.ts index d2ae79d8617d..c0eabe33ce64 100644 --- a/src/material/core/testing/option-shared.spec.ts +++ b/src/material/core/testing/option-shared.spec.ts @@ -12,7 +12,9 @@ import {MatOptionHarness} from './option-harness'; /** Shared tests to run on both the original and MDC-based options. */ export function runHarnessTests( - optionModule: typeof MatOptionModule, optionHarness: typeof MatOptionHarness) { + optionModule: typeof MatOptionModule, + optionHarness: typeof MatOptionHarness, + optionComponent: typeof MatOption) { let fixture: ComponentFixture; let loader: HarnessLoader; @@ -102,21 +104,19 @@ export function runHarnessTests( expect(await option.isMultiple()).toBe(true); }); -} - -@Component({ - providers: [{ - provide: MAT_OPTION_PARENT_COMPONENT, - useExisting: OptionHarnessTest - }], - template: ` - Plain option - Disabled option - ` -}) -class OptionHarnessTest implements MatOptionParentComponent { - @ViewChildren(MatOption) options: QueryList; - multiple = false; + @Component({ + providers: [{ + provide: MAT_OPTION_PARENT_COMPONENT, + useExisting: OptionHarnessTest + }], + template: ` + Plain option + Disabled option + ` + }) + class OptionHarnessTest implements MatOptionParentComponent { + @ViewChildren(optionComponent) options: QueryList<{setActiveStyles(): void}>; + multiple = false; + } } -