Skip to content

Commit

Permalink
feat(material/testing): MatChipHarness getAvatar (#22348)
Browse files Browse the repository at this point in the history
  • Loading branch information
tamas-nemeth authored Jul 12, 2021
1 parent 71d75f4 commit d733ee2
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 21 deletions.
2 changes: 2 additions & 0 deletions src/material-experimental/mdc-chips/testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ ng_test_library(
"//src/cdk/testing",
"//src/cdk/testing/testbed",
"//src/material-experimental/mdc-chips",
"//src/material/icon",
"//src/material/icon/testing",
"@npm//@angular/forms",
],
)
Expand Down
25 changes: 25 additions & 0 deletions src/material-experimental/mdc-chips/testing/chip-avatar-harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {HarnessPredicate, ComponentHarness} from '@angular/cdk/testing';
import {ChipAvatarHarnessFilters} from './chip-harness-filters';

/** Harness for interacting with a standard Material chip avatar in tests. */
export class MatChipAvatarHarness extends ComponentHarness {
static hostSelector = '.mat-mdc-chip-avatar';

/**
* Gets a `HarnessPredicate` that can be used to search for a `MatChipAvatarHarness` that meets
* certain criteria.
* @param options Options for filtering which input instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: ChipAvatarHarnessFilters = {}): HarnessPredicate<MatChipAvatarHarness> {
return new HarnessPredicate(MatChipAvatarHarness, options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ export interface ChipRowHarnessFilters extends ChipHarnessFilters {}
export interface ChipSetHarnessFilters extends BaseHarnessFilters {}

export interface ChipRemoveHarnessFilters extends BaseHarnessFilters {}

export interface ChipAvatarHarnessFilters extends BaseHarnessFilters {}
28 changes: 26 additions & 2 deletions src/material-experimental/mdc-chips/testing/chip-harness.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {HarnessLoader, parallel} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {Component} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {MatIconModule} from '@angular/material/icon';
import {MatIconHarness} from '@angular/material/icon/testing';
import {MatChipsModule} from '../index';
import {MatChipHarness} from './chip-harness';

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

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MatChipsModule],
imports: [MatChipsModule, MatIconModule],
declarations: [ChipHarnessTest],
}).compileComponents();

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

it('should find avatar in chip', async () => {
const chip = await loader.getHarness(MatChipHarness.with({
selector: '.mat-mdc-chip-with-avatar'
}));
const avatar = await chip.getAvatar();
expect(avatar).toBeTruthy();
const avatarHost = await avatar?.host();
expect(await avatarHost?.getAttribute('aria-label')).toBe('Coronavirus');
});

it('should find icon in chip', async () => {
const chip = await loader.getHarness(MatChipHarness.with({
selector: '.mat-mdc-chip-with-icon-avatar'
}));
expect(chip).toBeTruthy();
const icon = await chip.getHarness(MatIconHarness);
expect(icon).toBeTruthy();
expect(await icon.getName()).toBe('coronavirus');
});
});

@Component({
template: `
<mat-basic-chip>Basic Chip</mat-basic-chip>
<mat-chip>Chip <span matChipTrailingIcon>trailing_icon</span></mat-chip>
<mat-chip><mat-chip-avatar>B</mat-chip-avatar>Chip with avatar</mat-chip>
<mat-chip class="mat-mdc-chip-with-icon-avatar">
<mat-icon matChipAvatar aria-label="Coronavirus" aria-hidden="false">coronavirus</mat-icon>
Chip with avatar
</mat-chip>
<mat-chip
class="has-remove-button"
disabled>Disabled Chip <span matChipRemove>remove_icon</span>
Expand Down
19 changes: 16 additions & 3 deletions src/material-experimental/mdc-chips/testing/chip-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@
* found in the LICENSE file at https://angular.io/license
*/

import {ComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
import {ChipHarnessFilters, ChipRemoveHarnessFilters} from './chip-harness-filters';
import {ContentContainerComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
import {MatChipAvatarHarness} from './chip-avatar-harness';
import {
ChipAvatarHarnessFilters,
ChipHarnessFilters,
ChipRemoveHarnessFilters
} from './chip-harness-filters';
import {MatChipRemoveHarness} from './chip-remove-harness';

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

/**
Expand Down Expand Up @@ -52,4 +57,12 @@ export class MatChipHarness extends ComponentHarness {
async getRemoveButton(filter: ChipRemoveHarnessFilters = {}): Promise<MatChipRemoveHarness> {
return this.locatorFor(MatChipRemoveHarness.with(filter))();
}

/**
* Gets the avatar inside a chip.
* @param filter Optionally filters which avatars are included.
*/
async getAvatar(filter: ChipAvatarHarnessFilters = {}): Promise<MatChipAvatarHarness | null> {
return this.locatorForOptional(MatChipAvatarHarness.with(filter))();
}
}
4 changes: 4 additions & 0 deletions src/material/chips/testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ ng_test_library(
"//src/cdk/testing/testbed",
"//src/material/chips",
"//src/material/form-field",
"//src/material/icon",
"//src/material/icon/testing",
"@npm//@angular/platform-browser",
],
)
Expand All @@ -43,6 +45,8 @@ ng_test_library(
":harness_tests_lib",
":testing",
"//src/material/chips",
"//src/material/icon",
"//src/material/icon/testing",
],
)

Expand Down
25 changes: 25 additions & 0 deletions src/material/chips/testing/chip-avatar-harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {HarnessPredicate, ComponentHarness} from '@angular/cdk/testing';
import {ChipAvatarHarnessFilters} from './chip-harness-filters';

/** Harness for interacting with a standard Material chip avatar in tests. */
export class MatChipAvatarHarness extends ComponentHarness {
static hostSelector = '.mat-chip-avatar';

/**
* Gets a `HarnessPredicate` that can be used to search for a `MatChipAvatarHarness` that meets
* certain criteria.
* @param options Options for filtering which input instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: ChipAvatarHarnessFilters = {}): HarnessPredicate<MatChipAvatarHarness> {
return new HarnessPredicate(MatChipAvatarHarness, options);
}
}
3 changes: 3 additions & 0 deletions src/material/chips/testing/chip-harness-filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ export interface ChipInputHarnessFilters extends BaseHarnessFilters {

/** A set of criteria that can be used to filter a list of `MatChipRemoveHarness` instances. */
export interface ChipRemoveHarnessFilters extends BaseHarnessFilters {}

/** A set of criteria that can be used to filter a list of `MatChipAvatarHarness` instances. */
export interface ChipAvatarHarnessFilters extends BaseHarnessFilters {}
21 changes: 17 additions & 4 deletions src/material/chips/testing/chip-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@
* found in the LICENSE file at https://angular.io/license
*/

import {ComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
import {ChipHarnessFilters, ChipRemoveHarnessFilters} from './chip-harness-filters';
import {ContentContainerComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing';
import {MatChipAvatarHarness} from './chip-avatar-harness';
import {
ChipAvatarHarnessFilters,
ChipHarnessFilters,
ChipRemoveHarnessFilters
} from './chip-harness-filters';
import {MatChipRemoveHarness} from './chip-remove-harness';

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

Expand Down Expand Up @@ -88,9 +93,17 @@ export class MatChipHarness extends ComponentHarness {

/**
* Gets the remove button inside of a chip.
* @param filter Optionally filters which chips are included.
* @param filter Optionally filters which remove buttons are included.
*/
async getRemoveButton(filter: ChipRemoveHarnessFilters = {}): Promise<MatChipRemoveHarness> {
return this.locatorFor(MatChipRemoveHarness.with(filter))();
}

/**
* Gets the avatar inside a chip.
* @param filter Optionally filters which avatars are included.
*/
async getAvatar(filter: ChipAvatarHarnessFilters = {}): Promise<MatChipAvatarHarness | null> {
return this.locatorForOptional(MatChipAvatarHarness.with(filter))();
}
}
15 changes: 13 additions & 2 deletions src/material/chips/testing/chip-list-harness.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {MatChipsModule} from '@angular/material/chips';
import {runHarnessTests} from '@angular/material/chips/testing/shared.spec';
import {MatIconModule} from '@angular/material/icon';
import {MatIconHarness} from '@angular/material/icon/testing';
import {MatChipListHarness} from './chip-list-harness';
import {MatChipHarness} from './chip-harness';
import {MatChipInputHarness} from './chip-input-harness';
Expand All @@ -8,6 +10,15 @@ import {MatChipListboxHarness} from './chip-listbox-harness';
import {MatChipOptionHarness} from './chip-option-harness';

describe('Non-MDC-based MatChipListHarness', () => {
runHarnessTests(MatChipsModule, MatChipListHarness, MatChipListboxHarness, MatChipHarness,
MatChipOptionHarness, MatChipInputHarness, MatChipRemoveHarness);
runHarnessTests(
MatChipsModule,
MatChipListHarness,
MatChipListboxHarness,
MatChipHarness,
MatChipOptionHarness,
MatChipInputHarness,
MatChipRemoveHarness,
MatIconModule,
MatIconHarness
);
});
44 changes: 35 additions & 9 deletions src/material/chips/testing/shared.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {HarnessLoader, parallel, TestKey} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatChipsModule} from '@angular/material/chips';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatIconModule} from '@angular/material/icon';
import {MatIconHarness} from '@angular/material/icon/testing';
import {MatChipListHarness} from './chip-list-harness';
import {MatChipHarness} from './chip-harness';
import {MatChipInputHarness} from './chip-input-harness';
Expand All @@ -20,13 +22,15 @@ export function runHarnessTests(
chipHarness: typeof MatChipHarness,
chipOptionHarness: typeof MatChipOptionHarness,
chipInputHarness: typeof MatChipInputHarness,
chipRemoveHarness: typeof MatChipRemoveHarness) {
chipRemoveHarness: typeof MatChipRemoveHarness,
iconModule: typeof MatIconModule,
iconHarness: typeof MatIconHarness) {
let fixture: ComponentFixture<ChipsHarnessTest>;
let loader: HarnessLoader;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [chipsModule, MatFormFieldModule, NoopAnimationsModule],
imports: [chipsModule, MatFormFieldModule, NoopAnimationsModule, iconModule],
declarations: [ChipsHarnessTest],
}).compileComponents();

Expand Down Expand Up @@ -78,7 +82,7 @@ export function runHarnessTests(
]);
});

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

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

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

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

it('should get whether the input input is disabled', async () => {
it('should get whether the chip input is disabled', async () => {
const input = await loader.getHarness(chipInputHarness);
expect(await input.isDisabled()).toBe(false);
fixture.componentInstance.inputDisabled = true;
expect(await input.isDisabled()).toBe(true);
});

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

it('should find avatar in chip', async () => {
const chip = await loader.getHarness(chipHarness.with({
selector: '.mat-chip-with-avatar'
}));
const avatar = await chip.getAvatar();
expect(avatar).toBeTruthy();
const avatarHost = await avatar?.host();
expect(await avatarHost?.getAttribute('aria-label')).toBe('Coronavirus');
});

it('should find icon in chip', async () => {
const chip = await loader.getHarness(chipHarness.with({
selector: '.mat-chip-with-icon-avatar'
}));
expect(chip).toBeTruthy();
const icon = await chip.getHarness(iconHarness);
expect(icon).toBeTruthy();
expect(await icon.getName()).toBe('coronavirus');
});
}

@Component({
Expand All @@ -317,7 +340,10 @@ export function runHarnessTests(
Chip 3
<span matChipTrailingIcon>trailing_icon</span>
</mat-chip>
<mat-chip (removed)="remove()"><mat-chip-avatar>C</mat-chip-avatar>Chip 4</mat-chip>
<mat-chip class="mat-chip-with-icon-avatar" (removed)="remove()">
<mat-icon matChipAvatar aria-label="Coronavirus" aria-hidden="false">coronavirus</mat-icon>
Chip 4
</mat-chip>
</mat-chip-list>
<mat-chip-list></mat-chip-list>
Expand Down
6 changes: 5 additions & 1 deletion tools/public_api_guard/material/chips-testing.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export interface ChipAvatarHarnessFilters extends BaseHarnessFilters {
}

export interface ChipHarnessFilters extends BaseHarnessFilters {
selected?: boolean;
text?: string | RegExp;
Expand All @@ -21,8 +24,9 @@ export interface ChipOptionHarnessFilters extends ChipHarnessFilters {
export interface ChipRemoveHarnessFilters extends BaseHarnessFilters {
}

export declare class MatChipHarness extends ComponentHarness {
export declare class MatChipHarness extends ContentContainerComponentHarness {
deselect(): Promise<void>;
getAvatar(filter?: ChipAvatarHarnessFilters): Promise<MatChipAvatarHarness | null>;
getRemoveButton(filter?: ChipRemoveHarnessFilters): Promise<MatChipRemoveHarness>;
getText(): Promise<string>;
isDisabled(): Promise<boolean>;
Expand Down

0 comments on commit d733ee2

Please sign in to comment.