Skip to content

Commit 010c1e4

Browse files
committed
feat(button-toggle): add test harness
Sets up test harnesses for `mat-button-toggle` and `mat-button-toggle-group`.
1 parent 093d007 commit 010c1e4

14 files changed

+571
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")
4+
5+
ts_library(
6+
name = "testing",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
module_name = "@angular/material/button-toggle/testing",
12+
deps = [
13+
"//src/cdk/coercion",
14+
"//src/cdk/testing",
15+
"//src/material/button-toggle",
16+
],
17+
)
18+
19+
filegroup(
20+
name = "source-files",
21+
srcs = glob(["**/*.ts"]),
22+
)
23+
24+
ng_test_library(
25+
name = "harness_tests_lib",
26+
srcs = [
27+
"button-toggle-group-shared.spec.ts",
28+
"button-toggle-shared.spec.ts",
29+
],
30+
deps = [
31+
":testing",
32+
"//src/cdk/platform",
33+
"//src/cdk/testing",
34+
"//src/cdk/testing/testbed",
35+
"//src/material/button-toggle",
36+
],
37+
)
38+
39+
ng_test_library(
40+
name = "unit_tests_lib",
41+
srcs = glob(
42+
["**/*.spec.ts"],
43+
exclude = [
44+
"button-toggle-shared.spec.ts",
45+
"button-toggle-group-shared.spec.ts",
46+
],
47+
),
48+
deps = [
49+
":harness_tests_lib",
50+
":testing",
51+
"//src/material/button-toggle",
52+
],
53+
)
54+
55+
ng_web_test_suite(
56+
name = "unit_tests",
57+
deps = [":unit_tests_lib"],
58+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {BaseHarnessFilters} from '@angular/cdk/testing';
10+
11+
/** Criteria that can be used to filter a list of `MatButtonToggleGroupHarness` instances. */
12+
export interface ButtonToggleGroupHarnessFilters extends BaseHarnessFilters {
13+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10+
import {MatButtonToggleAppearance} from '@angular/material/button-toggle';
11+
import {ButtonToggleGroupHarnessFilters} from './button-toggle-group-harness-filters';
12+
import {ButtonToggleHarnessFilters} from './button-toggle-harness-filters';
13+
import {MatButtonToggleHarness} from './button-toggle-harness';
14+
15+
16+
/** Harness for interacting with a standard mat-button-toggle in tests. */
17+
export class MatButtonToggleGroupHarness extends ComponentHarness {
18+
/** The selector for the host element of a `MatButton` instance. */
19+
static hostSelector = 'mat-button-toggle-group';
20+
21+
/**
22+
* Gets a `HarnessPredicate` that can be used to search for a `MatButtonToggleGroupHarness`
23+
* that meets certain criteria.
24+
* @param options Options for filtering which button toggle instances are considered a match.
25+
* @return a `HarnessPredicate` configured with the given options.
26+
*/
27+
static with(options: ButtonToggleGroupHarnessFilters = {}):
28+
HarnessPredicate<MatButtonToggleGroupHarness> {
29+
return new HarnessPredicate(MatButtonToggleGroupHarness, options);
30+
}
31+
32+
/**
33+
* Gets the button toggles that are inside the group.
34+
* @param filter Optionally filters which toggles are included.
35+
*/
36+
async getToggles(filter: ButtonToggleHarnessFilters = {}): Promise<MatButtonToggleHarness[]> {
37+
return this.locatorForAll(MatButtonToggleHarness.with(filter))();
38+
}
39+
40+
/** Gets whether the button toggle group is disabled. */
41+
async isDisabled(): Promise<boolean> {
42+
return await (await this.host()).getAttribute('aria-disabled') === 'true';
43+
}
44+
45+
/** Gets whether the button toggle group is laid out vertically. */
46+
async isVertical(): Promise<boolean> {
47+
return (await this.host()).hasClass('mat-button-toggle-vertical');
48+
}
49+
50+
/** Gets the appearance that the group is using. */
51+
async getAppearance(): Promise<MatButtonToggleAppearance> {
52+
const host = await this.host();
53+
const className = 'mat-button-toggle-group-appearance-standard';
54+
return await host.hasClass(className) ? 'standard' : 'legacy';
55+
}
56+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {HarnessLoader} from '@angular/cdk/testing';
2+
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
3+
import {Component} from '@angular/core';
4+
import {ComponentFixture, TestBed} from '@angular/core/testing';
5+
import {MatButtonToggleModule, MatButtonToggleAppearance} from '@angular/material/button-toggle';
6+
import {MatButtonToggleGroupHarness} from './button-toggle-group-harness';
7+
8+
/** Shared tests to run on both the original and MDC-based button toggle group. */
9+
export function runHarnessTests(
10+
buttonToggleModule: typeof MatButtonToggleModule,
11+
buttonToggleGroupHarness: typeof MatButtonToggleGroupHarness) {
12+
let fixture: ComponentFixture<ButtonToggleGroupHarnessTest>;
13+
let loader: HarnessLoader;
14+
15+
beforeEach(async () => {
16+
await TestBed.configureTestingModule({
17+
imports: [buttonToggleModule],
18+
declarations: [ButtonToggleGroupHarnessTest],
19+
}).compileComponents();
20+
21+
fixture = TestBed.createComponent(ButtonToggleGroupHarnessTest);
22+
fixture.detectChanges();
23+
loader = TestbedHarnessEnvironment.loader(fixture);
24+
});
25+
26+
it('should load all button toggle group harnesses', async () => {
27+
const groups = await loader.getAllHarnesses(buttonToggleGroupHarness);
28+
expect(groups.length).toBe(1);
29+
});
30+
31+
it('should load the the toggles inside the group', async () => {
32+
const group = await loader.getHarness(buttonToggleGroupHarness);
33+
const toggles = await group.getToggles();
34+
expect(toggles.length).toBe(2);
35+
});
36+
37+
it('should get whether the group is disabled', async () => {
38+
const group = await loader.getHarness(buttonToggleGroupHarness);
39+
expect(await group.isDisabled()).toBe(false);
40+
fixture.componentInstance.disabled = true;
41+
expect(await group.isDisabled()).toBe(true);
42+
});
43+
44+
it('should get whether the group is vertical', async () => {
45+
const group = await loader.getHarness(buttonToggleGroupHarness);
46+
expect(await group.isVertical()).toBe(false);
47+
fixture.componentInstance.vertical = true;
48+
expect(await group.isVertical()).toBe(true);
49+
});
50+
51+
it('should get whether the group appearance', async () => {
52+
const group = await loader.getHarness(buttonToggleGroupHarness);
53+
expect(await group.getAppearance()).toBe('standard');
54+
fixture.componentInstance.appearance = 'legacy';
55+
expect(await group.getAppearance()).toBe('legacy');
56+
});
57+
}
58+
59+
@Component({
60+
template: `
61+
<mat-button-toggle-group [disabled]="disabled" [vertical]="vertical" [appearance]="appearance">
62+
<mat-button-toggle value="1">One</mat-button-toggle>
63+
<mat-button-toggle value="2">Two</mat-button-toggle>
64+
</mat-button-toggle-group>
65+
`
66+
})
67+
class ButtonToggleGroupHarnessTest {
68+
disabled = false;
69+
vertical = false;
70+
appearance: MatButtonToggleAppearance = 'standard';
71+
}
72+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {MatButtonToggleModule} from '@angular/material/button-toggle';
2+
import {runHarnessTests} from './button-toggle-group-shared.spec';
3+
import {MatButtonToggleGroupHarness} from './button-toggle-group-harness';
4+
5+
describe('Non-MDC-based MatButtonToggleGroupHarness', () => {
6+
runHarnessTests(MatButtonToggleModule, MatButtonToggleGroupHarness);
7+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {BaseHarnessFilters} from '@angular/cdk/testing';
10+
11+
/** Criteria that can be used to filter a list of `MatButtonToggleHarness` instances. */
12+
export interface ButtonToggleHarnessFilters extends BaseHarnessFilters {
13+
/** Only find instances whose text matches the given value. */
14+
text?: string | RegExp;
15+
/** Only find instances whose name matches the given value. */
16+
name?: string | RegExp;
17+
/** Only find instances that are checked. */
18+
checked?: boolean;
19+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {MatButtonToggleModule} from '@angular/material/button-toggle';
2+
import {runHarnessTests} from './button-toggle-shared.spec';
3+
import {MatButtonToggleHarness} from './button-toggle-harness';
4+
5+
describe('Non-MDC-based MatButtonToggleHarness', () => {
6+
runHarnessTests(MatButtonToggleModule, MatButtonToggleHarness);
7+
});
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10+
import {coerceBooleanProperty} from '@angular/cdk/coercion';
11+
import {MatButtonToggleAppearance} from '@angular/material/button-toggle';
12+
import {ButtonToggleHarnessFilters} from './button-toggle-harness-filters';
13+
14+
15+
/** Harness for interacting with a standard mat-button-toggle in tests. */
16+
export class MatButtonToggleHarness extends ComponentHarness {
17+
/** The selector for the host element of a `MatButton` instance. */
18+
static hostSelector = 'mat-button-toggle';
19+
20+
private _label = this.locatorFor('.mat-button-toggle-label-content');
21+
private _button = this.locatorFor('.mat-button-toggle-button');
22+
23+
/**
24+
* Gets a `HarnessPredicate` that can be used to search for a `MatButtonToggleHarness` that meets
25+
* certain criteria.
26+
* @param options Options for filtering which button toggle instances are considered a match.
27+
* @return a `HarnessPredicate` configured with the given options.
28+
*/
29+
static with(options: ButtonToggleHarnessFilters = {}): HarnessPredicate<MatButtonToggleHarness> {
30+
return new HarnessPredicate(MatButtonToggleHarness, options)
31+
.addOption('text', options.text,
32+
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text))
33+
.addOption('name', options.name,
34+
(harness, name) => HarnessPredicate.stringMatches(harness.getName(), name))
35+
.addOption('checked', options.checked,
36+
async (harness, checked) => (await harness.isChecked()) === checked);
37+
}
38+
39+
/** Gets a boolean promise indicating if the button toggle is checked. */
40+
async isChecked(): Promise<boolean> {
41+
const checked = (await this._button()).getAttribute('aria-pressed');
42+
return coerceBooleanProperty(await checked);
43+
}
44+
45+
/** Gets a boolean promise indicating if the button toggle is disabled. */
46+
async isDisabled(): Promise<boolean> {
47+
const disabled = (await this._button()).getAttribute('disabled');
48+
return coerceBooleanProperty(await disabled);
49+
}
50+
51+
/** Gets a promise for the button toggle's name. */
52+
async getName(): Promise<string | null> {
53+
return (await this._button()).getAttribute('name');
54+
}
55+
56+
/** Gets a promise for the button toggle's aria-label. */
57+
async getAriaLabel(): Promise<string | null> {
58+
return (await this._button()).getAttribute('aria-label');
59+
}
60+
61+
/** Gets a promise for the button toggles's aria-labelledby. */
62+
async getAriaLabelledby(): Promise<string | null> {
63+
return (await this._button()).getAttribute('aria-labelledby');
64+
}
65+
66+
/** Gets a promise for the button toggle's text. */
67+
async getText(): Promise<string> {
68+
return (await this._label()).text();
69+
}
70+
71+
/** Gets the appearance that the button toggle is using. */
72+
async getAppearance(): Promise<MatButtonToggleAppearance> {
73+
const host = await this.host();
74+
const className = 'mat-button-toggle-appearance-standard';
75+
return await host.hasClass(className) ? 'standard' : 'legacy';
76+
}
77+
78+
/** Focuses the toggle. */
79+
async focus(): Promise<void> {
80+
return (await this._button()).focus();
81+
}
82+
83+
/** Blurs the toggle. */
84+
async blur(): Promise<void> {
85+
return (await this._button()).blur();
86+
}
87+
88+
/** Toggle the checked state of the buttons toggle. */
89+
async toggle(): Promise<void> {
90+
return (await this._button()).click();
91+
}
92+
93+
/**
94+
* Puts the button toggle in a checked state by toggling it if it's
95+
* currently unchecked, or doing nothing if it is already checked.
96+
*/
97+
async check(): Promise<void> {
98+
if (!(await this.isChecked())) {
99+
await this.toggle();
100+
}
101+
}
102+
103+
/**
104+
* Puts the button toggle in an unchecked state by toggling it if it's
105+
* currently checked, or doing nothing if it's already unchecked.
106+
*/
107+
async uncheck(): Promise<void> {
108+
if (await this.isChecked()) {
109+
await this.toggle();
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)