Skip to content

Commit ab8f62f

Browse files
authored
refactor(material-experimental/mdc-slide-toggle): de-duplicate test harness logic (#21747)
De-duplicate the test harness logic between the MDC and non-MDC harnesses.
1 parent da5e2eb commit ab8f62f

File tree

5 files changed

+53
-129
lines changed

5 files changed

+53
-129
lines changed

scripts/check-mdc-exports-config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ export const config = {
7272
// Private module used to provide some common functionality.
7373
'_MatSlideToggleRequiredValidatorModule'
7474
],
75+
'mdc-slide-toggle/testing': [
76+
// Private base class that is only exported for MDC.
77+
'_MatSlideToggleHarnessBase'
78+
],
7579
'mdc-snack-bar': [
7680
// Private interface used to ensure consistency for MDC package.
7781
'_SnackBarContainer'

src/material-experimental/mdc-slide-toggle/testing/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ ts_library(
1010
),
1111
module_name = "@angular/material-experimental/mdc-slide-toggle/testing",
1212
deps = [
13-
"//src/cdk/coercion",
1413
"//src/cdk/testing",
1514
"//src/material/slide-toggle/testing",
1615
],

src/material-experimental/mdc-slide-toggle/testing/slide-toggle-harness.ts

Lines changed: 6 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10-
import {coerceBooleanProperty} from '@angular/cdk/coercion';
11-
import {SlideToggleHarnessFilters} from '@angular/material/slide-toggle/testing';
9+
import {HarnessPredicate} from '@angular/cdk/testing';
10+
import {
11+
_MatSlideToggleHarnessBase,
12+
SlideToggleHarnessFilters
13+
} from '@angular/material/slide-toggle/testing';
1214

1315

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

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

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

39-
/** Gets a boolean promise indicating if the slide-toggle is checked. */
40-
async isChecked(): Promise<boolean> {
41-
const checked = (await this._input()).getProperty('checked');
42-
return coerceBooleanProperty(await checked);
43-
}
44-
45-
/** Gets a boolean promise indicating if the slide-toggle is disabled. */
46-
async isDisabled(): Promise<boolean> {
47-
const disabled = (await this._input()).getAttribute('disabled');
48-
return coerceBooleanProperty(await disabled);
49-
}
50-
51-
/** Gets a boolean promise indicating if the slide-toggle is required. */
52-
async isRequired(): Promise<boolean> {
53-
const required = (await this._input()).getAttribute('required');
54-
return coerceBooleanProperty(await required);
55-
}
56-
57-
/** Gets a boolean promise indicating if the slide-toggle is valid. */
58-
async isValid(): Promise<boolean> {
59-
const invalid = (await this.host()).hasClass('ng-invalid');
60-
return !(await invalid);
61-
}
62-
63-
/** Gets a promise for the slide-toggle's name. */
64-
async getName(): Promise<string | null> {
65-
return (await this._input()).getAttribute('name');
66-
}
67-
68-
/** Gets a promise for the slide-toggle's aria-label. */
69-
async getAriaLabel(): Promise<string | null> {
70-
return (await this._input()).getAttribute('aria-label');
71-
}
72-
73-
/** Gets a promise for the slide-toggle's aria-labelledby. */
74-
async getAriaLabelledby(): Promise<string | null> {
75-
return (await this._input()).getAttribute('aria-labelledby');
76-
}
77-
78-
/** Gets a promise for the slide-toggle's label text. */
79-
async getLabelText(): Promise<string> {
80-
return (await this._label()).text();
81-
}
82-
83-
/** Focuses the slide-toggle and returns a void promise that indicates action completion. */
84-
async focus(): Promise<void> {
85-
return (await this._input()).focus();
86-
}
87-
88-
/** Blurs the slide-toggle and returns a void promise that indicates action completion. */
89-
async blur(): Promise<void> {
90-
return (await this._input()).blur();
91-
}
92-
93-
/** Whether the slide-toggle is focused. */
94-
async isFocused(): Promise<boolean> {
95-
return (await this._input()).isFocused();
96-
}
97-
98-
/**
99-
* Toggle the checked state of the slide-toggle and returns a void promise that indicates when the
100-
* action is complete.
101-
*
102-
* Note: This attempts to toggle the slide-toggle as a user would, by clicking it.
103-
*/
10439
async toggle(): Promise<void> {
10540
const elToClick = await this.isDisabled() ? this._inputContainer() : this._input();
10641
return (await elToClick).click();
10742
}
108-
109-
/**
110-
* Puts the slide-toggle in a checked state by toggling it if it is currently unchecked, or doing
111-
* nothing if it is already checked. Returns a void promise that indicates when the action is
112-
* complete.
113-
*
114-
* Note: This attempts to check the slide-toggle as a user would, by clicking it.
115-
*/
116-
async check(): Promise<void> {
117-
if (!(await this.isChecked())) {
118-
await this.toggle();
119-
}
120-
}
121-
122-
/**
123-
* Puts the slide-toggle in an unchecked state by toggling it if it is currently checked, or doing
124-
* nothing if it is already unchecked. Returns a void promise that indicates when the action is
125-
* complete.
126-
*
127-
* Note: This attempts to uncheck the slide-toggle as a user would, by clicking it.
128-
*/
129-
async uncheck(): Promise<void> {
130-
if (await this.isChecked()) {
131-
await this.toggle();
132-
}
133-
}
13443
}

src/material/slide-toggle/testing/slide-toggle-harness.ts

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,12 @@ import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
1010
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1111
import {SlideToggleHarnessFilters} from './slide-toggle-harness-filters';
1212

13-
14-
/** Harness for interacting with a standard mat-slide-toggle in tests. */
15-
export class MatSlideToggleHarness extends ComponentHarness {
16-
/** The selector for the host element of a `MatSlideToggle` instance. */
17-
static hostSelector = '.mat-slide-toggle';
18-
19-
/**
20-
* Gets a `HarnessPredicate` that can be used to search for a `MatSlideToggleHarness` that meets
21-
* certain criteria.
22-
* @param options Options for filtering which slide toggle instances are considered a match.
23-
* @return a `HarnessPredicate` configured with the given options.
24-
*/
25-
static with(options: SlideToggleHarnessFilters = {}): HarnessPredicate<MatSlideToggleHarness> {
26-
return new HarnessPredicate(MatSlideToggleHarness, options)
27-
.addOption('label', options.label,
28-
(harness, label) => HarnessPredicate.stringMatches(harness.getLabelText(), label))
29-
// We want to provide a filter option for "name" because the name of the slide-toggle is
30-
// only set on the underlying input. This means that it's not possible for developers
31-
// to retrieve the harness of a specific checkbox with name through a CSS selector.
32-
.addOption('name', options.name, async (harness, name) => await harness.getName() === name);
33-
}
34-
13+
export abstract class _MatSlideToggleHarnessBase extends ComponentHarness {
3514
private _label = this.locatorFor('label');
36-
private _input = this.locatorFor('input');
37-
private _inputContainer = this.locatorFor('.mat-slide-toggle-bar');
15+
protected _input = this.locatorFor('input');
16+
17+
/** Toggle the checked state of the slide-toggle. */
18+
abstract toggle(): Promise<void>;
3819

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

98-
/** Toggle the checked state of the slide-toggle. */
99-
async toggle(): Promise<void> {
100-
return (await this._inputContainer()).click();
101-
}
102-
10379
/**
10480
* Puts the slide-toggle in a checked state by toggling it if it is currently unchecked, or doing
10581
* nothing if it is already checked.
@@ -120,3 +96,34 @@ export class MatSlideToggleHarness extends ComponentHarness {
12096
}
12197
}
12298
}
99+
100+
101+
102+
/** Harness for interacting with a standard mat-slide-toggle in tests. */
103+
export class MatSlideToggleHarness extends _MatSlideToggleHarnessBase {
104+
/** The selector for the host element of a `MatSlideToggle` instance. */
105+
static hostSelector = '.mat-slide-toggle';
106+
107+
/**
108+
* Gets a `HarnessPredicate` that can be used to search for a `MatSlideToggleHarness` that meets
109+
* certain criteria.
110+
* @param options Options for filtering which slide toggle instances are considered a match.
111+
* @return a `HarnessPredicate` configured with the given options.
112+
*/
113+
static with(options: SlideToggleHarnessFilters = {}): HarnessPredicate<MatSlideToggleHarness> {
114+
return new HarnessPredicate(MatSlideToggleHarness, options)
115+
.addOption('label', options.label,
116+
(harness, label) => HarnessPredicate.stringMatches(harness.getLabelText(), label))
117+
// We want to provide a filter option for "name" because the name of the slide-toggle is
118+
// only set on the underlying input. This means that it's not possible for developers
119+
// to retrieve the harness of a specific checkbox with name through a CSS selector.
120+
.addOption('name', options.name, async (harness, name) => await harness.getName() === name);
121+
}
122+
123+
private _inputContainer = this.locatorFor('.mat-slide-toggle-bar');
124+
125+
/** Toggle the checked state of the slide-toggle. */
126+
async toggle(): Promise<void> {
127+
return (await this._inputContainer()).click();
128+
}
129+
}

tools/public_api_guard/material/slide-toggle/testing.d.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export declare class MatSlideToggleHarness extends ComponentHarness {
1+
export declare abstract class _MatSlideToggleHarnessBase extends ComponentHarness {
2+
protected _input: import("@angular/cdk/testing").AsyncFactoryFn<import("@angular/cdk/testing").TestElement>;
23
blur(): Promise<void>;
34
check(): Promise<void>;
45
focus(): Promise<void>;
@@ -11,8 +12,12 @@ export declare class MatSlideToggleHarness extends ComponentHarness {
1112
isFocused(): Promise<boolean>;
1213
isRequired(): Promise<boolean>;
1314
isValid(): Promise<boolean>;
14-
toggle(): Promise<void>;
15+
abstract toggle(): Promise<void>;
1516
uncheck(): Promise<void>;
17+
}
18+
19+
export declare class MatSlideToggleHarness extends _MatSlideToggleHarnessBase {
20+
toggle(): Promise<void>;
1621
static hostSelector: string;
1722
static with(options?: SlideToggleHarnessFilters): HarnessPredicate<MatSlideToggleHarness>;
1823
}

0 commit comments

Comments
 (0)