Skip to content

Commit

Permalink
feat(material/button): add variant to button harness (#25770)
Browse files Browse the repository at this point in the history
Adds the ability to get the variant of a button harness and to filter by it.

Fixes #25755.
  • Loading branch information
crisbeto committed Oct 7, 2022
1 parent 72547a4 commit 87e17aa
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 12 deletions.
6 changes: 6 additions & 0 deletions src/material/button/testing/button-harness-filters.ts
Expand Up @@ -8,8 +8,14 @@

import {BaseHarnessFilters} from '@angular/cdk/testing';

/** Possible button appearances. */
export type ButtonVariant = 'basic' | 'raised' | 'flat' | 'icon' | 'stroked' | 'fab' | 'mini-fab';

/** A set of criteria that can be used to filter a list of button harness instances. */
export interface ButtonHarnessFilters extends BaseHarnessFilters {
/** Only find instances whose text matches the given value. */
text?: string | RegExp;

/** Only find instances with a variant. */
variant?: ButtonVariant;
}
34 changes: 30 additions & 4 deletions src/material/button/testing/button-harness.ts
Expand Up @@ -12,7 +12,7 @@ import {
HarnessPredicate,
} from '@angular/cdk/testing';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {ButtonHarnessFilters} from './button-harness-filters';
import {ButtonHarnessFilters, ButtonVariant} from './button-harness-filters';

/** Harness for interacting with a MDC-based mat-button in tests. */
export class MatButtonHarness extends ContentContainerComponentHarness {
Expand All @@ -25,15 +25,20 @@ export class MatButtonHarness extends ContentContainerComponentHarness {
* @param options Options for narrowing the search:
* - `selector` finds a button whose host element matches the given selector.
* - `text` finds a button with specific text content.
* - `variant` finds buttons matching a specific variant.
* @return a `HarnessPredicate` configured with the given options.
*/
static with<T extends MatButtonHarness>(
this: ComponentHarnessConstructor<T>,
options: ButtonHarnessFilters = {},
): HarnessPredicate<T> {
return new HarnessPredicate(this, options).addOption('text', options.text, (harness, text) =>
HarnessPredicate.stringMatches(harness.getText(), text),
);
return new HarnessPredicate(this, options)
.addOption('text', options.text, (harness, text) =>
HarnessPredicate.stringMatches(harness.getText(), text),
)
.addOption('variant', options.variant, (harness, variant) =>
HarnessPredicate.stringMatches(harness.getVariant(), variant),
);
}

/**
Expand Down Expand Up @@ -75,4 +80,25 @@ export class MatButtonHarness extends ContentContainerComponentHarness {
async isFocused(): Promise<boolean> {
return (await this.host()).isFocused();
}

/** Gets the variant of the button. */
async getVariant(): Promise<ButtonVariant> {
const host = await this.host();

if ((await host.getAttribute('mat-raised-button')) != null) {
return 'raised';
} else if ((await host.getAttribute('mat-flat-button')) != null) {
return 'flat';
} else if ((await host.getAttribute('mat-icon-button')) != null) {
return 'icon';
} else if ((await host.getAttribute('mat-stroked-button')) != null) {
return 'stroked';
} else if ((await host.getAttribute('mat-fab')) != null) {
return 'fab';
} else if ((await host.getAttribute('mat-mini-fab')) != null) {
return 'mini-fab';
}

return 'basic';
}
}
30 changes: 29 additions & 1 deletion src/material/button/testing/shared.spec.ts
@@ -1,5 +1,5 @@
import {Platform, PlatformModule} from '@angular/cdk/platform';
import {HarnessLoader} from '@angular/cdk/testing';
import {HarnessLoader, parallel} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {Component} from '@angular/core';
import {ComponentFixture, inject, TestBed} from '@angular/core/testing';
Expand Down Expand Up @@ -113,6 +113,34 @@ export function runHarnessTests(
expect(await homeIcon.getName()).toBe('home');
expect(await favIcon.getName()).toBe('favorite');
});

it('should load all button harnesses', async () => {
const buttons = await loader.getAllHarnesses(buttonHarness);
const variants = await parallel(() => buttons.map(button => button.getVariant()));

expect(variants).toEqual([
'basic',
'flat',
'raised',
'stroked',
'icon',
'icon',
'fab',
'mini-fab',
'basic',
'flat',
'raised',
'stroked',
'icon',
'fab',
'mini-fab',
]);
});

it('should be able to filter buttons based on their variant', async () => {
const button = await loader.getHarness(buttonHarness.with({variant: 'flat'}));
expect(await button.getText()).toBe('Flat button');
});
}

@Component({
Expand Down
35 changes: 29 additions & 6 deletions src/material/legacy-button/testing/button-harness.ts
Expand Up @@ -8,7 +8,7 @@

import {ContentContainerComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {ButtonHarnessFilters} from '@angular/material/button/testing';
import {ButtonHarnessFilters, ButtonVariant} from '@angular/material/button/testing';

/**
* Harness for interacting with a standard mat-button in tests.
Expand All @@ -28,11 +28,13 @@ export class MatLegacyButtonHarness extends ContentContainerComponentHarness {
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: ButtonHarnessFilters = {}): HarnessPredicate<MatLegacyButtonHarness> {
return new HarnessPredicate(MatLegacyButtonHarness, options).addOption(
'text',
options.text,
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text),
);
return new HarnessPredicate(MatLegacyButtonHarness, options)
.addOption('text', options.text, (harness, text) =>
HarnessPredicate.stringMatches(harness.getText(), text),
)
.addOption('variant', options.variant, (harness, variant) =>
HarnessPredicate.stringMatches(harness.getVariant(), variant),
);
}

/**
Expand Down Expand Up @@ -74,4 +76,25 @@ export class MatLegacyButtonHarness extends ContentContainerComponentHarness {
async isFocused(): Promise<boolean> {
return (await this.host()).isFocused();
}

/** Gets the variant of the button. */
async getVariant(): Promise<ButtonVariant> {
const host = await this.host();

if ((await host.getAttribute('mat-raised-button')) != null) {
return 'raised';
} else if ((await host.getAttribute('mat-flat-button')) != null) {
return 'flat';
} else if ((await host.getAttribute('mat-icon-button')) != null) {
return 'icon';
} else if ((await host.getAttribute('mat-stroked-button')) != null) {
return 'stroked';
} else if ((await host.getAttribute('mat-fab')) != null) {
return 'fab';
} else if ((await host.getAttribute('mat-mini-fab')) != null) {
return 'mini-fab';
}

return 'basic';
}
}
5 changes: 4 additions & 1 deletion src/material/legacy-button/testing/public-api.ts
Expand Up @@ -7,4 +7,7 @@
*/

export {MatLegacyButtonHarness} from './button-harness';
export {ButtonHarnessFilters as LegacyButtonHarnessFilters} from '@angular/material/button/testing';
export {
ButtonHarnessFilters as LegacyButtonHarnessFilters,
ButtonVariant as LegacyButtonVariant,
} from '@angular/material/button/testing';
5 changes: 5 additions & 0 deletions tools/public_api_guard/material/button-testing.md
Expand Up @@ -12,8 +12,12 @@ import { HarnessPredicate } from '@angular/cdk/testing';
// @public
export interface ButtonHarnessFilters extends BaseHarnessFilters {
text?: string | RegExp;
variant?: ButtonVariant;
}

// @public
export type ButtonVariant = 'basic' | 'raised' | 'flat' | 'icon' | 'stroked' | 'fab' | 'mini-fab';

// @public
export class MatButtonHarness extends ContentContainerComponentHarness {
blur(): Promise<void>;
Expand All @@ -22,6 +26,7 @@ export class MatButtonHarness extends ContentContainerComponentHarness {
click(): Promise<void>;
focus(): Promise<void>;
getText(): Promise<string>;
getVariant(): Promise<ButtonVariant>;
// (undocumented)
static hostSelector: string;
isDisabled(): Promise<boolean>;
Expand Down
4 changes: 4 additions & 0 deletions tools/public_api_guard/material/legacy-button-testing.md
Expand Up @@ -7,9 +7,12 @@
import { ContentContainerComponentHarness } from '@angular/cdk/testing';
import { HarnessPredicate } from '@angular/cdk/testing';
import { ButtonHarnessFilters as LegacyButtonHarnessFilters } from '@angular/material/button/testing';
import { ButtonVariant as LegacyButtonVariant } from '@angular/material/button/testing';

export { LegacyButtonHarnessFilters }

export { LegacyButtonVariant }

// @public @deprecated
export class MatLegacyButtonHarness extends ContentContainerComponentHarness {
blur(): Promise<void>;
Expand All @@ -18,6 +21,7 @@ export class MatLegacyButtonHarness extends ContentContainerComponentHarness {
click(): Promise<void>;
focus(): Promise<void>;
getText(): Promise<string>;
getVariant(): Promise<LegacyButtonVariant>;
static hostSelector: string;
isDisabled(): Promise<boolean>;
isFocused(): Promise<boolean>;
Expand Down

0 comments on commit 87e17aa

Please sign in to comment.