Skip to content

Commit 081d833

Browse files
authored
feat(material/testing): expose whether harness elements are focused (#19704)
Currently we have a bunch of test harnesses that have methods for blurring and focusing the underlying element, but they don't expose whether it currently has focus. These changes add `isFocused` methods to all of the harnesses so they're consistent between each other. Fixes #19702.
1 parent 8ea3558 commit 081d833

File tree

41 files changed

+162
-80
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+162
-80
lines changed

src/material-experimental/mdc-button/testing/button-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,9 @@ export class MatButtonHarness extends ComponentHarness {
6262
async blur(): Promise<void> {
6363
return (await this.host()).blur();
6464
}
65+
66+
/** Whether the button is focused. */
67+
async isFocused(): Promise<boolean> {
68+
return (await this.host()).isFocused();
69+
}
6570
}

src/material-experimental/mdc-checkbox/testing/checkbox-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ export class MatCheckboxHarness extends ComponentHarness {
102102
return (await this._input()).blur();
103103
}
104104

105+
/** Whether the checkbox is focused. */
106+
async isFocused(): Promise<boolean> {
107+
return (await this._input()).isFocused();
108+
}
109+
105110
/**
106111
* Toggle the checked state of the checkbox and returns a void promise that indicates when the
107112
* action is complete.

src/material-experimental/mdc-menu/testing/menu-harness.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ export class MatMenuHarness extends ComponentHarness {
5656
return (await this.host()).blur();
5757
}
5858

59+
/** Whether the menu is focused. */
60+
async isFocused(): Promise<boolean> {
61+
return (await this.host()).isFocused();
62+
}
63+
5964
async open(): Promise<void> {
6065
throw Error('not implemented');
6166
}
@@ -105,16 +110,23 @@ export class MatMenuItemHarness extends ComponentHarness {
105110
return (await this.host()).text();
106111
}
107112

108-
/** Focuses the menu and returns a void promise that indicates when the action is complete. */
113+
/**
114+
* Focuses the menu item and returns a void promise that indicates when the action is complete.
115+
*/
109116
async focus(): Promise<void> {
110117
return (await this.host()).focus();
111118
}
112119

113-
/** Blurs the menu and returns a void promise that indicates when the action is complete. */
120+
/** Blurs the menu item and returns a void promise that indicates when the action is complete. */
114121
async blur(): Promise<void> {
115122
return (await this.host()).blur();
116123
}
117124

125+
/** Whether the menu item is focused. */
126+
async isFocused(): Promise<boolean> {
127+
return (await this.host()).isFocused();
128+
}
129+
118130
async click(): Promise<void> {
119131
throw Error('not implemented');
120132
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ export class MatSlideToggleHarness extends ComponentHarness {
9090
return (await this._input()).blur();
9191
}
9292

93+
/** Whether the slide-toggle is focused. */
94+
async isFocused(): Promise<boolean> {
95+
return (await this._input()).isFocused();
96+
}
97+
9398
/**
9499
* Toggle the checked state of the slide-toggle and returns a void promise that indicates when the
95100
* action is complete.

src/material-experimental/mdc-slider/testing/slider-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ export class MatSliderHarness extends ComponentHarness {
126126
return (await this.host()).blur();
127127
}
128128

129+
/** Whether the slider is focused. */
130+
async isFocused(): Promise<boolean> {
131+
return (await this.host()).isFocused();
132+
}
133+
129134
/** Calculates the percentage of the given value. */
130135
private async _calculatePercentage(value: number) {
131136
const [min, max] = await Promise.all([this.getMinValue(), this.getMaxValue()]);

src/material/autocomplete/testing/autocomplete-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ export class MatAutocompleteHarness extends ComponentHarness {
5656
return (await this.host()).blur();
5757
}
5858

59+
/** Whether the autocomplete input is focused. */
60+
async isFocused(): Promise<boolean> {
61+
return (await this.host()).isFocused();
62+
}
63+
5964
/** Enters text into the autocomplete. */
6065
async enterText(value: string): Promise<void> {
6166
return (await this.host()).sendKeys(value);

src/material/autocomplete/testing/shared.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ export function runHarnessTests(
6363

6464
it('should focus and blur an input', async () => {
6565
const input = await loader.getHarness(autocompleteHarness.with({selector: '#plain'}));
66-
expect(getActiveElementId()).not.toBe('plain');
66+
expect(await input.isFocused()).toBe(false);
6767
await input.focus();
68-
expect(getActiveElementId()).toBe('plain');
68+
expect(await input.isFocused()).toBe(true);
6969
await input.blur();
70-
expect(getActiveElementId()).not.toBe('plain');
70+
expect(await input.isFocused()).toBe(false);
7171
});
7272

7373
it('should be able to type in an input', async () => {
@@ -149,10 +149,6 @@ export function runHarnessTests(
149149
});
150150
}
151151

152-
function getActiveElementId() {
153-
return document.activeElement ? document.activeElement.id : '';
154-
}
155-
156152
@Component({
157153
template: `
158154
<mat-autocomplete #autocomplete="matAutocomplete">

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ export class MatButtonToggleHarness extends ComponentHarness {
8585
return (await this._button()).blur();
8686
}
8787

88+
/** Whether the toggle is focused. */
89+
async isFocused(): Promise<boolean> {
90+
return (await this._button()).isFocused();
91+
}
92+
8893
/** Toggle the checked state of the buttons toggle. */
8994
async toggle(): Promise<void> {
9095
return (await this._button()).click();

src/material/button-toggle/testing/button-toggle-shared.spec.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,17 @@ export function runHarnessTests(
8181

8282
it('should focus the button toggle', async () => {
8383
const toggle = await loader.getHarness(buttonToggleHarness.with({text: 'First'}));
84-
expect(getActiveElementTagName()).not.toBe('button');
84+
expect(await toggle.isFocused()).toBe(false);
8585
await toggle.focus();
86-
expect(getActiveElementTagName()).toBe('button');
86+
expect(await toggle.isFocused()).toBe(true);
8787
});
8888

8989
it('should blur the button toggle', async () => {
9090
const toggle = await loader.getHarness(buttonToggleHarness.with({text: 'First'}));
9191
await toggle.focus();
92-
expect(getActiveElementTagName()).toBe('button');
92+
expect(await toggle.isFocused()).toBe(true);
9393
await toggle.blur();
94-
expect(getActiveElementTagName()).not.toBe('button');
94+
expect(await toggle.isFocused()).toBe(false);
9595
});
9696

9797
it('should toggle the button value', async () => {
@@ -122,10 +122,6 @@ export function runHarnessTests(
122122
});
123123
}
124124

125-
function getActiveElementTagName() {
126-
return document.activeElement ? document.activeElement.tagName.toLowerCase() : '';
127-
}
128-
129125
@Component({
130126
template: `
131127
<mat-button-toggle

src/material/button/testing/button-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,9 @@ export class MatButtonHarness extends ComponentHarness {
6262
async blur(): Promise<void> {
6363
return (await this.host()).blur();
6464
}
65+
66+
/** Whether the button is focused. */
67+
async isFocused(): Promise<boolean> {
68+
return (await this.host()).isFocused();
69+
}
6570
}

src/material/button/testing/shared.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ export function runHarnessTests(
6767

6868
it('should focus and blur a button', async () => {
6969
const button = await loader.getHarness(buttonHarness.with({text: 'Basic button'}));
70-
expect(getActiveElementId()).not.toBe('basic');
70+
expect(await button.isFocused()).toBe(false);
7171
await button.focus();
72-
expect(getActiveElementId()).toBe('basic');
72+
expect(await button.isFocused()).toBe(true);
7373
await button.blur();
74-
expect(getActiveElementId()).not.toBe('basic');
74+
expect(await button.isFocused()).toBe(false);
7575
});
7676

7777
it('should click a button', async () => {
@@ -98,10 +98,6 @@ export function runHarnessTests(
9898
});
9999
}
100100

101-
function getActiveElementId() {
102-
return document.activeElement ? document.activeElement.id : '';
103-
}
104-
105101
@Component({
106102
// Include one of each type of button selector to ensure that they're all captured by
107103
// the harness's selector.

src/material/checkbox/testing/checkbox-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ export class MatCheckboxHarness extends ComponentHarness {
101101
return (await this._input()).blur();
102102
}
103103

104+
/** Whether the checkbox is focused. */
105+
async isFocused(): Promise<boolean> {
106+
return (await this._input()).isFocused();
107+
}
108+
104109
/**
105110
* Toggles the checked state of the checkbox.
106111
*

src/material/checkbox/testing/shared.spec.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,17 @@ export function runHarnessTests(
114114

115115
it('should focus checkbox', async () => {
116116
const checkbox = await loader.getHarness(checkboxHarness.with({label: 'First'}));
117-
expect(getActiveElementTagName()).not.toBe('input');
117+
expect(await checkbox.isFocused()).toBe(false);
118118
await checkbox.focus();
119-
expect(getActiveElementTagName()).toBe('input');
119+
expect(await checkbox.isFocused()).toBe(true);
120120
});
121121

122122
it('should blur checkbox', async () => {
123123
const checkbox = await loader.getHarness(checkboxHarness.with({label: 'First'}));
124124
await checkbox.focus();
125-
expect(getActiveElementTagName()).toBe('input');
125+
expect(await checkbox.isFocused()).toBe(true);
126126
await checkbox.blur();
127-
expect(getActiveElementTagName()).not.toBe('input');
127+
expect(await checkbox.isFocused()).toBe(false);
128128
});
129129

130130
it('should toggle checkbox', async () => {
@@ -167,10 +167,6 @@ export function runHarnessTests(
167167
});
168168
}
169169

170-
function getActiveElementTagName() {
171-
return document.activeElement ? document.activeElement.tagName.toLowerCase() : '';
172-
}
173-
174170
@Component({
175171
template: `
176172
<mat-checkbox

src/material/expansion/testing/expansion-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ export class MatExpansionPanelHarness extends ComponentHarness {
125125
return (await this._header()).blur();
126126
}
127127

128+
/** Whether the panel is focused. */
129+
async isFocused(): Promise<boolean> {
130+
return (await this._header()).isFocused();
131+
}
132+
128133
/** Whether the panel has a toggle indicator displayed. */
129134
async hasToggleIndicator(): Promise<boolean> {
130135
return (await this._expansionIndicator()) !== null;

src/material/input/testing/input-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ export class MatInputHarness extends MatFormFieldControlHarness {
9898
return (await this.host()).blur();
9999
}
100100

101+
/** Whether the input is focused. */
102+
async isFocused(): Promise<boolean> {
103+
return (await this.host()).isFocused();
104+
}
105+
101106
/**
102107
* Sets the value of the input. The value will be set by simulating
103108
* keypresses that correspond to the given value.

src/material/input/testing/shared.spec.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -168,18 +168,18 @@ export function runHarnessTests(
168168

169169
it('should be able to focus input', async () => {
170170
const input = await loader.getHarness(inputHarness.with({selector: '[name="favorite-food"]'}));
171-
expect(getActiveElementTagName()).not.toBe('input');
171+
expect(await input.isFocused()).toBe(false);
172172
await input.focus();
173-
expect(getActiveElementTagName()).toBe('input');
173+
expect(await input.isFocused()).toBe(true);
174174
});
175175

176176
it('should be able to blur input', async () => {
177177
const input = await loader.getHarness(inputHarness.with({selector: '[name="favorite-food"]'}));
178-
expect(getActiveElementTagName()).not.toBe('input');
178+
expect(await input.isFocused()).toBe(false);
179179
await input.focus();
180-
expect(getActiveElementTagName()).toBe('input');
180+
expect(await input.isFocused()).toBe(true);
181181
await input.blur();
182-
expect(getActiveElementTagName()).not.toBe('input');
182+
expect(await input.isFocused()).toBe(false);
183183
});
184184

185185
it('should be able to set the value of a control that cannot be typed in', async () => {
@@ -195,10 +195,6 @@ export function runHarnessTests(
195195
});
196196
}
197197

198-
function getActiveElementTagName() {
199-
return document.activeElement ? document.activeElement.tagName.toLowerCase() : '';
200-
}
201-
202198
@Component({
203199
template: `
204200
<mat-form-field>

src/material/list/testing/action-list-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,9 @@ export class MatActionListItemHarness extends MatListItemHarnessBase {
6262
async blur(): Promise<void> {
6363
return (await this.host()).blur();
6464
}
65+
66+
/** Whether the action list item is focused. */
67+
async isFocused(): Promise<boolean> {
68+
return (await this.host()).isFocused();
69+
}
6570
}

src/material/list/testing/nav-list-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,9 @@ export class MatNavListItemHarness extends MatListItemHarnessBase {
6868
async blur(): Promise<void> {
6969
return (await this.host()).blur();
7070
}
71+
72+
/** Whether the nav list item is focused. */
73+
async isFocused(): Promise<boolean> {
74+
return (await this.host()).isFocused();
75+
}
7176
}

src/material/list/testing/selection-list-harness.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ export class MatListOptionHarness extends MatListItemHarnessBase {
112112
return (await this.host()).blur();
113113
}
114114

115+
/** Whether the list option is focused. */
116+
async isFocused(): Promise<boolean> {
117+
return (await this.host()).isFocused();
118+
}
119+
115120
/** Toggles the checked state of the checkbox. */
116121
async toggle() {
117122
return (await this.host()).click();

src/material/menu/testing/menu-harness.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ export class MatMenuHarness extends ComponentHarness {
5757
return (await this.host()).blur();
5858
}
5959

60+
/** Whether the menu is focused. */
61+
async isFocused(): Promise<boolean> {
62+
return (await this.host()).isFocused();
63+
}
64+
6065
/** Opens the menu. */
6166
async open(): Promise<void> {
6267
if (!await this.isOpen()) {
@@ -168,6 +173,11 @@ export class MatMenuItemHarness extends ComponentHarness {
168173
return (await this.host()).blur();
169174
}
170175

176+
/** Whether the menu item is focused. */
177+
async isFocused(): Promise<boolean> {
178+
return (await this.host()).isFocused();
179+
}
180+
171181
/** Clicks the menu item. */
172182
async click(): Promise<void> {
173183
return (await this.host()).click();

src/material/menu/testing/shared.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ export function runHarnessTests(
6262

6363
it('should focus and blur a menu', async () => {
6464
const menu = await loader.getHarness(menuHarness.with({triggerText: 'Settings'}));
65-
expect(getActiveElementId()).not.toBe('settings');
65+
expect(await menu.isFocused()).toBe(false);
6666
await menu.focus();
67-
expect(getActiveElementId()).toBe('settings');
67+
expect(await menu.isFocused()).toBe(true);
6868
await menu.blur();
69-
expect(getActiveElementId()).not.toBe('settings');
69+
expect(await menu.isFocused()).toBe(false);
7070
});
7171

7272
it('should open and close', async () => {
@@ -172,10 +172,6 @@ export function runHarnessTests(
172172
});
173173
}
174174

175-
function getActiveElementId() {
176-
return document.activeElement ? document.activeElement.id : '';
177-
}
178-
179175
@Component({
180176
template: `
181177
<button type="button" id="settings" [matMenuTriggerFor]="settingsMenu">Settings</button>

0 commit comments

Comments
 (0)