Skip to content

Commit

Permalink
feat(badge): add test harness (#17661)
Browse files Browse the repository at this point in the history
Sets up a test harness for the badge directive.
  • Loading branch information
crisbeto authored and jelbourn committed Dec 3, 2019
1 parent acfa174 commit f96e820
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/material/badge/testing/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package(default_visibility = ["//visibility:public"])

load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")

ts_library(
name = "testing",
srcs = glob(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
module_name = "@angular/material/badge/testing",
deps = [
"//src/cdk/testing",
"//src/material/badge",
],
)

filegroup(
name = "source-files",
srcs = glob(["**/*.ts"]),
)

ng_test_library(
name = "harness_tests_lib",
srcs = ["shared.spec.ts"],
deps = [
":testing",
"//src/cdk/testing",
"//src/cdk/testing/testbed",
"//src/material/badge",
"@npm//@angular/platform-browser",
],
)

ng_test_library(
name = "unit_tests_lib",
srcs = glob(
["**/*.spec.ts"],
exclude = ["shared.spec.ts"],
),
deps = [
":harness_tests_lib",
":testing",
"//src/material/badge",
],
)

ng_web_test_suite(
name = "unit_tests",
deps = [":unit_tests_lib"],
)
13 changes: 13 additions & 0 deletions src/material/badge/testing/badge-harness-filters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @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 {BaseHarnessFilters} from '@angular/cdk/testing';

export interface BadgeHarnessFilters extends BaseHarnessFilters {
text?: string | RegExp;
}
7 changes: 7 additions & 0 deletions src/material/badge/testing/badge-harness.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {MatBadgeModule} from '@angular/material/badge';
import {runHarnessTests} from '@angular/material/badge/testing/shared.spec';
import {MatBadgeHarness} from './badge-harness';

describe('Non-MDC-based MatBadgeHarness', () => {
runHarnessTests(MatBadgeModule, MatBadgeHarness);
});
87 changes: 87 additions & 0 deletions src/material/badge/testing/badge-harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* @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 {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
import {MatBadgePosition, MatBadgeSize} from '@angular/material/badge';
import {BadgeHarnessFilters} from './badge-harness-filters';


/**
* Harness for interacting with a standard Material badge in tests.
* @dynamic
*/
export class MatBadgeHarness extends ComponentHarness {
static hostSelector = '.mat-badge';

/**
* Gets a `HarnessPredicate` that can be used to search for a badge with specific attributes.
* @param options Options for narrowing the search:
* - `text` finds a badge host with a particular text.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: BadgeHarnessFilters = {}): HarnessPredicate<MatBadgeHarness> {
return new HarnessPredicate(MatBadgeHarness, options)
.addOption('text', options.text,
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
}

private _badgeElement = this.locatorFor('.mat-badge-content');

/** Gets a promise for the badge text. */
async getText(): Promise<string> {
return (await this._badgeElement()).text();
}

/** Gets whether the badge is overlapping the content. */
async isOverlapping(): Promise<boolean> {
return (await this.host()).hasClass('mat-badge-overlap');
}

/** Gets the position of the badge. */
async getPosition(): Promise<MatBadgePosition> {
const host = await this.host();
let result = '';

if (await host.hasClass('mat-badge-above')) {
result += 'above';
} else if (await host.hasClass('mat-badge-below')) {
result += 'below';
}

if (await host.hasClass('mat-badge-before')) {
result += ' before';
} else if (await host.hasClass('mat-badge-after')) {
result += ' after';
}

return result.trim() as MatBadgePosition;
}

/** Gets the size of the badge. */
async getSize(): Promise<MatBadgeSize> {
const host = await this.host();

if (await host.hasClass('mat-badge-small')) {
return 'small';
} else if (await host.hasClass('mat-badge-large')) {
return 'large';
}

return 'medium';
}

/** Gets whether the badge is hidden. */
async isHidden(): Promise<boolean> {
return (await this.host()).hasClass('mat-badge-hidden');
}

/** Gets whether the badge is disabled. */
async isDisabled(): Promise<boolean> {
return (await this.host()).hasClass('mat-badge-disabled');
}
}
9 changes: 9 additions & 0 deletions src/material/badge/testing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @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
*/

export * from './public-api';
10 changes: 10 additions & 0 deletions src/material/badge/testing/public-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @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
*/

export * from './badge-harness';
export * from './badge-harness-filters';
142 changes: 142 additions & 0 deletions src/material/badge/testing/shared.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {Component} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {MatBadgeModule, MatBadgePosition, MatBadgeSize} from '@angular/material/badge';
import {MatBadgeHarness} from '@angular/material/badge/testing/badge-harness';

/** Shared tests to run on both the original and MDC-based badges. */
export function runHarnessTests(
badgeModule: typeof MatBadgeModule, badgeHarness: typeof MatBadgeHarness) {
let fixture: ComponentFixture<BadgeHarnessTest>;
let loader: HarnessLoader;

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

fixture = TestBed.createComponent(BadgeHarnessTest);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});

it('should load all badge harnesses', async () => {
const badges = await loader.getAllHarnesses(badgeHarness);
expect(badges.length).toBe(6);
});

it('should be able to get the text of a badge', async () => {
const badge = await loader.getHarness(badgeHarness.with({selector: '#simple'}));

expect(await badge.getText()).toBe('Simple badge');
fixture.componentInstance.simpleContent = 'Changed simple badge';
expect(await badge.getText()).toBe('Changed simple badge');
});

it('should load badge with exact text', async () => {
const badges = await loader.getAllHarnesses(badgeHarness.with({text: 'Simple badge'}));
expect(badges.length).toBe(1);
expect(await badges[0].getText()).toBe('Simple badge');
});

it('should load badge with regex label match', async () => {
const badges = await loader.getAllHarnesses(badgeHarness.with({text: /sized|disabled/i}));
expect(badges.length).toBe(2);
expect(await badges[0].getText()).toBe('Sized badge');
expect(await badges[1].getText()).toBe('Disabled badge');
});

it('should get whether a badge is overlapping', async () => {
const badge = await loader.getHarness(badgeHarness.with({selector: '#overlapping'}));

expect(await badge.isOverlapping()).toBe(true);
fixture.componentInstance.overlap = false;
expect(await badge.isOverlapping()).toBe(false);
});

it('should get whether a badge is disabled', async () => {
const badge = await loader.getHarness(badgeHarness.with({selector: '#disabled'}));

expect(await badge.isDisabled()).toBe(true);
fixture.componentInstance.disabled = false;
expect(await badge.isDisabled()).toBe(false);
});

it('should get whether a badge is hidden', async () => {
const badge = await loader.getHarness(badgeHarness.with({selector: '#hidden'}));

expect(await badge.isHidden()).toBe(true);
fixture.componentInstance.hidden = false;
expect(await badge.isHidden()).toBe(false);
});

it('should get the position of a badge', async () => {
const instance = fixture.componentInstance;
const badge = await loader.getHarness(badgeHarness.with({selector: '#positioned'}));

expect(await badge.getPosition()).toBe('above after');

instance.position = 'below';
expect(await badge.getPosition()).toBe('below after');

instance.position = 'below before';
expect(await badge.getPosition()).toBe('below before');

instance.position = 'above';
expect(await badge.getPosition()).toBe('above after');

instance.position = 'above before';
expect(await badge.getPosition()).toBe('above before');
});

it('should get the size of a badge', async () => {
const instance = fixture.componentInstance;
const badge = await loader.getHarness(badgeHarness.with({selector: '#sized'}));

expect(await badge.getSize()).toBe('medium');

instance.size = 'small';
expect(await badge.getSize()).toBe('small');

instance.size = 'large';
expect(await badge.getSize()).toBe('large');
});
}


@Component({
template: `
<button id="simple" [matBadge]="simpleContent">Simple</button>
<button
id="positioned"
matBadge="Positioned badge"
[matBadgePosition]="position">Positioned</button>
<button
id="sized"
matBadge="Sized badge"
[matBadgeSize]="size">Sized</button>
<button
id="overlapping"
matBadge="Overlapping badge"
[matBadgeOverlap]="overlap">Overlapping</button>
<button
id="hidden"
matBadge="Hidden badge"
[matBadgeHidden]="hidden">Hidden</button>
<button
id="disabled"
matBadge="Disabled badge"
[matBadgeDisabled]="disabled">Disabled</button>
`
})
class BadgeHarnessTest {
simpleContent = 'Simple badge';
position: MatBadgePosition = 'above after';
size: MatBadgeSize = 'medium';
overlap = true;
hidden = true;
disabled = true;
}

1 change: 1 addition & 0 deletions src/material/config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ entryPoints = [
"autocomplete",
"autocomplete/testing",
"badge",
"badge/testing",
"bottom-sheet",
"button",
"button/testing",
Expand Down
2 changes: 2 additions & 0 deletions test/karma-system-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ System.config({
'@angular/material/autocomplete/testing': 'dist/packages/material/autocomplete/testing/index.js',
'@angular/material/autocomplete/testing/shared.spec': 'dist/packages/material/autocomplete/testing/shared.spec.js',
'@angular/material/badge': 'dist/packages/material/badge/index.js',
'@angular/material/badge/testing': 'dist/packages/material/badge/testing/index.js',
'@angular/material/badge/testing/shared.spec': 'dist/packages/material/badge/testing/shared.spec.js',
'@angular/material/bottom-sheet': 'dist/packages/material/bottom-sheet/index.js',
'@angular/material/button': 'dist/packages/material/button/index.js',
'@angular/material/button/testing': 'dist/packages/material/button/testing/index.js',
Expand Down
14 changes: 14 additions & 0 deletions tools/public_api_guard/material/badge/testing.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface BadgeHarnessFilters extends BaseHarnessFilters {
text?: string | RegExp;
}

export declare class MatBadgeHarness extends ComponentHarness {
getPosition(): Promise<MatBadgePosition>;
getSize(): Promise<MatBadgeSize>;
getText(): Promise<string>;
isDisabled(): Promise<boolean>;
isHidden(): Promise<boolean>;
isOverlapping(): Promise<boolean>;
static hostSelector: string;
static with(options?: BadgeHarnessFilters): HarnessPredicate<MatBadgeHarness>;
}

0 comments on commit f96e820

Please sign in to comment.