Skip to content

Commit d733ee2

Browse files
authored
feat(material/testing): MatChipHarness getAvatar (#22348)
1 parent 71d75f4 commit d733ee2

File tree

12 files changed

+173
-21
lines changed

12 files changed

+173
-21
lines changed

src/material-experimental/mdc-chips/testing/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ ng_test_library(
2323
"//src/cdk/testing",
2424
"//src/cdk/testing/testbed",
2525
"//src/material-experimental/mdc-chips",
26+
"//src/material/icon",
27+
"//src/material/icon/testing",
2628
"@npm//@angular/forms",
2729
],
2830
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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 {HarnessPredicate, ComponentHarness} from '@angular/cdk/testing';
10+
import {ChipAvatarHarnessFilters} from './chip-harness-filters';
11+
12+
/** Harness for interacting with a standard Material chip avatar in tests. */
13+
export class MatChipAvatarHarness extends ComponentHarness {
14+
static hostSelector = '.mat-mdc-chip-avatar';
15+
16+
/**
17+
* Gets a `HarnessPredicate` that can be used to search for a `MatChipAvatarHarness` that meets
18+
* certain criteria.
19+
* @param options Options for filtering which input instances are considered a match.
20+
* @return a `HarnessPredicate` configured with the given options.
21+
*/
22+
static with(options: ChipAvatarHarnessFilters = {}): HarnessPredicate<MatChipAvatarHarness> {
23+
return new HarnessPredicate(MatChipAvatarHarness, options);
24+
}
25+
}

src/material-experimental/mdc-chips/testing/chip-harness-filters.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ export interface ChipRowHarnessFilters extends ChipHarnessFilters {}
3434
export interface ChipSetHarnessFilters extends BaseHarnessFilters {}
3535

3636
export interface ChipRemoveHarnessFilters extends BaseHarnessFilters {}
37+
38+
export interface ChipAvatarHarnessFilters extends BaseHarnessFilters {}

src/material-experimental/mdc-chips/testing/chip-harness.spec.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import {HarnessLoader, parallel} from '@angular/cdk/testing';
22
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
33
import {Component} from '@angular/core';
44
import {ComponentFixture, TestBed} from '@angular/core/testing';
5+
import {MatIconModule} from '@angular/material/icon';
6+
import {MatIconHarness} from '@angular/material/icon/testing';
57
import {MatChipsModule} from '../index';
68
import {MatChipHarness} from './chip-harness';
79

@@ -12,7 +14,7 @@ describe('MatChipHarness', () => {
1214

1315
beforeEach(async () => {
1416
await TestBed.configureTestingModule({
15-
imports: [MatChipsModule],
17+
imports: [MatChipsModule, MatIconModule],
1618
declarations: [ChipHarnessTest],
1719
}).compileComponents();
1820

@@ -55,13 +57,35 @@ describe('MatChipHarness', () => {
5557
expect(await harness.getRemoveButton()).toBeTruthy();
5658
});
5759

60+
it('should find avatar in chip', async () => {
61+
const chip = await loader.getHarness(MatChipHarness.with({
62+
selector: '.mat-mdc-chip-with-avatar'
63+
}));
64+
const avatar = await chip.getAvatar();
65+
expect(avatar).toBeTruthy();
66+
const avatarHost = await avatar?.host();
67+
expect(await avatarHost?.getAttribute('aria-label')).toBe('Coronavirus');
68+
});
69+
70+
it('should find icon in chip', async () => {
71+
const chip = await loader.getHarness(MatChipHarness.with({
72+
selector: '.mat-mdc-chip-with-icon-avatar'
73+
}));
74+
expect(chip).toBeTruthy();
75+
const icon = await chip.getHarness(MatIconHarness);
76+
expect(icon).toBeTruthy();
77+
expect(await icon.getName()).toBe('coronavirus');
78+
});
5879
});
5980

6081
@Component({
6182
template: `
6283
<mat-basic-chip>Basic Chip</mat-basic-chip>
6384
<mat-chip>Chip <span matChipTrailingIcon>trailing_icon</span></mat-chip>
64-
<mat-chip><mat-chip-avatar>B</mat-chip-avatar>Chip with avatar</mat-chip>
85+
<mat-chip class="mat-mdc-chip-with-icon-avatar">
86+
<mat-icon matChipAvatar aria-label="Coronavirus" aria-hidden="false">coronavirus</mat-icon>
87+
Chip with avatar
88+
</mat-chip>
6589
<mat-chip
6690
class="has-remove-button"
6791
disabled>Disabled Chip <span matChipRemove>remove_icon</span>

src/material-experimental/mdc-chips/testing/chip-harness.ts

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

9-
import {ComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
10-
import {ChipHarnessFilters, ChipRemoveHarnessFilters} from './chip-harness-filters';
9+
import {ContentContainerComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
10+
import {MatChipAvatarHarness} from './chip-avatar-harness';
11+
import {
12+
ChipAvatarHarnessFilters,
13+
ChipHarnessFilters,
14+
ChipRemoveHarnessFilters
15+
} from './chip-harness-filters';
1116
import {MatChipRemoveHarness} from './chip-remove-harness';
1217

1318
/** Harness for interacting with a mat-chip in tests. */
14-
export class MatChipHarness extends ComponentHarness {
19+
export class MatChipHarness extends ContentContainerComponentHarness {
1520
static hostSelector = '.mat-mdc-basic-chip, .mat-mdc-chip';
1621

1722
/**
@@ -52,4 +57,12 @@ export class MatChipHarness extends ComponentHarness {
5257
async getRemoveButton(filter: ChipRemoveHarnessFilters = {}): Promise<MatChipRemoveHarness> {
5358
return this.locatorFor(MatChipRemoveHarness.with(filter))();
5459
}
60+
61+
/**
62+
* Gets the avatar inside a chip.
63+
* @param filter Optionally filters which avatars are included.
64+
*/
65+
async getAvatar(filter: ChipAvatarHarnessFilters = {}): Promise<MatChipAvatarHarness | null> {
66+
return this.locatorForOptional(MatChipAvatarHarness.with(filter))();
67+
}
5568
}

src/material/chips/testing/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ ng_test_library(
2929
"//src/cdk/testing/testbed",
3030
"//src/material/chips",
3131
"//src/material/form-field",
32+
"//src/material/icon",
33+
"//src/material/icon/testing",
3234
"@npm//@angular/platform-browser",
3335
],
3436
)
@@ -43,6 +45,8 @@ ng_test_library(
4345
":harness_tests_lib",
4446
":testing",
4547
"//src/material/chips",
48+
"//src/material/icon",
49+
"//src/material/icon/testing",
4650
],
4751
)
4852

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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 {HarnessPredicate, ComponentHarness} from '@angular/cdk/testing';
10+
import {ChipAvatarHarnessFilters} from './chip-harness-filters';
11+
12+
/** Harness for interacting with a standard Material chip avatar in tests. */
13+
export class MatChipAvatarHarness extends ComponentHarness {
14+
static hostSelector = '.mat-chip-avatar';
15+
16+
/**
17+
* Gets a `HarnessPredicate` that can be used to search for a `MatChipAvatarHarness` that meets
18+
* certain criteria.
19+
* @param options Options for filtering which input instances are considered a match.
20+
* @return a `HarnessPredicate` configured with the given options.
21+
*/
22+
static with(options: ChipAvatarHarnessFilters = {}): HarnessPredicate<MatChipAvatarHarness> {
23+
return new HarnessPredicate(MatChipAvatarHarness, options);
24+
}
25+
}

src/material/chips/testing/chip-harness-filters.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,6 @@ export interface ChipInputHarnessFilters extends BaseHarnessFilters {
4141

4242
/** A set of criteria that can be used to filter a list of `MatChipRemoveHarness` instances. */
4343
export interface ChipRemoveHarnessFilters extends BaseHarnessFilters {}
44+
45+
/** A set of criteria that can be used to filter a list of `MatChipAvatarHarness` instances. */
46+
export interface ChipAvatarHarnessFilters extends BaseHarnessFilters {}

src/material/chips/testing/chip-harness.ts

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

9-
import {ComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
10-
import {ChipHarnessFilters, ChipRemoveHarnessFilters} from './chip-harness-filters';
9+
import {ContentContainerComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
10+
import {MatChipAvatarHarness} from './chip-avatar-harness';
11+
import {
12+
ChipAvatarHarnessFilters,
13+
ChipHarnessFilters,
14+
ChipRemoveHarnessFilters
15+
} from './chip-harness-filters';
1116
import {MatChipRemoveHarness} from './chip-remove-harness';
1217

1318
/** Harness for interacting with a standard selectable Angular Material chip in tests. */
14-
export class MatChipHarness extends ComponentHarness {
19+
export class MatChipHarness extends ContentContainerComponentHarness {
1520
/** The selector for the host element of a `MatChip` instance. */
1621
static hostSelector = '.mat-chip';
1722

@@ -88,9 +93,17 @@ export class MatChipHarness extends ComponentHarness {
8893

8994
/**
9095
* Gets the remove button inside of a chip.
91-
* @param filter Optionally filters which chips are included.
96+
* @param filter Optionally filters which remove buttons are included.
9297
*/
9398
async getRemoveButton(filter: ChipRemoveHarnessFilters = {}): Promise<MatChipRemoveHarness> {
9499
return this.locatorFor(MatChipRemoveHarness.with(filter))();
95100
}
101+
102+
/**
103+
* Gets the avatar inside a chip.
104+
* @param filter Optionally filters which avatars are included.
105+
*/
106+
async getAvatar(filter: ChipAvatarHarnessFilters = {}): Promise<MatChipAvatarHarness | null> {
107+
return this.locatorForOptional(MatChipAvatarHarness.with(filter))();
108+
}
96109
}
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import {MatChipsModule} from '@angular/material/chips';
22
import {runHarnessTests} from '@angular/material/chips/testing/shared.spec';
3+
import {MatIconModule} from '@angular/material/icon';
4+
import {MatIconHarness} from '@angular/material/icon/testing';
35
import {MatChipListHarness} from './chip-list-harness';
46
import {MatChipHarness} from './chip-harness';
57
import {MatChipInputHarness} from './chip-input-harness';
@@ -8,6 +10,15 @@ import {MatChipListboxHarness} from './chip-listbox-harness';
810
import {MatChipOptionHarness} from './chip-option-harness';
911

1012
describe('Non-MDC-based MatChipListHarness', () => {
11-
runHarnessTests(MatChipsModule, MatChipListHarness, MatChipListboxHarness, MatChipHarness,
12-
MatChipOptionHarness, MatChipInputHarness, MatChipRemoveHarness);
13+
runHarnessTests(
14+
MatChipsModule,
15+
MatChipListHarness,
16+
MatChipListboxHarness,
17+
MatChipHarness,
18+
MatChipOptionHarness,
19+
MatChipInputHarness,
20+
MatChipRemoveHarness,
21+
MatIconModule,
22+
MatIconHarness
23+
);
1324
});

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

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations';
33
import {HarnessLoader, parallel, TestKey} from '@angular/cdk/testing';
44
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
55
import {ComponentFixture, TestBed} from '@angular/core/testing';
6-
import {MatFormFieldModule} from '@angular/material/form-field';
76
import {MatChipsModule} from '@angular/material/chips';
7+
import {MatFormFieldModule} from '@angular/material/form-field';
8+
import {MatIconModule} from '@angular/material/icon';
9+
import {MatIconHarness} from '@angular/material/icon/testing';
810
import {MatChipListHarness} from './chip-list-harness';
911
import {MatChipHarness} from './chip-harness';
1012
import {MatChipInputHarness} from './chip-input-harness';
@@ -20,13 +22,15 @@ export function runHarnessTests(
2022
chipHarness: typeof MatChipHarness,
2123
chipOptionHarness: typeof MatChipOptionHarness,
2224
chipInputHarness: typeof MatChipInputHarness,
23-
chipRemoveHarness: typeof MatChipRemoveHarness) {
25+
chipRemoveHarness: typeof MatChipRemoveHarness,
26+
iconModule: typeof MatIconModule,
27+
iconHarness: typeof MatIconHarness) {
2428
let fixture: ComponentFixture<ChipsHarnessTest>;
2529
let loader: HarnessLoader;
2630

2731
beforeEach(async () => {
2832
await TestBed.configureTestingModule({
29-
imports: [chipsModule, MatFormFieldModule, NoopAnimationsModule],
33+
imports: [chipsModule, MatFormFieldModule, NoopAnimationsModule, iconModule],
3034
declarations: [ChipsHarnessTest],
3135
}).compileComponents();
3236

@@ -78,7 +82,7 @@ export function runHarnessTests(
7882
]);
7983
});
8084

81-
it('should get whether a chip list is in multi selection mode', async () => {
85+
it('should get whether a chip list is in multi-selection mode', async () => {
8286
const chipLists = await loader.getAllHarnesses(chipListHarness);
8387

8488
expect(await parallel(() => chipLists.map(list => list.isMultiple()))).toEqual([
@@ -193,7 +197,7 @@ export function runHarnessTests(
193197
expect(await chip.isSelected()).toBe(false);
194198
});
195199

196-
it('should get the disabled text of a chip', async () => {
200+
it('should get the disabled state of a chip', async () => {
197201
const chips = await loader.getAllHarnesses(chipHarness);
198202
expect(await parallel(() => chips.map(chip => chip.isDisabled()))).toEqual([
199203
false,
@@ -205,7 +209,7 @@ export function runHarnessTests(
205209
]);
206210
});
207211

208-
it('should get the selected text of a chip', async () => {
212+
it('should get the selected state of a chip', async () => {
209213
const chips = await loader.getAllHarnesses(chipOptionHarness);
210214
expect(await parallel(() => chips.map(chip => chip.isSelected()))).toEqual([
211215
false,
@@ -240,14 +244,14 @@ export function runHarnessTests(
240244
expect(inputs.length).toBe(1);
241245
});
242246

243-
it('should get whether the input input is disabled', async () => {
247+
it('should get whether the chip input is disabled', async () => {
244248
const input = await loader.getHarness(chipInputHarness);
245249
expect(await input.isDisabled()).toBe(false);
246250
fixture.componentInstance.inputDisabled = true;
247251
expect(await input.isDisabled()).toBe(true);
248252
});
249253

250-
it('should get whether the input input is required', async () => {
254+
it('should get whether the chip input is required', async () => {
251255
const input = await loader.getHarness(chipInputHarness);
252256
expect(await input.isRequired()).toBe(false);
253257
fixture.componentInstance.inputRequired = true;
@@ -300,6 +304,25 @@ export function runHarnessTests(
300304
expect(fixture.componentInstance.remove).toHaveBeenCalled();
301305
});
302306

307+
it('should find avatar in chip', async () => {
308+
const chip = await loader.getHarness(chipHarness.with({
309+
selector: '.mat-chip-with-avatar'
310+
}));
311+
const avatar = await chip.getAvatar();
312+
expect(avatar).toBeTruthy();
313+
const avatarHost = await avatar?.host();
314+
expect(await avatarHost?.getAttribute('aria-label')).toBe('Coronavirus');
315+
});
316+
317+
it('should find icon in chip', async () => {
318+
const chip = await loader.getHarness(chipHarness.with({
319+
selector: '.mat-chip-with-icon-avatar'
320+
}));
321+
expect(chip).toBeTruthy();
322+
const icon = await chip.getHarness(iconHarness);
323+
expect(icon).toBeTruthy();
324+
expect(await icon.getName()).toBe('coronavirus');
325+
});
303326
}
304327

305328
@Component({
@@ -317,7 +340,10 @@ export function runHarnessTests(
317340
Chip 3
318341
<span matChipTrailingIcon>trailing_icon</span>
319342
</mat-chip>
320-
<mat-chip (removed)="remove()"><mat-chip-avatar>C</mat-chip-avatar>Chip 4</mat-chip>
343+
<mat-chip class="mat-chip-with-icon-avatar" (removed)="remove()">
344+
<mat-icon matChipAvatar aria-label="Coronavirus" aria-hidden="false">coronavirus</mat-icon>
345+
Chip 4
346+
</mat-chip>
321347
</mat-chip-list>
322348
323349
<mat-chip-list></mat-chip-list>

tools/public_api_guard/material/chips-testing.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
export interface ChipAvatarHarnessFilters extends BaseHarnessFilters {
2+
}
3+
14
export interface ChipHarnessFilters extends BaseHarnessFilters {
25
selected?: boolean;
36
text?: string | RegExp;
@@ -21,8 +24,9 @@ export interface ChipOptionHarnessFilters extends ChipHarnessFilters {
2124
export interface ChipRemoveHarnessFilters extends BaseHarnessFilters {
2225
}
2326

24-
export declare class MatChipHarness extends ComponentHarness {
27+
export declare class MatChipHarness extends ContentContainerComponentHarness {
2528
deselect(): Promise<void>;
29+
getAvatar(filter?: ChipAvatarHarnessFilters): Promise<MatChipAvatarHarness | null>;
2630
getRemoveButton(filter?: ChipRemoveHarnessFilters): Promise<MatChipRemoveHarness>;
2731
getText(): Promise<string>;
2832
isDisabled(): Promise<boolean>;

0 commit comments

Comments
 (0)