Skip to content

Commit 47614f3

Browse files
asynclizcopybara-github
authored andcommitted
test(chips): add harness and filter unit tests
PiperOrigin-RevId: 540709968
1 parent d9f66b3 commit 47614f3

File tree

3 files changed

+180
-1
lines changed

3 files changed

+180
-1
lines changed

chips/filter-chip_test.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,145 @@
66

77
// import 'jasmine'; (google3-only)
88

9+
import {html} from 'lit';
10+
11+
import {Environment} from '../testing/environment.js';
912
import {createTokenTests} from '../testing/tokens.js';
1013

1114
import {MdFilterChip} from './filter-chip.js';
15+
import {ChipHarness} from './harness.js';
1216

1317
describe('<md-filter-chip>', () => {
1418
describe('.styles', () => {
1519
createTokenTests(MdFilterChip.styles);
1620
});
21+
22+
const env = new Environment();
23+
24+
async function setupTest() {
25+
const chip = new MdFilterChip();
26+
env.render(html`${chip}`);
27+
await env.waitForStability();
28+
return {chip, harness: new ChipHarness(chip)};
29+
}
30+
31+
describe('selection', () => {
32+
it('should select on click', async () => {
33+
const {chip, harness} = await setupTest();
34+
35+
await harness.clickWithMouse();
36+
expect(chip.selected).withContext('chip.selected').toBeTrue();
37+
});
38+
39+
it('should deselect on click', async () => {
40+
const {chip, harness} = await setupTest();
41+
chip.selected = true;
42+
43+
await harness.clickWithMouse();
44+
expect(chip.selected).withContext('chip.selected').toBeFalse();
45+
});
46+
47+
it('should not select on click when disabled', async () => {
48+
const {chip, harness} = await setupTest();
49+
chip.disabled = true;
50+
51+
await harness.clickWithMouse();
52+
expect(chip.selected).withContext('chip.selected').toBeFalse();
53+
});
54+
55+
it('should dispatch "selected" event when selected changes programmatically',
56+
async () => {
57+
const {chip} = await setupTest();
58+
const handler = jasmine.createSpy();
59+
chip.addEventListener('selected', handler);
60+
61+
chip.selected = true;
62+
await env.waitForStability();
63+
chip.selected = false;
64+
await env.waitForStability();
65+
expect(handler).toHaveBeenCalledTimes(2);
66+
});
67+
68+
it('should dispatch "selected" event when selected changes by click',
69+
async () => {
70+
const {chip, harness} = await setupTest();
71+
const handler = jasmine.createSpy();
72+
chip.addEventListener('selected', handler);
73+
74+
await harness.clickWithMouse();
75+
await harness.clickWithMouse();
76+
expect(handler).toHaveBeenCalledTimes(2);
77+
});
78+
});
79+
80+
describe('removable', () => {
81+
it('should remove chip from DOM when remove button clicked', async () => {
82+
const {chip, harness} = await setupTest();
83+
chip.removable = true;
84+
await env.waitForStability();
85+
86+
expect(chip.parentElement)
87+
.withContext('chip should be attached before removing')
88+
.not.toBeNull();
89+
harness.action = 'trailing';
90+
await harness.clickWithMouse();
91+
expect(chip.parentElement)
92+
.withContext('chip should be detached after removing')
93+
.toBeNull();
94+
});
95+
96+
it('should dispatch a "remove" event when removed', async () => {
97+
const {chip, harness} = await setupTest();
98+
chip.removable = true;
99+
await env.waitForStability();
100+
const handler = jasmine.createSpy();
101+
chip.addEventListener('remove', handler);
102+
103+
harness.action = 'trailing';
104+
await harness.clickWithMouse();
105+
expect(handler).toHaveBeenCalledTimes(1);
106+
});
107+
108+
it('should not remove chip if "remove" event is default prevented',
109+
async () => {
110+
const {chip, harness} = await setupTest();
111+
chip.removable = true;
112+
await env.waitForStability();
113+
chip.addEventListener('remove', event => {
114+
event.preventDefault();
115+
});
116+
117+
harness.action = 'trailing';
118+
await harness.clickWithMouse();
119+
expect(chip.parentElement)
120+
.withContext('chip should still be attached')
121+
.not.toBeNull();
122+
});
123+
124+
it('should provide a default "ariaLabelRemove" value', async () => {
125+
const {chip} = await setupTest();
126+
chip.label = 'Label';
127+
128+
expect(chip.ariaLabelRemove).toEqual(`Remove ${chip.label}`);
129+
});
130+
131+
it('should provide a default "ariaLabelRemove" when "ariaLabel" is provided',
132+
async () => {
133+
const {chip} = await setupTest();
134+
chip.label = 'Label';
135+
chip.ariaLabel = 'Descriptive label';
136+
137+
expect(chip.ariaLabelRemove).toEqual(`Remove ${chip.ariaLabel}`);
138+
});
139+
140+
it('should allow setting a custom "ariaLabelRemove"', async () => {
141+
const {chip} = await setupTest();
142+
chip.label = 'Label';
143+
chip.ariaLabel = 'Descriptive label';
144+
const customAriaLabelRemove = 'Remove custom label';
145+
chip.ariaLabelRemove = customAriaLabelRemove;
146+
147+
expect(chip.ariaLabelRemove).toEqual(customAriaLabelRemove);
148+
});
149+
});
17150
});

chips/harness.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* @license
3+
* Copyright 2023 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import {Harness} from '../testing/harness.js';
8+
9+
import {MdAssistChip} from './assist-chip.js';
10+
import {MdFilterChip} from './filter-chip.js';
11+
import {MdInputChip} from './input-chip.js';
12+
import {MdSuggestionChip} from './suggestion-chip.js';
13+
14+
/**
15+
* Test harness for chips.
16+
*/
17+
export class ChipHarness extends
18+
Harness<MdAssistChip|MdFilterChip|MdInputChip|MdSuggestionChip> {
19+
action: 'primary'|'trailing' = 'primary';
20+
21+
protected override async getInteractiveElement() {
22+
await this.element.updateComplete;
23+
if (this.action === 'trailing') {
24+
// Retrieve MultiActionChip's trailingAction
25+
const {trailingAction} =
26+
this.element as {trailingAction?: HTMLElement | null};
27+
if (!trailingAction) {
28+
throw new Error(
29+
'`ChipHarness.action` is "trailing", but the chip does not have a trailing action.');
30+
}
31+
32+
return trailingAction;
33+
}
34+
35+
const {primaryId} = this.element as unknown as {primaryId: string};
36+
const primaryAction = primaryId &&
37+
this.element.renderRoot.querySelector<HTMLElement>(`#${primaryId}`);
38+
if (!primaryAction) {
39+
throw new Error(
40+
'`ChipHarness.action` is "primary", but the chip does not have a primary action.');
41+
}
42+
43+
return primaryAction;
44+
}
45+
}

chips/lib/trailing-icons.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ function handleRemoveClick(this: Chip, event: Event) {
4141
}
4242

4343
event.stopPropagation();
44-
const preventDefault = !this.dispatchEvent(new Event('remove'));
44+
const preventDefault =
45+
!this.dispatchEvent(new Event('remove', {cancelable: true}));
4546
if (preventDefault) {
4647
return;
4748
}

0 commit comments

Comments
 (0)