@crowdstrike/glide-core 0.8.0 → 0.9.0

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 (152) hide show
  1. package/dist/button-group.button.d.ts +14 -15
  2. package/dist/button-group.button.js +1 -1
  3. package/dist/button-group.button.styles.js +75 -52
  4. package/dist/button-group.button.test.basics.d.ts +1 -1
  5. package/dist/button-group.button.test.basics.js +83 -147
  6. package/dist/button-group.button.test.events.js +8 -67
  7. package/dist/button-group.button.test.focus.js +13 -0
  8. package/dist/button-group.button.test.interactions.d.ts +1 -0
  9. package/dist/button-group.button.test.interactions.js +42 -0
  10. package/dist/button-group.d.ts +7 -10
  11. package/dist/button-group.js +1 -1
  12. package/dist/button-group.stories.d.ts +1 -5
  13. package/dist/button-group.styles.js +18 -6
  14. package/dist/button-group.test.basics.js +113 -234
  15. package/dist/button-group.test.events.js +210 -263
  16. package/dist/button-group.test.focus.d.ts +1 -0
  17. package/dist/button-group.test.focus.js +39 -0
  18. package/dist/button-group.test.interactions.d.ts +1 -0
  19. package/dist/button-group.test.interactions.js +91 -0
  20. package/dist/button.test.basics.js +1 -1
  21. package/dist/checkbox-group.js +1 -1
  22. package/dist/checkbox-group.styles.js +1 -1
  23. package/dist/checkbox-group.test.basics.js +1 -1
  24. package/dist/checkbox-group.test.events.js +4 -4
  25. package/dist/checkbox-group.test.focus.js +4 -3
  26. package/dist/checkbox.d.ts +7 -1
  27. package/dist/checkbox.js +1 -1
  28. package/dist/checkbox.styles.js +10 -0
  29. package/dist/checkbox.test.events.js +4 -4
  30. package/dist/checkbox.test.focus.js +2 -2
  31. package/dist/{checkbox.test.states.js → checkbox.test.interactions.js} +24 -1
  32. package/dist/drawer.js +1 -1
  33. package/dist/dropdown.d.ts +6 -4
  34. package/dist/dropdown.js +1 -1
  35. package/dist/dropdown.option.d.ts +6 -2
  36. package/dist/dropdown.option.js +1 -1
  37. package/dist/dropdown.option.styles.js +13 -0
  38. package/dist/dropdown.option.test.basics.js +6 -3
  39. package/dist/dropdown.option.test.events.js +1 -1
  40. package/dist/dropdown.option.test.focus.js +1 -1
  41. package/dist/dropdown.option.test.interactions.multiple.js +1 -54
  42. package/dist/dropdown.option.test.interactions.single.js +51 -9
  43. package/dist/dropdown.styles.js +20 -19
  44. package/dist/dropdown.test.basics.js +143 -2
  45. package/dist/dropdown.test.basics.multiple.js +5 -2
  46. package/dist/dropdown.test.events.filterable.js +74 -0
  47. package/dist/dropdown.test.events.js +49 -160
  48. package/dist/dropdown.test.events.multiple.js +265 -8
  49. package/dist/dropdown.test.events.single.js +199 -2
  50. package/dist/dropdown.test.focus.filterable.js +9 -5
  51. package/dist/dropdown.test.focus.js +1 -1
  52. package/dist/dropdown.test.focus.multiple.js +1 -1
  53. package/dist/dropdown.test.focus.single.js +1 -1
  54. package/dist/dropdown.test.interactions.filterable.js +68 -11
  55. package/dist/dropdown.test.interactions.js +94 -5
  56. package/dist/dropdown.test.interactions.multiple.js +202 -5
  57. package/dist/dropdown.test.interactions.single.js +68 -6
  58. package/dist/form-controls-layout.test.basics.js +1 -1
  59. package/dist/icon-button.test.basics.js +1 -1
  60. package/dist/icons/checked.d.ts +1 -1
  61. package/dist/icons/checked.js +1 -1
  62. package/dist/icons/magnifying-glass.js +1 -1
  63. package/dist/input.d.ts +0 -6
  64. package/dist/input.js +1 -1
  65. package/dist/input.styles.js +7 -2
  66. package/dist/input.test.basics.js +19 -5
  67. package/dist/input.test.events.js +4 -4
  68. package/dist/input.test.focus.js +4 -4
  69. package/dist/input.test.translations.d.ts +1 -0
  70. package/dist/input.test.translations.js +38 -0
  71. package/dist/input.test.validity.js +133 -4
  72. package/dist/label.d.ts +1 -1
  73. package/dist/label.js +1 -1
  74. package/dist/label.styles.js +22 -13
  75. package/dist/label.test.basics.js +26 -24
  76. package/dist/library/expect-argument-error.js +1 -1
  77. package/dist/library/localize.d.ts +3 -1
  78. package/dist/menu.d.ts +3 -5
  79. package/dist/menu.js +1 -1
  80. package/dist/menu.options.test.basics.js +2 -2
  81. package/dist/menu.styles.js +1 -15
  82. package/dist/menu.test.basics.d.ts +1 -2
  83. package/dist/menu.test.basics.js +22 -6
  84. package/dist/menu.test.focus.d.ts +1 -0
  85. package/dist/menu.test.focus.js +13 -6
  86. package/dist/menu.test.interactions.js +212 -56
  87. package/dist/modal.icon-button.test.basics.js +1 -1
  88. package/dist/modal.js +1 -1
  89. package/dist/modal.styles.js +18 -13
  90. package/dist/modal.tertiary-icon.d.ts +0 -1
  91. package/dist/modal.tertiary-icon.js +1 -1
  92. package/dist/modal.tertiary-icon.test.basics.js +1 -1
  93. package/dist/modal.test.basics.js +1 -1
  94. package/dist/modal.test.events.js +10 -10
  95. package/dist/radio-group.js +1 -1
  96. package/dist/radio-group.styles.js +1 -1
  97. package/dist/radio-group.test.focus.js +3 -3
  98. package/dist/radio.d.ts +1 -0
  99. package/dist/radio.js +1 -1
  100. package/dist/radio.styles.js +33 -0
  101. package/dist/split-container.test.basics.js +4 -0
  102. package/dist/split-link.test.interactions.js +1 -1
  103. package/dist/styles/variables.css +1 -1
  104. package/dist/tab.d.ts +1 -1
  105. package/dist/tab.group.js +1 -1
  106. package/dist/tab.group.test.basics.js +1 -1
  107. package/dist/tab.group.test.interactions.js +198 -2
  108. package/dist/tab.js +1 -1
  109. package/dist/tab.panel.d.ts +1 -0
  110. package/dist/tab.panel.js +1 -1
  111. package/dist/tab.panel.styles.js +11 -1
  112. package/dist/tag.test.basics.js +2 -2
  113. package/dist/textarea.d.ts +0 -1
  114. package/dist/textarea.js +2 -2
  115. package/dist/textarea.stories.d.ts +3 -4
  116. package/dist/textarea.styles.js +14 -3
  117. package/dist/textarea.test.basics.js +80 -44
  118. package/dist/textarea.test.events.js +56 -41
  119. package/dist/textarea.test.translations.d.ts +1 -0
  120. package/dist/textarea.test.translations.js +34 -0
  121. package/dist/textarea.test.validity.js +104 -20
  122. package/dist/toasts.js +1 -1
  123. package/dist/toasts.styles.js +8 -1
  124. package/dist/toasts.test.basics.js +20 -0
  125. package/dist/toggle.js +1 -1
  126. package/dist/toggle.test.focus.js +1 -1
  127. package/dist/toggle.test.interactions.d.ts +1 -0
  128. package/dist/tooltip.d.ts +7 -5
  129. package/dist/tooltip.js +1 -1
  130. package/dist/tooltip.styles.js +90 -25
  131. package/dist/tooltip.test.basics.js +38 -3
  132. package/dist/tooltip.test.interactions.js +136 -34
  133. package/dist/translations/en.js +1 -1
  134. package/dist/translations/fr.js +1 -1
  135. package/dist/translations/ja.js +1 -1
  136. package/dist/tree.d.ts +0 -1
  137. package/dist/tree.item.d.ts +1 -2
  138. package/dist/tree.item.js +1 -1
  139. package/dist/tree.item.menu.d.ts +0 -1
  140. package/dist/tree.item.menu.js +1 -1
  141. package/dist/tree.js +1 -1
  142. package/dist/tree.test.basics.js +1 -1
  143. package/package.json +2 -4
  144. package/dist/drawer.test.floating-components.d.ts +0 -1
  145. package/dist/drawer.test.floating-components.js +0 -52
  146. package/dist/library/set-containing-block.d.ts +0 -15
  147. package/dist/library/set-containing-block.js +0 -1
  148. package/dist/modal.test.floating-components.js +0 -63
  149. /package/dist/{checkbox.test.states.d.ts → button-group.button.test.focus.d.ts} +0 -0
  150. /package/dist/{modal.test.floating-components.d.ts → checkbox.test.interactions.d.ts} +0 -0
  151. /package/dist/{toggle.test.states.d.ts → dropdown.test.events.filterable.d.ts} +0 -0
  152. /package/dist/{toggle.test.states.js → toggle.test.interactions.js} +0 -0
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-expressions */
2
2
  import * as sinon from 'sinon';
3
- import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
4
- import { sendKeys } from '@web/test-runner-commands';
3
+ import { aTimeout, assert, expect, fixture, html, oneEvent, } from '@open-wc/testing';
5
4
  import GlideCoreDropdown from './dropdown.js';
6
5
  import GlideCoreDropdownOption from './dropdown.option.js';
7
6
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
@@ -11,160 +10,6 @@ GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
11
10
  // timeout, which would make for a slow test. Its timeout can likely be
12
11
  // configured. But waiting a turn of the event loop, when which the event
13
12
  // will have been dispatched, gets the job done as well.
14
- it('dispatches a "change" event when an option is selected via click', async () => {
15
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
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
- component.querySelector('glide-core-dropdown-option')?.click();
31
- });
32
- const event = await oneEvent(component, 'change');
33
- expect(event instanceof Event).to.be.true;
34
- expect(event.bubbles).to.be.true;
35
- expect(spy.calledOnce).to.be.true;
36
- });
37
- it('dispatches a "change" event when an option is selected via Enter', async () => {
38
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
39
- <glide-core-dropdown-option
40
- label="One"
41
- value="one"
42
- ></glide-core-dropdown-option>
43
-
44
- <glide-core-dropdown-option
45
- label="Two"
46
- value="two"
47
- selected
48
- ></glide-core-dropdown-option>
49
- </glide-core-dropdown>`);
50
- const spy = sinon.spy();
51
- component.addEventListener('change', spy);
52
- // Activate the first option before selecting it. The second option is
53
- // currently active because it's selected.
54
- component
55
- .querySelector('glide-core-dropdown-option')
56
- ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
57
- component.focus();
58
- sendKeys({ press: 'Enter' });
59
- const event = await oneEvent(component, 'change');
60
- expect(event instanceof Event).to.be.true;
61
- expect(event.bubbles).to.be.true;
62
- expect(spy.calledOnce).to.be.true;
63
- });
64
- it('dispatches a "change" event when an option is selected via Space', async () => {
65
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
66
- <glide-core-dropdown-option
67
- label="One"
68
- value="one"
69
- ></glide-core-dropdown-option>
70
-
71
- <glide-core-dropdown-option
72
- label="Two"
73
- value="two"
74
- selected
75
- ></glide-core-dropdown-option>
76
- </glide-core-dropdown>`);
77
- const spy = sinon.spy();
78
- component.addEventListener('change', spy);
79
- // Activate the first option before selecting it. The second option is
80
- // currently active because it's selected.
81
- component
82
- .querySelector('glide-core-dropdown-option')
83
- ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
84
- component.focus();
85
- sendKeys({ press: ' ' });
86
- const event = await oneEvent(component, 'change');
87
- expect(event instanceof Event).to.be.true;
88
- expect(event.bubbles).to.be.true;
89
- expect(spy.calledOnce).to.be.true;
90
- });
91
- it('dispatches an "input" event when an option is selected via click', async () => {
92
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
93
- <glide-core-dropdown-option
94
- label="One"
95
- value="one"
96
- ></glide-core-dropdown-option>
97
-
98
- <glide-core-dropdown-option
99
- label="Two"
100
- value="two"
101
- selected
102
- ></glide-core-dropdown-option>
103
- </glide-core-dropdown>`);
104
- const spy = sinon.spy();
105
- component.addEventListener('input', spy);
106
- setTimeout(() => {
107
- component.querySelector('glide-core-dropdown-option')?.click();
108
- });
109
- const event = await oneEvent(component, 'input');
110
- expect(event instanceof Event).to.be.true;
111
- expect(event.bubbles).to.be.true;
112
- expect(spy.calledOnce).to.be.true;
113
- });
114
- it('dispatches an "input" event when an option is selected via Enter', async () => {
115
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
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
- // Activate the first option before selecting it. The second option is
130
- // currently active because it's selected.
131
- component
132
- .querySelector('glide-core-dropdown-option')
133
- ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
134
- component.focus();
135
- sendKeys({ press: 'Enter' });
136
- const event = await oneEvent(component, 'input');
137
- expect(event instanceof Event).to.be.true;
138
- expect(event.bubbles).to.be.true;
139
- expect(spy.calledOnce).to.be.true;
140
- });
141
- it('dispatches an "input" event when an option is selected via Space', async () => {
142
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
143
- <glide-core-dropdown-option
144
- label="One"
145
- value="one"
146
- ></glide-core-dropdown-option>
147
-
148
- <glide-core-dropdown-option
149
- label="Two"
150
- value="two"
151
- selected
152
- ></glide-core-dropdown-option>
153
- </glide-core-dropdown>`);
154
- const spy = sinon.spy();
155
- component.addEventListener('input', spy);
156
- // Activate the first option before selecting it. The second option is
157
- // currently active because it's selected.
158
- component
159
- .querySelector('glide-core-dropdown-option')
160
- ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
161
- component.focus();
162
- sendKeys({ press: ' ' });
163
- const event = await oneEvent(component, 'input');
164
- expect(event instanceof Event).to.be.true;
165
- expect(event.bubbles).to.be.true;
166
- expect(spy.calledOnce).to.be.true;
167
- });
168
13
  it('dispatches an "invalid" event on submit when required and no option is selected', async () => {
169
14
  const form = document.createElement('form');
170
15
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" required>
@@ -213,7 +58,7 @@ it('does not dispatch an "invalid" event when `checkValidity` is called when not
213
58
  component.addEventListener('invalid', spy);
214
59
  component.checkValidity();
215
60
  await aTimeout(0);
216
- expect(spy.notCalled).to.be.true;
61
+ expect(spy.callCount).to.equal(0);
217
62
  });
218
63
  it('does not dispatch an "invalid" event when `checkValidity` is called when required, disabled, and no option is selected', async () => {
219
64
  const form = document.createElement('form');
@@ -232,7 +77,7 @@ it('does not dispatch an "invalid" event when `checkValidity` is called when req
232
77
  component.addEventListener('invalid', spy);
233
78
  component.checkValidity();
234
79
  await aTimeout(0);
235
- expect(spy.notCalled).to.be.true;
80
+ expect(spy.callCount).to.equal(0);
236
81
  });
237
82
  it('does not dispatch an "invalid" event when `reportValidity` is called when not required,', async () => {
238
83
  const form = document.createElement('form');
@@ -246,7 +91,7 @@ it('does not dispatch an "invalid" event when `reportValidity` is called when no
246
91
  component.addEventListener('invalid', spy);
247
92
  component.reportValidity();
248
93
  await aTimeout(0);
249
- expect(spy.notCalled).to.be.true;
94
+ expect(spy.callCount).to.equal(0);
250
95
  });
251
96
  it('does not dispatch an "invalid" event when `reportValidity` is called when required, disabled, and no option is selected', async () => {
252
97
  const form = document.createElement('form');
@@ -265,5 +110,49 @@ it('does not dispatch an "invalid" event when `reportValidity` is called when re
265
110
  component.addEventListener('invalid', spy);
266
111
  component.reportValidity();
267
112
  await aTimeout(0);
268
- expect(spy.notCalled).to.be.true;
113
+ expect(spy.callCount).to.equal(0);
114
+ });
115
+ it('does not dispatch a "change" event when an option is selected programmatically', async () => {
116
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
117
+ <glide-core-dropdown-option
118
+ label="One"
119
+ value="one"
120
+ ></glide-core-dropdown-option>
121
+
122
+ <glide-core-dropdown-option
123
+ label="Two"
124
+ value="two"
125
+ ></glide-core-dropdown-option>
126
+ </glide-core-dropdown>`);
127
+ const spy = sinon.spy();
128
+ component.addEventListener('change', spy);
129
+ setTimeout(() => {
130
+ const option = component?.querySelector('glide-core-dropdown-option');
131
+ assert(option);
132
+ option.selected = true;
133
+ });
134
+ await aTimeout(0);
135
+ expect(spy.callCount).to.equal(0);
136
+ });
137
+ it('does not dispatch a "input" event when an option is selected programmatically', async () => {
138
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
139
+ <glide-core-dropdown-option
140
+ label="One"
141
+ value="one"
142
+ ></glide-core-dropdown-option>
143
+
144
+ <glide-core-dropdown-option
145
+ label="Two"
146
+ value="two"
147
+ ></glide-core-dropdown-option>
148
+ </glide-core-dropdown>`);
149
+ const spy = sinon.spy();
150
+ component.addEventListener('input', spy);
151
+ setTimeout(() => {
152
+ const option = component?.querySelector('glide-core-dropdown-option');
153
+ assert(option);
154
+ option.selected = true;
155
+ });
156
+ await aTimeout(0);
157
+ expect(spy.callCount).to.equal(0);
269
158
  });
@@ -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
  });