Skip to content

Commit f96e820

Browse files
crisbetojelbourn
authored andcommitted
feat(badge): add test harness (#17661)
Sets up a test harness for the badge directive.
1 parent acfa174 commit f96e820

File tree

10 files changed

+336
-0
lines changed

10 files changed

+336
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")
4+
5+
ts_library(
6+
name = "testing",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
module_name = "@angular/material/badge/testing",
12+
deps = [
13+
"//src/cdk/testing",
14+
"//src/material/badge",
15+
],
16+
)
17+
18+
filegroup(
19+
name = "source-files",
20+
srcs = glob(["**/*.ts"]),
21+
)
22+
23+
ng_test_library(
24+
name = "harness_tests_lib",
25+
srcs = ["shared.spec.ts"],
26+
deps = [
27+
":testing",
28+
"//src/cdk/testing",
29+
"//src/cdk/testing/testbed",
30+
"//src/material/badge",
31+
"@npm//@angular/platform-browser",
32+
],
33+
)
34+
35+
ng_test_library(
36+
name = "unit_tests_lib",
37+
srcs = glob(
38+
["**/*.spec.ts"],
39+
exclude = ["shared.spec.ts"],
40+
),
41+
deps = [
42+
":harness_tests_lib",
43+
":testing",
44+
"//src/material/badge",
45+
],
46+
)
47+
48+
ng_web_test_suite(
49+
name = "unit_tests",
50+
deps = [":unit_tests_lib"],
51+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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 {BaseHarnessFilters} from '@angular/cdk/testing';
10+
11+
export interface BadgeHarnessFilters extends BaseHarnessFilters {
12+
text?: string | RegExp;
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {MatBadgeModule} from '@angular/material/badge';
2+
import {runHarnessTests} from '@angular/material/badge/testing/shared.spec';
3+
import {MatBadgeHarness} from './badge-harness';
4+
5+
describe('Non-MDC-based MatBadgeHarness', () => {
6+
runHarnessTests(MatBadgeModule, MatBadgeHarness);
7+
});
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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 {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10+
import {MatBadgePosition, MatBadgeSize} from '@angular/material/badge';
11+
import {BadgeHarnessFilters} from './badge-harness-filters';
12+
13+
14+
/**
15+
* Harness for interacting with a standard Material badge in tests.
16+
* @dynamic
17+
*/
18+
export class MatBadgeHarness extends ComponentHarness {
19+
static hostSelector = '.mat-badge';
20+
21+
/**
22+
* Gets a `HarnessPredicate` that can be used to search for a badge with specific attributes.
23+
* @param options Options for narrowing the search:
24+
* - `text` finds a badge host with a particular text.
25+
* @return a `HarnessPredicate` configured with the given options.
26+
*/
27+
static with(options: BadgeHarnessFilters = {}): HarnessPredicate<MatBadgeHarness> {
28+
return new HarnessPredicate(MatBadgeHarness, options)
29+
.addOption('text', options.text,
30+
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
31+
}
32+
33+
private _badgeElement = this.locatorFor('.mat-badge-content');
34+
35+
/** Gets a promise for the badge text. */
36+
async getText(): Promise<string> {
37+
return (await this._badgeElement()).text();
38+
}
39+
40+
/** Gets whether the badge is overlapping the content. */
41+
async isOverlapping(): Promise<boolean> {
42+
return (await this.host()).hasClass('mat-badge-overlap');
43+
}
44+
45+
/** Gets the position of the badge. */
46+
async getPosition(): Promise<MatBadgePosition> {
47+
const host = await this.host();
48+
let result = '';
49+
50+
if (await host.hasClass('mat-badge-above')) {
51+
result += 'above';
52+
} else if (await host.hasClass('mat-badge-below')) {
53+
result += 'below';
54+
}
55+
56+
if (await host.hasClass('mat-badge-before')) {
57+
result += ' before';
58+
} else if (await host.hasClass('mat-badge-after')) {
59+
result += ' after';
60+
}
61+
62+
return result.trim() as MatBadgePosition;
63+
}
64+
65+
/** Gets the size of the badge. */
66+
async getSize(): Promise<MatBadgeSize> {
67+
const host = await this.host();
68+
69+
if (await host.hasClass('mat-badge-small')) {
70+
return 'small';
71+
} else if (await host.hasClass('mat-badge-large')) {
72+
return 'large';
73+
}
74+
75+
return 'medium';
76+
}
77+
78+
/** Gets whether the badge is hidden. */
79+
async isHidden(): Promise<boolean> {
80+
return (await this.host()).hasClass('mat-badge-hidden');
81+
}
82+
83+
/** Gets whether the badge is disabled. */
84+
async isDisabled(): Promise<boolean> {
85+
return (await this.host()).hasClass('mat-badge-disabled');
86+
}
87+
}

src/material/badge/testing/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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+
export * from './public-api';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
export * from './badge-harness';
10+
export * from './badge-harness-filters';
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import {HarnessLoader} from '@angular/cdk/testing';
2+
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
3+
import {Component} from '@angular/core';
4+
import {ComponentFixture, TestBed} from '@angular/core/testing';
5+
import {MatBadgeModule, MatBadgePosition, MatBadgeSize} from '@angular/material/badge';
6+
import {MatBadgeHarness} from '@angular/material/badge/testing/badge-harness';
7+
8+
/** Shared tests to run on both the original and MDC-based badges. */
9+
export function runHarnessTests(
10+
badgeModule: typeof MatBadgeModule, badgeHarness: typeof MatBadgeHarness) {
11+
let fixture: ComponentFixture<BadgeHarnessTest>;
12+
let loader: HarnessLoader;
13+
14+
beforeEach(async () => {
15+
await TestBed.configureTestingModule({
16+
imports: [badgeModule],
17+
declarations: [BadgeHarnessTest],
18+
}).compileComponents();
19+
20+
fixture = TestBed.createComponent(BadgeHarnessTest);
21+
fixture.detectChanges();
22+
loader = TestbedHarnessEnvironment.loader(fixture);
23+
});
24+
25+
it('should load all badge harnesses', async () => {
26+
const badges = await loader.getAllHarnesses(badgeHarness);
27+
expect(badges.length).toBe(6);
28+
});
29+
30+
it('should be able to get the text of a badge', async () => {
31+
const badge = await loader.getHarness(badgeHarness.with({selector: '#simple'}));
32+
33+
expect(await badge.getText()).toBe('Simple badge');
34+
fixture.componentInstance.simpleContent = 'Changed simple badge';
35+
expect(await badge.getText()).toBe('Changed simple badge');
36+
});
37+
38+
it('should load badge with exact text', async () => {
39+
const badges = await loader.getAllHarnesses(badgeHarness.with({text: 'Simple badge'}));
40+
expect(badges.length).toBe(1);
41+
expect(await badges[0].getText()).toBe('Simple badge');
42+
});
43+
44+
it('should load badge with regex label match', async () => {
45+
const badges = await loader.getAllHarnesses(badgeHarness.with({text: /sized|disabled/i}));
46+
expect(badges.length).toBe(2);
47+
expect(await badges[0].getText()).toBe('Sized badge');
48+
expect(await badges[1].getText()).toBe('Disabled badge');
49+
});
50+
51+
it('should get whether a badge is overlapping', async () => {
52+
const badge = await loader.getHarness(badgeHarness.with({selector: '#overlapping'}));
53+
54+
expect(await badge.isOverlapping()).toBe(true);
55+
fixture.componentInstance.overlap = false;
56+
expect(await badge.isOverlapping()).toBe(false);
57+
});
58+
59+
it('should get whether a badge is disabled', async () => {
60+
const badge = await loader.getHarness(badgeHarness.with({selector: '#disabled'}));
61+
62+
expect(await badge.isDisabled()).toBe(true);
63+
fixture.componentInstance.disabled = false;
64+
expect(await badge.isDisabled()).toBe(false);
65+
});
66+
67+
it('should get whether a badge is hidden', async () => {
68+
const badge = await loader.getHarness(badgeHarness.with({selector: '#hidden'}));
69+
70+
expect(await badge.isHidden()).toBe(true);
71+
fixture.componentInstance.hidden = false;
72+
expect(await badge.isHidden()).toBe(false);
73+
});
74+
75+
it('should get the position of a badge', async () => {
76+
const instance = fixture.componentInstance;
77+
const badge = await loader.getHarness(badgeHarness.with({selector: '#positioned'}));
78+
79+
expect(await badge.getPosition()).toBe('above after');
80+
81+
instance.position = 'below';
82+
expect(await badge.getPosition()).toBe('below after');
83+
84+
instance.position = 'below before';
85+
expect(await badge.getPosition()).toBe('below before');
86+
87+
instance.position = 'above';
88+
expect(await badge.getPosition()).toBe('above after');
89+
90+
instance.position = 'above before';
91+
expect(await badge.getPosition()).toBe('above before');
92+
});
93+
94+
it('should get the size of a badge', async () => {
95+
const instance = fixture.componentInstance;
96+
const badge = await loader.getHarness(badgeHarness.with({selector: '#sized'}));
97+
98+
expect(await badge.getSize()).toBe('medium');
99+
100+
instance.size = 'small';
101+
expect(await badge.getSize()).toBe('small');
102+
103+
instance.size = 'large';
104+
expect(await badge.getSize()).toBe('large');
105+
});
106+
}
107+
108+
109+
@Component({
110+
template: `
111+
<button id="simple" [matBadge]="simpleContent">Simple</button>
112+
<button
113+
id="positioned"
114+
matBadge="Positioned badge"
115+
[matBadgePosition]="position">Positioned</button>
116+
<button
117+
id="sized"
118+
matBadge="Sized badge"
119+
[matBadgeSize]="size">Sized</button>
120+
<button
121+
id="overlapping"
122+
matBadge="Overlapping badge"
123+
[matBadgeOverlap]="overlap">Overlapping</button>
124+
<button
125+
id="hidden"
126+
matBadge="Hidden badge"
127+
[matBadgeHidden]="hidden">Hidden</button>
128+
<button
129+
id="disabled"
130+
matBadge="Disabled badge"
131+
[matBadgeDisabled]="disabled">Disabled</button>
132+
`
133+
})
134+
class BadgeHarnessTest {
135+
simpleContent = 'Simple badge';
136+
position: MatBadgePosition = 'above after';
137+
size: MatBadgeSize = 'medium';
138+
overlap = true;
139+
hidden = true;
140+
disabled = true;
141+
}
142+

src/material/config.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ entryPoints = [
22
"autocomplete",
33
"autocomplete/testing",
44
"badge",
5+
"badge/testing",
56
"bottom-sheet",
67
"button",
78
"button/testing",

test/karma-system-config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ System.config({
101101
'@angular/material/autocomplete/testing': 'dist/packages/material/autocomplete/testing/index.js',
102102
'@angular/material/autocomplete/testing/shared.spec': 'dist/packages/material/autocomplete/testing/shared.spec.js',
103103
'@angular/material/badge': 'dist/packages/material/badge/index.js',
104+
'@angular/material/badge/testing': 'dist/packages/material/badge/testing/index.js',
105+
'@angular/material/badge/testing/shared.spec': 'dist/packages/material/badge/testing/shared.spec.js',
104106
'@angular/material/bottom-sheet': 'dist/packages/material/bottom-sheet/index.js',
105107
'@angular/material/button': 'dist/packages/material/button/index.js',
106108
'@angular/material/button/testing': 'dist/packages/material/button/testing/index.js',
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export interface BadgeHarnessFilters extends BaseHarnessFilters {
2+
text?: string | RegExp;
3+
}
4+
5+
export declare class MatBadgeHarness extends ComponentHarness {
6+
getPosition(): Promise<MatBadgePosition>;
7+
getSize(): Promise<MatBadgeSize>;
8+
getText(): Promise<string>;
9+
isDisabled(): Promise<boolean>;
10+
isHidden(): Promise<boolean>;
11+
isOverlapping(): Promise<boolean>;
12+
static hostSelector: string;
13+
static with(options?: BadgeHarnessFilters): HarnessPredicate<MatBadgeHarness>;
14+
}

0 commit comments

Comments
 (0)