@crowdstrike/glide-core 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/dist/accordion.d.ts +7 -3
  2. package/dist/button-group.button.d.ts +12 -16
  3. package/dist/button-group.button.js +1 -1
  4. package/dist/button-group.button.styles.js +76 -52
  5. package/dist/button-group.button.test.basics.d.ts +1 -1
  6. package/dist/button-group.button.test.basics.js +83 -147
  7. package/dist/button-group.button.test.events.js +8 -67
  8. package/dist/button-group.button.test.focus.js +13 -0
  9. package/dist/button-group.button.test.interactions.d.ts +1 -0
  10. package/dist/button-group.button.test.interactions.js +42 -0
  11. package/dist/button-group.d.ts +10 -10
  12. package/dist/button-group.js +1 -1
  13. package/dist/button-group.stories.d.ts +1 -5
  14. package/dist/button-group.styles.js +18 -6
  15. package/dist/button-group.test.basics.js +113 -234
  16. package/dist/button-group.test.events.js +210 -263
  17. package/dist/button-group.test.focus.d.ts +1 -0
  18. package/dist/button-group.test.focus.js +39 -0
  19. package/dist/button-group.test.interactions.d.ts +1 -0
  20. package/dist/button-group.test.interactions.js +91 -0
  21. package/dist/button.d.ts +3 -0
  22. package/dist/button.test.basics.js +1 -1
  23. package/dist/checkbox-group.d.ts +6 -2
  24. package/dist/checkbox-group.js +1 -1
  25. package/dist/checkbox-group.stories.d.ts +1 -1
  26. package/dist/checkbox-group.styles.js +1 -1
  27. package/dist/checkbox-group.test.basics.js +1 -1
  28. package/dist/checkbox-group.test.events.js +4 -4
  29. package/dist/checkbox-group.test.focus.js +4 -3
  30. package/dist/checkbox.d.ts +12 -5
  31. package/dist/checkbox.js +1 -1
  32. package/dist/checkbox.stories.d.ts +1 -1
  33. package/dist/checkbox.styles.js +10 -0
  34. package/dist/checkbox.test.basics.js +15 -6
  35. package/dist/checkbox.test.events.js +16 -8
  36. package/dist/checkbox.test.focus.js +3 -3
  37. package/dist/checkbox.test.form.js +1 -0
  38. package/dist/checkbox.test.interactions.js +123 -0
  39. package/dist/drawer.d.ts +5 -5
  40. package/dist/drawer.js +1 -1
  41. package/dist/drawer.stories.d.ts +0 -1
  42. package/dist/dropdown.d.ts +9 -6
  43. package/dist/dropdown.js +1 -1
  44. package/dist/dropdown.option.d.ts +6 -2
  45. package/dist/dropdown.option.js +1 -1
  46. package/dist/dropdown.option.styles.js +13 -0
  47. package/dist/dropdown.option.test.basics.js +6 -3
  48. package/dist/dropdown.option.test.events.js +1 -1
  49. package/dist/dropdown.option.test.focus.js +1 -1
  50. package/dist/dropdown.option.test.interactions.multiple.js +1 -54
  51. package/dist/dropdown.option.test.interactions.single.js +51 -9
  52. package/dist/dropdown.styles.js +20 -19
  53. package/dist/dropdown.test.basics.js +143 -2
  54. package/dist/dropdown.test.basics.multiple.js +5 -2
  55. package/dist/dropdown.test.events.filterable.js +74 -0
  56. package/dist/dropdown.test.events.js +49 -160
  57. package/dist/dropdown.test.events.multiple.js +265 -8
  58. package/dist/dropdown.test.events.single.js +199 -2
  59. package/dist/dropdown.test.focus.filterable.js +9 -5
  60. package/dist/dropdown.test.focus.js +1 -1
  61. package/dist/dropdown.test.focus.multiple.js +1 -1
  62. package/dist/dropdown.test.focus.single.js +1 -1
  63. package/dist/dropdown.test.interactions.filterable.js +68 -11
  64. package/dist/dropdown.test.interactions.js +94 -5
  65. package/dist/dropdown.test.interactions.multiple.js +202 -5
  66. package/dist/dropdown.test.interactions.single.js +68 -6
  67. package/dist/form-controls-layout.test.basics.js +1 -1
  68. package/dist/icon-button.d.ts +2 -0
  69. package/dist/icon-button.test.basics.js +1 -1
  70. package/dist/icons/checked.d.ts +1 -1
  71. package/dist/icons/checked.js +1 -1
  72. package/dist/icons/magnifying-glass.js +1 -1
  73. package/dist/input.d.ts +4 -9
  74. package/dist/input.js +1 -1
  75. package/dist/input.styles.js +7 -2
  76. package/dist/input.test.basics.js +19 -5
  77. package/dist/input.test.events.js +4 -4
  78. package/dist/input.test.focus.js +4 -4
  79. package/dist/input.test.translations.d.ts +1 -0
  80. package/dist/input.test.translations.js +38 -0
  81. package/dist/input.test.validity.js +133 -4
  82. package/dist/label.d.ts +1 -1
  83. package/dist/label.js +1 -1
  84. package/dist/label.styles.js +25 -13
  85. package/dist/label.test.basics.js +26 -24
  86. package/dist/library/expect-argument-error.js +1 -1
  87. package/dist/library/localize.d.ts +4 -1
  88. package/dist/menu.d.ts +3 -5
  89. package/dist/menu.js +1 -1
  90. package/dist/menu.options.test.basics.js +2 -2
  91. package/dist/menu.styles.js +1 -15
  92. package/dist/menu.test.basics.d.ts +1 -2
  93. package/dist/menu.test.basics.js +22 -6
  94. package/dist/menu.test.events.js +197 -7
  95. package/dist/menu.test.focus.d.ts +1 -0
  96. package/dist/menu.test.focus.js +13 -6
  97. package/dist/menu.test.interactions.js +214 -58
  98. package/dist/modal.icon-button.test.basics.js +1 -1
  99. package/dist/modal.js +1 -1
  100. package/dist/modal.stories.d.ts +1 -0
  101. package/dist/modal.styles.js +18 -13
  102. package/dist/modal.tertiary-icon.d.ts +0 -1
  103. package/dist/modal.tertiary-icon.js +1 -1
  104. package/dist/modal.tertiary-icon.test.basics.js +3 -3
  105. package/dist/modal.test.basics.js +1 -1
  106. package/dist/modal.test.events.js +10 -10
  107. package/dist/radio-group.d.ts +4 -3
  108. package/dist/radio-group.js +1 -1
  109. package/dist/radio-group.stories.d.ts +1 -1
  110. package/dist/radio-group.styles.js +1 -1
  111. package/dist/radio-group.test.focus.js +3 -3
  112. package/dist/radio.d.ts +2 -2
  113. package/dist/radio.js +1 -1
  114. package/dist/radio.styles.js +33 -0
  115. package/dist/split-container.d.ts +1 -1
  116. package/dist/split-container.test.basics.js +4 -0
  117. package/dist/split-link.test.interactions.js +1 -1
  118. package/dist/status-indicator.d.ts +1 -1
  119. package/dist/styles/variables.css +1 -1
  120. package/dist/tab.d.ts +1 -1
  121. package/dist/tab.group.js +1 -1
  122. package/dist/tab.group.test.basics.js +1 -1
  123. package/dist/tab.group.test.interactions.js +198 -2
  124. package/dist/tab.js +1 -1
  125. package/dist/tab.panel.d.ts +1 -0
  126. package/dist/tab.panel.js +1 -1
  127. package/dist/tab.panel.styles.js +11 -1
  128. package/dist/tabs.stories.d.ts +1 -0
  129. package/dist/tag.d.ts +3 -6
  130. package/dist/tag.test.basics.js +2 -2
  131. package/dist/textarea.d.ts +4 -4
  132. package/dist/textarea.js +2 -2
  133. package/dist/textarea.stories.d.ts +3 -4
  134. package/dist/textarea.styles.js +14 -3
  135. package/dist/textarea.test.basics.js +80 -44
  136. package/dist/textarea.test.events.js +56 -41
  137. package/dist/textarea.test.translations.d.ts +1 -0
  138. package/dist/textarea.test.translations.js +34 -0
  139. package/dist/textarea.test.validity.js +104 -20
  140. package/dist/toasts.js +1 -1
  141. package/dist/toasts.styles.js +8 -1
  142. package/dist/toasts.test.basics.js +20 -0
  143. package/dist/toggle.d.ts +3 -3
  144. package/dist/toggle.js +1 -1
  145. package/dist/toggle.stories.d.ts +1 -1
  146. package/dist/toggle.test.focus.js +1 -1
  147. package/dist/toggle.test.interactions.d.ts +1 -0
  148. package/dist/{toggle.test.states.js → toggle.test.interactions.js} +26 -0
  149. package/dist/tooltip.d.ts +9 -7
  150. package/dist/tooltip.js +1 -1
  151. package/dist/tooltip.styles.js +90 -25
  152. package/dist/tooltip.test.basics.js +38 -3
  153. package/dist/tooltip.test.interactions.js +136 -34
  154. package/dist/translations/en.js +1 -1
  155. package/dist/translations/fr.js +1 -1
  156. package/dist/translations/ja.js +1 -1
  157. package/dist/tree.d.ts +1 -2
  158. package/dist/tree.item.d.ts +1 -5
  159. package/dist/tree.item.icon-button.d.ts +1 -0
  160. package/dist/tree.item.icon-button.js +1 -1
  161. package/dist/tree.item.icon-button.test.basics.js +9 -0
  162. package/dist/tree.item.js +1 -1
  163. package/dist/tree.item.menu.d.ts +2 -1
  164. package/dist/tree.item.menu.js +1 -1
  165. package/dist/tree.item.menu.test.basics.js +15 -0
  166. package/dist/tree.item.styles.js +2 -0
  167. package/dist/tree.item.test.basics.d.ts +2 -1
  168. package/dist/tree.item.test.basics.js +46 -4
  169. package/dist/tree.js +1 -1
  170. package/dist/tree.test.basics.js +1 -1
  171. package/dist/tree.test.focus.js +91 -4
  172. package/package.json +3 -4
  173. package/dist/checkbox.test.states.js +0 -63
  174. package/dist/drawer.test.floating-components.d.ts +0 -1
  175. package/dist/drawer.test.floating-components.js +0 -52
  176. package/dist/library/set-containing-block.d.ts +0 -15
  177. package/dist/library/set-containing-block.js +0 -1
  178. package/dist/modal.test.floating-components.js +0 -63
  179. /package/dist/{checkbox.test.states.d.ts → button-group.button.test.focus.d.ts} +0 -0
  180. /package/dist/{modal.test.floating-components.d.ts → checkbox.test.interactions.d.ts} +0 -0
  181. /package/dist/{toggle.test.states.d.ts → dropdown.test.events.filterable.d.ts} +0 -0
@@ -1,10 +1,211 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-expressions */
2
2
  import * as sinon from 'sinon';
3
3
  import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
4
+ import { sendKeys } from '@web/test-runner-commands';
4
5
  import GlideCoreDropdown from './dropdown.js';
5
6
  import GlideCoreDropdownOption from './dropdown.option.js';
6
7
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
7
8
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
9
+ it('dispatches one "change" event when an option is selected via click', async () => {
10
+ const component = await fixture(html `<glide-core-dropdown
11
+ label="Label"
12
+ placeholder="Placeholder"
13
+ open
14
+ multiple
15
+ >
16
+ <glide-core-dropdown-option
17
+ label="One"
18
+ value="one"
19
+ ></glide-core-dropdown-option>
20
+
21
+ <glide-core-dropdown-option
22
+ label="Two"
23
+ value="two"
24
+ selected
25
+ ></glide-core-dropdown-option>
26
+ </glide-core-dropdown>`);
27
+ const spy = sinon.spy();
28
+ component.addEventListener('change', spy);
29
+ setTimeout(() => {
30
+ // Calling `click()` isn't sufficient because it simply sets
31
+ // `selected` and so isn't likely to produce a duplicate event,
32
+ // we assert against below. The checkbox, because it produces
33
+ // its own "change" event, is most likely where the duplicate would
34
+ // come from.
35
+ component
36
+ .querySelector('glide-core-dropdown-option')
37
+ ?.shadowRoot?.querySelector('[data-test="checkbox"]')
38
+ ?.click();
39
+ });
40
+ const event = await oneEvent(component, 'change');
41
+ expect(event instanceof Event).to.be.true;
42
+ expect(event.bubbles).to.be.true;
43
+ expect(spy.callCount).to.equal(1);
44
+ });
45
+ it('dispatches one "change" event when an option is selected via Enter', async () => {
46
+ const component = await fixture(html `<glide-core-dropdown
47
+ label="Label"
48
+ placeholder="Placeholder"
49
+ open
50
+ multiple
51
+ >
52
+ <glide-core-dropdown-option
53
+ label="One"
54
+ value="one"
55
+ ></glide-core-dropdown-option>
56
+
57
+ <glide-core-dropdown-option
58
+ label="Two"
59
+ value="two"
60
+ selected
61
+ ></glide-core-dropdown-option>
62
+ </glide-core-dropdown>`);
63
+ const spy = sinon.spy();
64
+ component.addEventListener('change', spy);
65
+ // Activate the first option before selecting it. The second option is
66
+ // currently active because it's selected.
67
+ component
68
+ .querySelector('glide-core-dropdown-option')
69
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
70
+ component.focus();
71
+ sendKeys({ press: 'Enter' });
72
+ const event = await oneEvent(component, 'change');
73
+ expect(event instanceof Event).to.be.true;
74
+ expect(event.bubbles).to.be.true;
75
+ expect(spy.callCount).to.equal(1);
76
+ });
77
+ it('dispatches one "change" event when an option is selected via Space', async () => {
78
+ const component = await fixture(html `<glide-core-dropdown
79
+ label="Label"
80
+ placeholder="Placeholder"
81
+ open
82
+ multiple
83
+ >
84
+ <glide-core-dropdown-option
85
+ label="One"
86
+ value="one"
87
+ ></glide-core-dropdown-option>
88
+
89
+ <glide-core-dropdown-option
90
+ label="Two"
91
+ value="two"
92
+ selected
93
+ ></glide-core-dropdown-option>
94
+ </glide-core-dropdown>`);
95
+ const spy = sinon.spy();
96
+ component.addEventListener('change', spy);
97
+ // Activate the first option before selecting it. The second option is
98
+ // currently active because it's selected.
99
+ component
100
+ .querySelector('glide-core-dropdown-option')
101
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
102
+ component.focus();
103
+ sendKeys({ press: ' ' });
104
+ const event = await oneEvent(component, 'change');
105
+ expect(event instanceof Event).to.be.true;
106
+ expect(event.bubbles).to.be.true;
107
+ expect(spy.callCount).to.equal(1);
108
+ });
109
+ it('dispatches one "input" event when an option is selected via click', async () => {
110
+ const component = await fixture(html `<glide-core-dropdown
111
+ label="Label"
112
+ placeholder="Placeholder"
113
+ open
114
+ multiple
115
+ >
116
+ <glide-core-dropdown-option
117
+ label="One"
118
+ value="one"
119
+ ></glide-core-dropdown-option>
120
+
121
+ <glide-core-dropdown-option
122
+ label="Two"
123
+ value="two"
124
+ selected
125
+ ></glide-core-dropdown-option>
126
+ </glide-core-dropdown>`);
127
+ const spy = sinon.spy();
128
+ component.addEventListener('input', spy);
129
+ setTimeout(() => {
130
+ // Calling `click()` isn't sufficient because it simply sets
131
+ // `selected` and so isn't likely to produce a duplicate event,
132
+ // we assert against below. The checkbox, because it produces
133
+ // its own "change" event, is most likely where the duplicate would
134
+ // come from.
135
+ component
136
+ .querySelector('glide-core-dropdown-option')
137
+ ?.shadowRoot?.querySelector('[data-test="checkbox"]')
138
+ ?.click();
139
+ });
140
+ const event = await oneEvent(component, 'input');
141
+ expect(event instanceof Event).to.be.true;
142
+ expect(event.bubbles).to.be.true;
143
+ expect(spy.callCount).to.equal(1);
144
+ });
145
+ it('dispatches one "input" event when an option is selected via Enter', async () => {
146
+ const component = await fixture(html `<glide-core-dropdown
147
+ label="Label"
148
+ placeholder="Placeholder"
149
+ open
150
+ multiple
151
+ >
152
+ <glide-core-dropdown-option
153
+ label="One"
154
+ value="one"
155
+ ></glide-core-dropdown-option>
156
+
157
+ <glide-core-dropdown-option
158
+ label="Two"
159
+ value="two"
160
+ selected
161
+ ></glide-core-dropdown-option>
162
+ </glide-core-dropdown>`);
163
+ const spy = sinon.spy();
164
+ component.addEventListener('input', spy);
165
+ // Activate the first option before selecting it. The second option is
166
+ // currently active because it's selected.
167
+ component
168
+ .querySelector('glide-core-dropdown-option')
169
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
170
+ component.focus();
171
+ sendKeys({ press: 'Enter' });
172
+ const event = await oneEvent(component, 'input');
173
+ expect(event instanceof Event).to.be.true;
174
+ expect(event.bubbles).to.be.true;
175
+ expect(spy.callCount).to.equal(1);
176
+ });
177
+ it('dispatches one "input" event when an option is selected via Space', async () => {
178
+ const component = await fixture(html `<glide-core-dropdown
179
+ label="Label"
180
+ placeholder="Placeholder"
181
+ open
182
+ multiple
183
+ >
184
+ <glide-core-dropdown-option
185
+ label="One"
186
+ value="one"
187
+ ></glide-core-dropdown-option>
188
+
189
+ <glide-core-dropdown-option
190
+ label="Two"
191
+ value="two"
192
+ selected
193
+ ></glide-core-dropdown-option>
194
+ </glide-core-dropdown>`);
195
+ const spy = sinon.spy();
196
+ component.addEventListener('input', spy);
197
+ // Activate the first option before selecting it. The second option is
198
+ // currently active because it's selected.
199
+ component
200
+ .querySelector('glide-core-dropdown-option')
201
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
202
+ component.focus();
203
+ sendKeys({ press: ' ' });
204
+ const event = await oneEvent(component, 'input');
205
+ expect(event instanceof Event).to.be.true;
206
+ expect(event.bubbles).to.be.true;
207
+ expect(spy.callCount).to.equal(1);
208
+ });
8
209
  it('dispatches one "change" event when Select All is clicked', async () => {
9
210
  const component = await fixture(html `<glide-core-dropdown
10
211
  label="Label"
@@ -32,7 +233,7 @@ it('dispatches one "change" event when Select All is clicked', async () => {
32
233
  ?.click();
33
234
  });
34
235
  await aTimeout(0);
35
- expect(spy.calledOnce).to.be.true;
236
+ expect(spy.callCount).to.equal(1);
36
237
  });
37
238
  it('dispatches one "input" event when Select All is clicked', async () => {
38
239
  const component = await fixture(html `<glide-core-dropdown
@@ -61,7 +262,7 @@ it('dispatches one "input" event when Select All is clicked', async () => {
61
262
  ?.click();
62
263
  });
63
264
  await aTimeout(0);
64
- expect(spy.calledOnce).to.be.true;
265
+ expect(spy.callCount).to.equal(1);
65
266
  });
66
267
  it('does not dispatch a "change" event when `value` is changed programmatically', async () => {
67
268
  const component = await fixture(html `<glide-core-dropdown
@@ -92,7 +293,7 @@ it('does not dispatch a "change" event when `value` is changed programmatically'
92
293
  component.value = ['one', 'two'];
93
294
  });
94
295
  await aTimeout(0);
95
- expect(spy.called).to.be.false;
296
+ expect(spy.callCount).to.equal(0);
96
297
  });
97
298
  it('continues to dispatch "change" events upon selection after `value` is changed programmatically', async () => {
98
299
  const component = await fixture(html `<glide-core-dropdown
@@ -156,7 +357,7 @@ it('does not dispatch an "input" event when `value` is changed programmatically'
156
357
  component.value = ['one', 'two'];
157
358
  });
158
359
  await aTimeout(0);
159
- expect(spy.called).to.be.false;
360
+ expect(spy.callCount).to.equal(0);
160
361
  });
161
362
  it('continues to dispatch "input" events upon selection after `value` is changed programmatically', async () => {
162
363
  const component = await fixture(html `<glide-core-dropdown
@@ -191,7 +392,7 @@ it('continues to dispatch "input" events upon selection after `value` is changed
191
392
  const event = await oneEvent(component, 'input');
192
393
  expect(event instanceof Event).to.be.true;
193
394
  });
194
- it('dispatches a "change" event when an option is selected after Select All is clicked', async () => {
395
+ it('dispatches one "change" event when an option is selected after Select All is clicked', async () => {
195
396
  const component = await fixture(html `<glide-core-dropdown
196
397
  label="Label"
197
398
  placeholder="Placeholder"
@@ -222,9 +423,9 @@ it('dispatches a "change" event when an option is selected after Select All is c
222
423
  component.querySelector('glide-core-dropdown-option')?.click();
223
424
  });
224
425
  await aTimeout(0);
225
- expect(spy.called).to.be.true;
426
+ expect(spy.callCount).to.equal(1);
226
427
  });
227
- it('dispatches an "input" event when an option is selected after Select All is clicked', async () => {
428
+ it('dispatches one "input" event when an option is selected after Select All is clicked', async () => {
228
429
  const component = await fixture(html `<glide-core-dropdown
229
430
  label="Label"
230
431
  placeholder="Placeholder"
@@ -255,5 +456,61 @@ it('dispatches an "input" event when an option is selected after Select All is c
255
456
  component.querySelector('glide-core-dropdown-option')?.click();
256
457
  });
257
458
  await aTimeout(0);
258
- expect(spy.called).to.be.true;
459
+ expect(spy.callCount).to.equal(1);
460
+ });
461
+ it('dispatches one "change" event when a tag is removed', async () => {
462
+ const component = await fixture(html `<glide-core-dropdown
463
+ label="Label"
464
+ placeholder="Placeholder"
465
+ open
466
+ multiple
467
+ >
468
+ <glide-core-dropdown-option
469
+ label="One"
470
+ value="one"
471
+ selected
472
+ ></glide-core-dropdown-option>
473
+
474
+ <glide-core-dropdown-option
475
+ label="Two"
476
+ value="two"
477
+ ></glide-core-dropdown-option>
478
+ </glide-core-dropdown>`);
479
+ setTimeout(() => {
480
+ component.shadowRoot
481
+ ?.querySelector('[data-test="tag"]')
482
+ ?.click();
483
+ });
484
+ const spy = sinon.spy();
485
+ component.addEventListener('change', spy);
486
+ await aTimeout(0);
487
+ expect(spy.callCount).to.equal(1);
488
+ });
489
+ it('dispatches one "input" event when a tag is removed', async () => {
490
+ const component = await fixture(html `<glide-core-dropdown
491
+ label="Label"
492
+ placeholder="Placeholder"
493
+ open
494
+ multiple
495
+ >
496
+ <glide-core-dropdown-option
497
+ label="One"
498
+ value="one"
499
+ selected
500
+ ></glide-core-dropdown-option>
501
+
502
+ <glide-core-dropdown-option
503
+ label="Two"
504
+ value="two"
505
+ ></glide-core-dropdown-option>
506
+ </glide-core-dropdown>`);
507
+ setTimeout(() => {
508
+ component.shadowRoot
509
+ ?.querySelector('[data-test="tag"]')
510
+ ?.click();
511
+ });
512
+ const spy = sinon.spy();
513
+ component.addEventListener('input', spy);
514
+ await aTimeout(0);
515
+ expect(spy.callCount).to.equal(1);
259
516
  });
@@ -2,8 +2,163 @@
2
2
  import './dropdown.option.js';
3
3
  import * as sinon from 'sinon';
4
4
  import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
5
+ import { sendKeys } from '@web/test-runner-commands';
5
6
  import GlideCoreDropdown from './dropdown.js';
6
7
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
8
+ it('dispatches one "change" event when an option is selected via click', async () => {
9
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
10
+ <glide-core-dropdown-option
11
+ label="One"
12
+ value="one"
13
+ ></glide-core-dropdown-option>
14
+
15
+ <glide-core-dropdown-option
16
+ label="Two"
17
+ value="two"
18
+ selected
19
+ ></glide-core-dropdown-option>
20
+ </glide-core-dropdown>`);
21
+ const spy = sinon.spy();
22
+ component.addEventListener('change', spy);
23
+ setTimeout(() => {
24
+ component.querySelector('glide-core-dropdown-option')?.click();
25
+ });
26
+ const event = await oneEvent(component, 'change');
27
+ expect(event instanceof Event).to.be.true;
28
+ expect(event.bubbles).to.be.true;
29
+ expect(spy.callCount).to.equal(1);
30
+ });
31
+ it('dispatches one "change" event when an option is selected via Enter', async () => {
32
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
33
+ <glide-core-dropdown-option
34
+ label="One"
35
+ value="one"
36
+ ></glide-core-dropdown-option>
37
+
38
+ <glide-core-dropdown-option
39
+ label="Two"
40
+ value="two"
41
+ selected
42
+ ></glide-core-dropdown-option>
43
+ </glide-core-dropdown>`);
44
+ const spy = sinon.spy();
45
+ component.addEventListener('change', spy);
46
+ // Activate the first option before selecting it. The second option is
47
+ // currently active because it's selected.
48
+ component
49
+ .querySelector('glide-core-dropdown-option')
50
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
51
+ component.focus();
52
+ sendKeys({ press: 'Enter' });
53
+ const event = await oneEvent(component, 'change');
54
+ expect(event instanceof Event).to.be.true;
55
+ expect(event.bubbles).to.be.true;
56
+ expect(spy.callCount).to.equal(1);
57
+ });
58
+ it('dispatches one "change" event when an option is selected via Space', async () => {
59
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
60
+ <glide-core-dropdown-option
61
+ label="One"
62
+ value="one"
63
+ ></glide-core-dropdown-option>
64
+
65
+ <glide-core-dropdown-option
66
+ label="Two"
67
+ value="two"
68
+ selected
69
+ ></glide-core-dropdown-option>
70
+ </glide-core-dropdown>`);
71
+ const spy = sinon.spy();
72
+ component.addEventListener('change', spy);
73
+ // Activate the first option before selecting it. The second option is
74
+ // currently active because it's selected.
75
+ component
76
+ .querySelector('glide-core-dropdown-option')
77
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
78
+ component.focus();
79
+ sendKeys({ press: ' ' });
80
+ const event = await oneEvent(component, 'change');
81
+ expect(event instanceof Event).to.be.true;
82
+ expect(event.bubbles).to.be.true;
83
+ expect(spy.callCount).to.equal(1);
84
+ });
85
+ it('dispatches one "input" event when an option is selected via click', async () => {
86
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
87
+ <glide-core-dropdown-option
88
+ label="One"
89
+ value="one"
90
+ ></glide-core-dropdown-option>
91
+
92
+ <glide-core-dropdown-option
93
+ label="Two"
94
+ value="two"
95
+ selected
96
+ ></glide-core-dropdown-option>
97
+ </glide-core-dropdown>`);
98
+ const spy = sinon.spy();
99
+ component.addEventListener('input', spy);
100
+ setTimeout(() => {
101
+ component.querySelector('glide-core-dropdown-option')?.click();
102
+ });
103
+ const event = await oneEvent(component, 'input');
104
+ expect(event instanceof Event).to.be.true;
105
+ expect(event.bubbles).to.be.true;
106
+ expect(spy.callCount).to.equal(1);
107
+ });
108
+ it('dispatches one "input" event when an option is selected via Enter', async () => {
109
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
110
+ <glide-core-dropdown-option
111
+ label="One"
112
+ value="one"
113
+ ></glide-core-dropdown-option>
114
+
115
+ <glide-core-dropdown-option
116
+ label="Two"
117
+ value="two"
118
+ selected
119
+ ></glide-core-dropdown-option>
120
+ </glide-core-dropdown>`);
121
+ const spy = sinon.spy();
122
+ component.addEventListener('input', spy);
123
+ // Activate the first option before selecting it. The second option is
124
+ // currently active because it's selected.
125
+ component
126
+ .querySelector('glide-core-dropdown-option')
127
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
128
+ component.focus();
129
+ sendKeys({ press: 'Enter' });
130
+ const event = await oneEvent(component, 'input');
131
+ expect(event instanceof Event).to.be.true;
132
+ expect(event.bubbles).to.be.true;
133
+ expect(spy.callCount).to.equal(1);
134
+ });
135
+ it('dispatches one "input" event when an option is selected via Space', async () => {
136
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
137
+ <glide-core-dropdown-option
138
+ label="One"
139
+ value="one"
140
+ ></glide-core-dropdown-option>
141
+
142
+ <glide-core-dropdown-option
143
+ label="Two"
144
+ value="two"
145
+ selected
146
+ ></glide-core-dropdown-option>
147
+ </glide-core-dropdown>`);
148
+ const spy = sinon.spy();
149
+ component.addEventListener('input', spy);
150
+ // Activate the first option before selecting it. The second option is
151
+ // currently active because it's selected.
152
+ component
153
+ .querySelector('glide-core-dropdown-option')
154
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
155
+ component.focus();
156
+ sendKeys({ press: ' ' });
157
+ const event = await oneEvent(component, 'input');
158
+ expect(event instanceof Event).to.be.true;
159
+ expect(event.bubbles).to.be.true;
160
+ expect(spy.callCount).to.equal(1);
161
+ });
7
162
  it('does not dispatch a "change" event when `value` is changed programmatically', async () => {
8
163
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
9
164
  <glide-core-dropdown-option
@@ -23,7 +178,7 @@ it('does not dispatch a "change" event when `value` is changed programmatically'
23
178
  component.value = ['one'];
24
179
  });
25
180
  await aTimeout(0);
26
- expect(spy.called).to.be.false;
181
+ expect(spy.callCount).to.equal(0);
27
182
  });
28
183
  it('continues to dispatch "change" events upon selection after `value` is changed programmatically', async () => {
29
184
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
@@ -64,7 +219,49 @@ it('does not dispatch an "input" event when `value` is changed programmatically'
64
219
  component.value = ['one'];
65
220
  });
66
221
  await aTimeout(0);
67
- expect(spy.called).to.be.false;
222
+ expect(spy.callCount).to.equal(0);
223
+ });
224
+ it('does not dispatch a "change" event when an already selected option is selected', async () => {
225
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
226
+ <glide-core-dropdown-option
227
+ label="One"
228
+ value="one"
229
+ selected
230
+ ></glide-core-dropdown-option>
231
+
232
+ <glide-core-dropdown-option
233
+ label="Two"
234
+ value="two"
235
+ ></glide-core-dropdown-option>
236
+ </glide-core-dropdown>`);
237
+ const spy = sinon.spy();
238
+ component.addEventListener('change', spy);
239
+ setTimeout(() => {
240
+ component.querySelector('glide-core-dropdown-option')?.click();
241
+ });
242
+ await aTimeout(0);
243
+ expect(spy.callCount).to.equal(0);
244
+ });
245
+ it('does not dispatch an "input" event when an already selected option is selected', async () => {
246
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
247
+ <glide-core-dropdown-option
248
+ label="One"
249
+ value="one"
250
+ selected
251
+ ></glide-core-dropdown-option>
252
+
253
+ <glide-core-dropdown-option
254
+ label="Two"
255
+ value="two"
256
+ ></glide-core-dropdown-option>
257
+ </glide-core-dropdown>`);
258
+ const spy = sinon.spy();
259
+ component.addEventListener('input', spy);
260
+ setTimeout(() => {
261
+ component.querySelector('glide-core-dropdown-option')?.click();
262
+ });
263
+ await aTimeout(0);
264
+ expect(spy.callCount).to.equal(0);
68
265
  });
69
266
  it('continues to dispatch "input" events upon selection after `value` is changed programmatically', async () => {
70
267
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
@@ -1,5 +1,5 @@
1
1
  import './dropdown.option.js';
2
- import { assert, expect, fixture, html } from '@open-wc/testing';
2
+ import { aTimeout, assert, expect, fixture, html } from '@open-wc/testing';
3
3
  import { sendMouse } from '@web/test-runner-commands';
4
4
  import GlideCoreDropdown from './dropdown.js';
5
5
  import GlideCoreDropdownOption from './dropdown.option.js';
@@ -61,7 +61,7 @@ const defaultSlot = html `
61
61
  value="eleven"
62
62
  ></glide-core-dropdown-option>
63
63
  `;
64
- it('focuses the input when `focus` is called', async () => {
64
+ it('focuses the input when `focus()` is called', async () => {
65
65
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
66
66
  ${defaultSlot}
67
67
  </glide-core-dropdown>`);
@@ -78,12 +78,14 @@ it('retains focus on the input when an option is selected via click', async () =
78
78
  >
79
79
  ${defaultSlot}
80
80
  </glide-core-dropdown>`);
81
+ // Wait for it to open.
82
+ await aTimeout(0);
81
83
  component.focus();
82
84
  const option = component.querySelector('glide-core-dropdown-option');
83
85
  assert(option);
84
86
  const { x, y } = option.getBoundingClientRect();
85
87
  // A simple `option.click()` won't do because we need a "mousedown" so that
86
- // `#onOptionsMousedown` gets covered.
88
+ // `#onOptionsMousedown` is covered.
87
89
  await sendMouse({
88
90
  type: 'click',
89
91
  position: [Math.ceil(x), Math.ceil(y)],
@@ -92,9 +94,11 @@ it('retains focus on the input when an option is selected via click', async () =
92
94
  expect(component.shadowRoot?.activeElement).to.equal(input);
93
95
  });
94
96
  it('retains focus on the the input when an option is selected via Enter', async () => {
95
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
97
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
96
98
  ${defaultSlot}
97
99
  </glide-core-dropdown>`);
100
+ // Wait for it to open.
101
+ await aTimeout(0);
98
102
  component.focus();
99
103
  component
100
104
  .querySelector('glide-core-dropdown-option')
@@ -104,7 +108,7 @@ it('retains focus on the the input when an option is selected via Enter', async
104
108
  expect(component.shadowRoot?.activeElement).to.equal(input);
105
109
  });
106
110
  it('retains focus on the the input when the button is clicked', async () => {
107
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
111
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
108
112
  ${defaultSlot}
109
113
  </glide-core-dropdown>`);
110
114
  component.focus();
@@ -33,5 +33,5 @@ it('closes and reports validity when it loses focus', async () => {
33
33
  expect(component.open).to.be.false;
34
34
  expect(component.shadowRoot?.activeElement).to.equal(null);
35
35
  expect(component.validity.valid).to.equal(false);
36
- expect(component.shadowRoot?.querySelector('glide-core-label')?.error).to.equal(true);
36
+ expect(component.shadowRoot?.querySelector('glide-core-private-label')?.error).to.equal(true);
37
37
  });
@@ -4,7 +4,7 @@ import GlideCoreDropdown from './dropdown.js';
4
4
  import GlideCoreDropdownOption from './dropdown.option.js';
5
5
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
6
6
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
7
- it('focuses the button when `focus` is called', async () => {
7
+ it('focuses the button when `focus()` is called', async () => {
8
8
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
9
9
  <glide-core-dropdown-option
10
10
  label="One"
@@ -4,7 +4,7 @@ import GlideCoreDropdown from './dropdown.js';
4
4
  import GlideCoreDropdownOption from './dropdown.option.js';
5
5
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
6
6
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
7
- it('focuses the button when `focus` is called', async () => {
7
+ it('focuses the button when `focus()` is called', async () => {
8
8
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
9
9
  <glide-core-dropdown-option
10
10
  label="Label"