Skip to content

refactor(material-experimental/mdc-slide-toggle): de-duplicate test harness logic #21747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions scripts/check-mdc-exports-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export const config = {
// Private module used to provide some common functionality.
'_MatSlideToggleRequiredValidatorModule'
],
'mdc-slide-toggle/testing': [
// Private base class that is only exported for MDC.
'_MatSlideToggleHarnessBase'
],
'mdc-snack-bar': [
// Private interface used to ensure consistency for MDC package.
'_SnackBarContainer'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ ts_library(
),
module_name = "@angular/material-experimental/mdc-slide-toggle/testing",
deps = [
"//src/cdk/coercion",
"//src/cdk/testing",
"//src/material/slide-toggle/testing",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/

import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {SlideToggleHarnessFilters} from '@angular/material/slide-toggle/testing';
import {HarnessPredicate} from '@angular/cdk/testing';
import {
_MatSlideToggleHarnessBase,
SlideToggleHarnessFilters
} from '@angular/material/slide-toggle/testing';


/** Harness for interacting with a MDC-based mat-slide-toggle in tests. */
export class MatSlideToggleHarness extends ComponentHarness {
export class MatSlideToggleHarness extends _MatSlideToggleHarnessBase {
static hostSelector = '.mat-mdc-slide-toggle';

/**
Expand All @@ -32,103 +34,10 @@ export class MatSlideToggleHarness extends ComponentHarness {
.addOption('name', options.name, async (harness, name) => await harness.getName() === name);
}

private _label = this.locatorFor('label');
private _input = this.locatorFor('input');
private _inputContainer = this.locatorFor('.mdc-switch');

/** Gets a boolean promise indicating if the slide-toggle is checked. */
async isChecked(): Promise<boolean> {
const checked = (await this._input()).getProperty('checked');
return coerceBooleanProperty(await checked);
}

/** Gets a boolean promise indicating if the slide-toggle is disabled. */
async isDisabled(): Promise<boolean> {
const disabled = (await this._input()).getAttribute('disabled');
return coerceBooleanProperty(await disabled);
}

/** Gets a boolean promise indicating if the slide-toggle is required. */
async isRequired(): Promise<boolean> {
const required = (await this._input()).getAttribute('required');
return coerceBooleanProperty(await required);
}

/** Gets a boolean promise indicating if the slide-toggle is valid. */
async isValid(): Promise<boolean> {
const invalid = (await this.host()).hasClass('ng-invalid');
return !(await invalid);
}

/** Gets a promise for the slide-toggle's name. */
async getName(): Promise<string | null> {
return (await this._input()).getAttribute('name');
}

/** Gets a promise for the slide-toggle's aria-label. */
async getAriaLabel(): Promise<string | null> {
return (await this._input()).getAttribute('aria-label');
}

/** Gets a promise for the slide-toggle's aria-labelledby. */
async getAriaLabelledby(): Promise<string | null> {
return (await this._input()).getAttribute('aria-labelledby');
}

/** Gets a promise for the slide-toggle's label text. */
async getLabelText(): Promise<string> {
return (await this._label()).text();
}

/** Focuses the slide-toggle and returns a void promise that indicates action completion. */
async focus(): Promise<void> {
return (await this._input()).focus();
}

/** Blurs the slide-toggle and returns a void promise that indicates action completion. */
async blur(): Promise<void> {
return (await this._input()).blur();
}

/** Whether the slide-toggle is focused. */
async isFocused(): Promise<boolean> {
return (await this._input()).isFocused();
}

/**
* Toggle the checked state of the slide-toggle and returns a void promise that indicates when the
* action is complete.
*
* Note: This attempts to toggle the slide-toggle as a user would, by clicking it.
*/
async toggle(): Promise<void> {
const elToClick = await this.isDisabled() ? this._inputContainer() : this._input();
return (await elToClick).click();
}

/**
* Puts the slide-toggle in a checked state by toggling it if it is currently unchecked, or doing
* nothing if it is already checked. Returns a void promise that indicates when the action is
* complete.
*
* Note: This attempts to check the slide-toggle as a user would, by clicking it.
*/
async check(): Promise<void> {
if (!(await this.isChecked())) {
await this.toggle();
}
}

/**
* Puts the slide-toggle in an unchecked state by toggling it if it is currently checked, or doing
* nothing if it is already unchecked. Returns a void promise that indicates when the action is
* complete.
*
* Note: This attempts to uncheck the slide-toggle as a user would, by clicking it.
*/
async uncheck(): Promise<void> {
if (await this.isChecked()) {
await this.toggle();
}
}
}
65 changes: 36 additions & 29 deletions src/material/slide-toggle/testing/slide-toggle-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,12 @@ import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {SlideToggleHarnessFilters} from './slide-toggle-harness-filters';


/** Harness for interacting with a standard mat-slide-toggle in tests. */
export class MatSlideToggleHarness extends ComponentHarness {
/** The selector for the host element of a `MatSlideToggle` instance. */
static hostSelector = '.mat-slide-toggle';

/**
* Gets a `HarnessPredicate` that can be used to search for a `MatSlideToggleHarness` that meets
* certain criteria.
* @param options Options for filtering which slide toggle instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: SlideToggleHarnessFilters = {}): HarnessPredicate<MatSlideToggleHarness> {
return new HarnessPredicate(MatSlideToggleHarness, options)
.addOption('label', options.label,
(harness, label) => HarnessPredicate.stringMatches(harness.getLabelText(), label))
// We want to provide a filter option for "name" because the name of the slide-toggle is
// only set on the underlying input. This means that it's not possible for developers
// to retrieve the harness of a specific checkbox with name through a CSS selector.
.addOption('name', options.name, async (harness, name) => await harness.getName() === name);
}

export abstract class _MatSlideToggleHarnessBase extends ComponentHarness {
private _label = this.locatorFor('label');
private _input = this.locatorFor('input');
private _inputContainer = this.locatorFor('.mat-slide-toggle-bar');
protected _input = this.locatorFor('input');

/** Toggle the checked state of the slide-toggle. */
abstract toggle(): Promise<void>;

/** Whether the slide-toggle is checked. */
async isChecked(): Promise<boolean> {
Expand Down Expand Up @@ -95,11 +76,6 @@ export class MatSlideToggleHarness extends ComponentHarness {
return (await this._input()).isFocused();
}

/** Toggle the checked state of the slide-toggle. */
async toggle(): Promise<void> {
return (await this._inputContainer()).click();
}

/**
* Puts the slide-toggle in a checked state by toggling it if it is currently unchecked, or doing
* nothing if it is already checked.
Expand All @@ -120,3 +96,34 @@ export class MatSlideToggleHarness extends ComponentHarness {
}
}
}



/** Harness for interacting with a standard mat-slide-toggle in tests. */
export class MatSlideToggleHarness extends _MatSlideToggleHarnessBase {
/** The selector for the host element of a `MatSlideToggle` instance. */
static hostSelector = '.mat-slide-toggle';

/**
* Gets a `HarnessPredicate` that can be used to search for a `MatSlideToggleHarness` that meets
* certain criteria.
* @param options Options for filtering which slide toggle instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: SlideToggleHarnessFilters = {}): HarnessPredicate<MatSlideToggleHarness> {
return new HarnessPredicate(MatSlideToggleHarness, options)
.addOption('label', options.label,
(harness, label) => HarnessPredicate.stringMatches(harness.getLabelText(), label))
// We want to provide a filter option for "name" because the name of the slide-toggle is
// only set on the underlying input. This means that it's not possible for developers
// to retrieve the harness of a specific checkbox with name through a CSS selector.
.addOption('name', options.name, async (harness, name) => await harness.getName() === name);
}

private _inputContainer = this.locatorFor('.mat-slide-toggle-bar');

/** Toggle the checked state of the slide-toggle. */
async toggle(): Promise<void> {
return (await this._inputContainer()).click();
}
}
9 changes: 7 additions & 2 deletions tools/public_api_guard/material/slide-toggle/testing.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export declare class MatSlideToggleHarness extends ComponentHarness {
export declare abstract class _MatSlideToggleHarnessBase extends ComponentHarness {
protected _input: import("@angular/cdk/testing").AsyncFactoryFn<import("@angular/cdk/testing").TestElement>;
blur(): Promise<void>;
check(): Promise<void>;
focus(): Promise<void>;
Expand All @@ -11,8 +12,12 @@ export declare class MatSlideToggleHarness extends ComponentHarness {
isFocused(): Promise<boolean>;
isRequired(): Promise<boolean>;
isValid(): Promise<boolean>;
toggle(): Promise<void>;
abstract toggle(): Promise<void>;
uncheck(): Promise<void>;
}

export declare class MatSlideToggleHarness extends _MatSlideToggleHarnessBase {
toggle(): Promise<void>;
static hostSelector: string;
static with(options?: SlideToggleHarnessFilters): HarnessPredicate<MatSlideToggleHarness>;
}
Expand Down