@gitlab/ui 44.1.0 → 46.0.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 (47) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/components/base/alert/alert.js +9 -1
  3. package/dist/components/base/new_dropdowns/base_dropdown/base_dropdown.js +8 -0
  4. package/dist/components/base/new_dropdowns/listbox/listbox.js +116 -18
  5. package/dist/utility_classes.css +1 -1
  6. package/dist/utility_classes.css.map +1 -1
  7. package/package.json +2 -2
  8. package/src/components/base/alert/alert.spec.js +13 -14
  9. package/src/components/base/alert/alert.vue +14 -1
  10. package/src/components/base/banner/banner.spec.js +4 -4
  11. package/src/components/base/datepicker/datepicker.spec.js +1 -1
  12. package/src/components/base/daterange_picker/daterange_picker.spec.js +4 -4
  13. package/src/components/base/drawer/drawer.spec.js +2 -2
  14. package/src/components/base/dropdown/dropdown.spec.js +5 -5
  15. package/src/components/base/filtered_search/filtered_search.spec.js +4 -4
  16. package/src/components/base/filtered_search/filtered_search_token.spec.js +9 -9
  17. package/src/components/base/filtered_search/filtered_search_token_segment.spec.js +12 -12
  18. package/src/components/base/form/form_textarea/form_textarea.spec.js +2 -2
  19. package/src/components/base/infinite_scroll/infinite_scroll.spec.js +6 -6
  20. package/src/components/base/label/label.spec.js +5 -5
  21. package/src/components/base/modal/modal.spec.js +1 -1
  22. package/src/components/base/nav/nav.spec.js +1 -1
  23. package/src/components/base/nav/nav_item_dropdown.spec.js +3 -3
  24. package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.vue +6 -0
  25. package/src/components/base/new_dropdowns/listbox/listbox.md +22 -0
  26. package/src/components/base/new_dropdowns/listbox/listbox.spec.js +101 -7
  27. package/src/components/base/new_dropdowns/listbox/listbox.stories.js +244 -20
  28. package/src/components/base/new_dropdowns/listbox/listbox.vue +138 -12
  29. package/src/components/base/paginated_list/paginated_list.spec.js +1 -1
  30. package/src/components/base/pagination/pagination.spec.js +2 -2
  31. package/src/components/base/search_box_by_click/search_box_by_click.spec.js +7 -7
  32. package/src/components/base/search_box_by_type/search_box_by_type.spec.js +2 -2
  33. package/src/components/base/sorting/sorting.spec.js +1 -1
  34. package/src/components/base/sorting/sorting_item.spec.js +2 -2
  35. package/src/components/base/tabs/tabs/scrollable_tabs.spec.js +1 -1
  36. package/src/components/base/tabs/tabs/tabs.spec.js +6 -6
  37. package/src/components/base/token/token.spec.js +1 -1
  38. package/src/components/base/token_selector/token_container.spec.js +1 -1
  39. package/src/components/base/token_selector/token_selector.spec.js +4 -4
  40. package/src/components/base/token_selector/token_selector_dropdown.spec.js +1 -1
  41. package/src/components/charts/column/column_chart.spec.js +1 -1
  42. package/src/components/charts/sparkline/sparkline.spec.js +2 -2
  43. package/src/directives/resize_observer/resize_observer.spec.js +5 -5
  44. package/src/scss/utilities.scss +0 -202
  45. package/src/scss/utility-mixins/display.scss +0 -35
  46. package/src/scss/utility-mixins/flex.scss +0 -7
  47. package/src/scss/utility-mixins/spacing.scss +0 -91
@@ -15,6 +15,8 @@ import {
15
15
  buttonSizeOptions,
16
16
  dropdownVariantOptions,
17
17
  } from '../../../../utils/constants';
18
+ import GlLoadingIcon from '../../loading_icon/loading_icon.vue';
19
+ import GlSearchBoxByType from '../../search_box_by_type/search_box_by_type.vue';
18
20
  import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
19
21
  import GlListboxItem from './listbox_item.vue';
20
22
  import GlListboxGroup from './listbox_group.vue';
@@ -22,6 +24,7 @@ import { isOption, itemsValidator, flattenedOptions } from './utils';
22
24
 
23
25
  export const ITEM_SELECTOR = '[role="option"]';
24
26
  const GROUP_TOP_BORDER_CLASSES = ['gl-border-t', 'gl-pt-3', 'gl-mt-3'];
27
+ export const SEARCH_INPUT_SELECTOR = '.gl-search-box-by-type-input';
25
28
 
26
29
  export default {
27
30
  events: {
@@ -32,6 +35,8 @@ export default {
32
35
  GlBaseDropdown,
33
36
  GlListboxItem,
34
37
  GlListboxGroup,
38
+ GlSearchBoxByType,
39
+ GlLoadingIcon,
35
40
  },
36
41
  model: {
37
42
  prop: 'selected',
@@ -124,6 +129,7 @@ export default {
124
129
  },
125
130
  /**
126
131
  * Set to "true" when dropdown content (items) is loading
132
+ * It will render a small loader in the dropdown toggle and make it disabled
127
133
  */
128
134
  loading: {
129
135
  type: Boolean,
@@ -164,18 +170,55 @@ export default {
164
170
  },
165
171
  /**
166
172
  * The `aria-labelledby` attribute value for the toggle button
173
+ * Provide the string of ids seperated by space
167
174
  */
168
- ariaLabelledby: {
175
+ toggleAriaLabelledBy: {
169
176
  type: String,
170
177
  required: false,
171
178
  default: null,
172
179
  },
180
+ /**
181
+ * The `aria-labelledby` attribute value for the list of options
182
+ * Provide the string of ids seperated by space
183
+ */
184
+ listAriaLabelledBy: {
185
+ type: String,
186
+ required: false,
187
+ default: null,
188
+ },
189
+ /**
190
+ * Enable search
191
+ */
192
+ searchable: {
193
+ type: Boolean,
194
+ required: false,
195
+ default: false,
196
+ },
197
+ /**
198
+ * Set to "true" when items search is in progress.
199
+ * It will display loading icon below the search input
200
+ */
201
+ searching: {
202
+ type: Boolean,
203
+ required: false,
204
+ default: false,
205
+ },
206
+ /**
207
+ * Message to be displayed when filtering produced no results
208
+ */
209
+ noResultsText: {
210
+ type: String,
211
+ required: false,
212
+ default: 'No results found',
213
+ },
173
214
  },
174
215
  data() {
175
216
  return {
176
217
  selectedValues: [],
177
218
  toggleId: uniqueId('dropdown-toggle-btn-'),
219
+ listboxId: uniqueId('listbox-'),
178
220
  nextFocusedItemIndex: null,
221
+ searchStr: '',
179
222
  };
180
223
  },
181
224
  computed: {
@@ -201,6 +244,17 @@ export default {
201
244
  .map((selected) => this.flattenedOptions.findIndex(({ value }) => value === selected))
202
245
  .sort();
203
246
  },
247
+ showList() {
248
+ return this.flattenedOptions.length && !this.searching;
249
+ },
250
+ showNoResultsText() {
251
+ return !this.flattenedOptions.length && !this.searching;
252
+ },
253
+ announceSRSearchResults() {
254
+ return (
255
+ this.searchable && !this.showNoResultsText && this.$scopedSlots['search-summary-sr-only']
256
+ );
257
+ },
204
258
  },
205
259
  watch: {
206
260
  selected: {
@@ -218,12 +272,22 @@ export default {
218
272
  },
219
273
  },
220
274
  methods: {
275
+ open() {
276
+ this.$refs.baseDropdown.open();
277
+ },
278
+ close() {
279
+ this.$refs.baseDropdown.close();
280
+ },
221
281
  groupClasses(index) {
222
282
  return index === 0 ? null : GROUP_TOP_BORDER_CLASSES;
223
283
  },
224
284
  onShow() {
225
285
  this.$nextTick(() => {
226
- this.focusItem(this.selectedIndices[0] ?? 0, this.getFocusableListItemElements());
286
+ if (this.searchable) {
287
+ this.focusSearchInput();
288
+ } else {
289
+ this.focusItem(this.selectedIndices[0] ?? 0, this.getFocusableListItemElements());
290
+ }
227
291
  /**
228
292
  * Emitted when dropdown is shown
229
293
  *
@@ -242,21 +306,33 @@ export default {
242
306
  this.nextFocusedItemIndex = null;
243
307
  },
244
308
  onKeydown(event) {
245
- const { code } = event;
309
+ const { code, target } = event;
246
310
  const elements = this.getFocusableListItemElements();
247
311
 
248
312
  if (elements.length < 1) return;
249
313
 
250
314
  let stop = true;
315
+ const isSearchInput = target.matches(SEARCH_INPUT_SELECTOR);
251
316
 
252
317
  if (code === HOME) {
253
318
  this.focusItem(0, elements);
254
319
  } else if (code === END) {
255
320
  this.focusItem(elements.length - 1, elements);
256
321
  } else if (code === ARROW_UP) {
257
- this.focusNextItem(event, elements, -1);
322
+ if (isSearchInput) {
323
+ return;
324
+ }
325
+ if (this.searchable && elements.indexOf(target) === 0) {
326
+ this.focusSearchInput();
327
+ } else {
328
+ this.focusNextItem(event, elements, -1);
329
+ }
258
330
  } else if (code === ARROW_DOWN) {
259
- this.focusNextItem(event, elements, 1);
331
+ if (isSearchInput) {
332
+ this.focusItem(0, elements);
333
+ } else {
334
+ this.focusNextItem(event, elements, 1);
335
+ }
260
336
  } else {
261
337
  stop = false;
262
338
  }
@@ -266,8 +342,8 @@ export default {
266
342
  }
267
343
  },
268
344
  getFocusableListItemElements() {
269
- const items = this.$refs.list.querySelectorAll(ITEM_SELECTOR);
270
- return Array.from(items);
345
+ const items = this.$refs.list?.querySelectorAll(ITEM_SELECTOR);
346
+ return Array.from(items || []);
271
347
  },
272
348
  focusNextItem(event, elements, offset) {
273
349
  const { target } = event;
@@ -283,11 +359,14 @@ export default {
283
359
  elements[index]?.focus();
284
360
  });
285
361
  },
286
- onSelect({ value }, isSelected) {
362
+ focusSearchInput() {
363
+ this.$refs.searchBox.focusInput();
364
+ },
365
+ onSelect(item, isSelected) {
287
366
  if (this.multiple) {
288
- this.onMultiSelect(value, isSelected);
367
+ this.onMultiSelect(item.value, isSelected);
289
368
  } else {
290
- this.onSingleSelect(value, isSelected);
369
+ this.onSingleSelect(item.value, isSelected);
291
370
  }
292
371
  },
293
372
  isSelected(item) {
@@ -318,6 +397,15 @@ export default {
318
397
  );
319
398
  }
320
399
  },
400
+ search(searchTerm) {
401
+ /**
402
+ * Emitted when the search query string is changed
403
+ *
404
+ * @event search
405
+ * @type {string}
406
+ */
407
+ this.$emit('search', searchTerm);
408
+ },
321
409
  isOption,
322
410
  },
323
411
  };
@@ -327,7 +415,7 @@ export default {
327
415
  <gl-base-dropdown
328
416
  ref="baseDropdown"
329
417
  aria-haspopup="listbox"
330
- :aria-labelledby="ariaLabelledby"
418
+ :aria-labelledby="toggleAriaLabelledBy"
331
419
  :toggle-id="toggleId"
332
420
  :toggle-text="listboxToggleText"
333
421
  :toggle-class="toggleClass"
@@ -346,10 +434,29 @@ export default {
346
434
  <!-- @slot Content to display in dropdown header -->
347
435
  <slot name="header"></slot>
348
436
 
437
+ <div v-if="searchable" class="gl-border-b-1 gl-border-b-solid gl-border-b-gray-200">
438
+ <gl-search-box-by-type
439
+ ref="searchBox"
440
+ v-model="searchStr"
441
+ :aria-owns="listboxId"
442
+ data-testid="listbox-search-input"
443
+ @input="search"
444
+ @keydown="onKeydown"
445
+ />
446
+ <gl-loading-icon
447
+ v-if="searching"
448
+ data-testid="listbox-search-loader"
449
+ size="md"
450
+ class="gl-my-3"
451
+ />
452
+ </div>
453
+
349
454
  <component
350
455
  :is="listboxTag"
456
+ v-if="showList"
457
+ id="listbox"
351
458
  ref="list"
352
- :aria-labelledby="toggleId"
459
+ :aria-labelledby="listAriaLabelledBy || toggleId"
353
460
  role="listbox"
354
461
  class="gl-new-dropdown-contents gl-list-style-none gl-pl-0 gl-mb-0"
355
462
  tabindex="-1"
@@ -395,6 +502,25 @@ export default {
395
502
  </template>
396
503
  </template>
397
504
  </component>
505
+
506
+ <span
507
+ v-if="announceSRSearchResults"
508
+ data-testid="listbox-number-of-results"
509
+ class="gl-sr-only"
510
+ aria-live="assertive"
511
+ >
512
+ <!-- @slot Text read by screen reader announcing a number of search results -->
513
+ <slot name="search-summary-sr-only"></slot>
514
+ </span>
515
+
516
+ <div
517
+ v-else-if="showNoResultsText"
518
+ aria-live="assertive"
519
+ class="gl-pl-7 gl-pr-5 gl-pt-3 gl-font-base gl-text-gray-600"
520
+ data-testid="listbox-no-results-text"
521
+ >
522
+ {{ noResultsText }}
523
+ </div>
398
524
  <!-- @slot Content to display in dropdown footer -->
399
525
  <slot name="footer"></slot>
400
526
  </gl-base-dropdown>
@@ -161,7 +161,7 @@ describe('Paginated List', () => {
161
161
  it('has search enabled by default', () => {
162
162
  createComponent();
163
163
 
164
- expect(wrapper.findComponent(GlSearchBoxByType).exists()).toBeTruthy();
164
+ expect(wrapper.findComponent(GlSearchBoxByType).exists()).toBe(true);
165
165
  });
166
166
 
167
167
  it('has search disabled when filterable prop set to false', () => {
@@ -63,7 +63,7 @@ describe('pagination component', () => {
63
63
  });
64
64
  await wrapper.vm.$nextTick();
65
65
 
66
- expect(wrapper.html()).toBeFalsy();
66
+ expect(wrapper.html()).toBe('');
67
67
  });
68
68
 
69
69
  it('supports slots customization', () => {
@@ -114,7 +114,7 @@ describe('pagination component', () => {
114
114
  const nextButton = buttons.at(buttons.length - 1);
115
115
  nextButton.trigger('click');
116
116
 
117
- expect(wrapper.emitted('input')).toBeTruthy();
117
+ expect(wrapper.emitted('input')).toHaveLength(1);
118
118
  expect(wrapper.emitted('input')[0]).toEqual([2]);
119
119
  });
120
120
 
@@ -33,7 +33,7 @@ describe('search box by click component', () => {
33
33
  wrapper.findComponent({ ref: 'input' }).vm.$emit('input', 'new value');
34
34
 
35
35
  await wrapper.vm.$nextTick();
36
- expect(wrapper.emitted().input).toEqual([['new value']]);
36
+ expect(wrapper.emitted('input')).toEqual([['new value']]);
37
37
  });
38
38
 
39
39
  it('does not emit an input event when input is updated to the same value', async () => {
@@ -41,7 +41,7 @@ describe('search box by click component', () => {
41
41
 
42
42
  await wrapper.setProps({ value: 'another value' });
43
43
 
44
- expect(wrapper.emitted().input).toBe(undefined);
44
+ expect(wrapper.emitted('input')).toBe(undefined);
45
45
  });
46
46
 
47
47
  it('does not displays history dropdown by default', () => {
@@ -70,7 +70,7 @@ describe('search box by click component', () => {
70
70
  findClearIcon().vm.$emit('click');
71
71
 
72
72
  await wrapper.vm.$nextTick();
73
- expect(wrapper.emitted().input).toEqual([['']]);
73
+ expect(wrapper.emitted('input')).toEqual([['']]);
74
74
  });
75
75
 
76
76
  it('emits clear event when clicked', async () => {
@@ -78,7 +78,7 @@ describe('search box by click component', () => {
78
78
  findClearIcon().vm.$emit('click');
79
79
  await wrapper.vm.$nextTick();
80
80
 
81
- expect(wrapper.emitted().clear).toHaveLength(1);
81
+ expect(wrapper.emitted('clear')).toHaveLength(1);
82
82
  });
83
83
  });
84
84
 
@@ -109,7 +109,7 @@ describe('search box by click component', () => {
109
109
  wrapper.findComponent(GlDropdownItem).vm.$emit('click');
110
110
 
111
111
  await wrapper.vm.$nextTick();
112
- expect(wrapper.emitted().input[0]).toEqual(['one']);
112
+ expect(wrapper.emitted('input')[0]).toEqual(['one']);
113
113
  expect(wrapper.emitted()['history-item-selected'][0]).toEqual(['one']);
114
114
  });
115
115
  });
@@ -149,7 +149,7 @@ describe('search box by click component', () => {
149
149
  wrapper.findComponent(GlFormInput).vm.$emit('keydown', { type: 'key', keyCode: 13 });
150
150
 
151
151
  await wrapper.vm.$nextTick();
152
- expect(wrapper.emitted().submit[0]).toEqual(['some-input']);
152
+ expect(wrapper.emitted('submit')[0]).toEqual(['some-input']);
153
153
  });
154
154
 
155
155
  it('emits submit event when search button is pressed', async () => {
@@ -157,7 +157,7 @@ describe('search box by click component', () => {
157
157
  findSearchButton().vm.$emit('click');
158
158
 
159
159
  await wrapper.vm.$nextTick();
160
- expect(wrapper.emitted().submit[0]).toEqual(['some-input']);
160
+ expect(wrapper.emitted('submit')[0]).toEqual(['some-input']);
161
161
  });
162
162
 
163
163
  it('adds `searchButtonAttributes` prop to search button', () => {
@@ -40,7 +40,7 @@ describe('search box by type component', () => {
40
40
  it('emits empty value when clicked', () => {
41
41
  findClearIcon().vm.$emit('click', { stopPropagation: jest.fn() });
42
42
 
43
- expect(wrapper.emitted().input).toEqual([['']]);
43
+ expect(wrapper.emitted('input')).toEqual([['']]);
44
44
  });
45
45
  });
46
46
 
@@ -59,7 +59,7 @@ describe('search box by type component', () => {
59
59
  it(`emits ${modelEvent} event when input value changes`, () => {
60
60
  findInput().setValue(newValue);
61
61
 
62
- expect(wrapper.emitted().input).toEqual([[newValue]]);
62
+ expect(wrapper.emitted('input')).toEqual([[newValue]]);
63
63
  });
64
64
  });
65
65
 
@@ -85,7 +85,7 @@ describe('sorting component', () => {
85
85
 
86
86
  selectDirectionButton().trigger('click');
87
87
 
88
- expect(wrapper.emitted().sortDirectionChange[0]).toEqual([true]);
88
+ expect(wrapper.emitted('sortDirectionChange')[0]).toEqual([true]);
89
89
  });
90
90
 
91
91
  it('should allow custom sort tooltip to be applied', () => {
@@ -36,7 +36,7 @@ describe('sorting item component', () => {
36
36
  it('does not show the check icon when the active prop is not provided', () => {
37
37
  createComponent();
38
38
 
39
- expect(findActiveIcon().exists()).toBeTruthy();
39
+ expect(findActiveIcon().exists()).toBe(true);
40
40
  expect(findActiveIcon().classes()).toContain('inactive');
41
41
  });
42
42
 
@@ -45,7 +45,7 @@ describe('sorting item component', () => {
45
45
  active: true,
46
46
  });
47
47
 
48
- expect(findActiveIcon().exists()).toBeTruthy();
48
+ expect(findActiveIcon().exists()).toBe(true);
49
49
  expect(findActiveIcon().classes()).not.toContain('inactive');
50
50
  });
51
51
 
@@ -88,7 +88,7 @@ describe('GlScrollableTabs', () => {
88
88
  });
89
89
 
90
90
  it('passes props through', () => {
91
- expect(NAV_CLASS).toBeTruthy();
91
+ expect(NAV_CLASS).toBe('gl-scrollable-tabs-nav');
92
92
  expect(wrapper.findComponent(GlTabs).props()).toMatchObject({
93
93
  ...TEST_DEFAULT_PROPS,
94
94
  navClass: [NAV_CLASS, TEST_DEFAULT_PROPS.navClass],
@@ -234,9 +234,9 @@ describe('tabs component', () => {
234
234
 
235
235
  // `input` event should only be fired if the active tab changes.
236
236
  if (expectedActiveTabIndex > 0) {
237
- expect(wrapper.emitted().input[1]).toEqual([expectedActiveTabIndex]);
237
+ expect(wrapper.emitted('input')[1]).toEqual([expectedActiveTabIndex]);
238
238
  } else {
239
- expect(wrapper.emitted().input[1]).toBeUndefined();
239
+ expect(wrapper.emitted('input')[1]).toBeUndefined();
240
240
  }
241
241
  });
242
242
  }
@@ -339,8 +339,8 @@ describe('tabs component', () => {
339
339
 
340
340
  await nextTick();
341
341
 
342
- expect(wrapper.emitted().input[0]).toEqual([1]);
343
- expect(wrapper.emitted().input[1]).toEqual([1]);
342
+ expect(wrapper.emitted('input')[0]).toEqual([1]);
343
+ expect(wrapper.emitted('input')[1]).toEqual([1]);
344
344
  });
345
345
  });
346
346
  });
@@ -352,7 +352,7 @@ describe('tabs component', () => {
352
352
 
353
353
  await nextTick();
354
354
 
355
- expect(wrapper.emitted().input[0]).toEqual([0]);
355
+ expect(wrapper.emitted('input')[0]).toEqual([0]);
356
356
  });
357
357
  });
358
358
 
@@ -363,7 +363,7 @@ describe('tabs component', () => {
363
363
  await nextTick();
364
364
  await findTabByText('Second').trigger('click');
365
365
 
366
- expect(wrapper.emitted().input[1]).toEqual([1]);
366
+ expect(wrapper.emitted('input')[1]).toEqual([1]);
367
367
  });
368
368
  });
369
369
 
@@ -17,7 +17,7 @@ describe('Token component', () => {
17
17
  it('emits close when "x" is clicked', () => {
18
18
  wrapper = createComponent();
19
19
  findIcon(wrapper).vm.$emit('click');
20
- expect(wrapper.emitted().close).toBeTruthy();
20
+ expect(wrapper.emitted('close')).toHaveLength(1);
21
21
  });
22
22
 
23
23
  it('hides the icon when view-only', () => {
@@ -205,7 +205,7 @@ describe('GlTokenContainer', () => {
205
205
  describe('when escape key is pressed', () => {
206
206
  it('fires `cancel-focus` event', async () => {
207
207
  await setup(0, keyboard.escape);
208
- expect(wrapper.emitted('cancel-focus')).toBeTruthy();
208
+ expect(wrapper.emitted('cancel-focus')).toHaveLength(1);
209
209
  });
210
210
  });
211
211
 
@@ -398,7 +398,7 @@ describe('GlTokenSelector', () => {
398
398
  });
399
399
 
400
400
  it('fires `focus` event', () => {
401
- expect(wrapper.emitted('focus')).toBeTruthy();
401
+ expect(wrapper.emitted('focus')).toHaveLength(1);
402
402
  });
403
403
  });
404
404
 
@@ -414,7 +414,7 @@ describe('GlTokenSelector', () => {
414
414
  });
415
415
 
416
416
  it('fires `blur` event', () => {
417
- expect(wrapper.emitted('blur')).toBeTruthy();
417
+ expect(wrapper.emitted('blur')).toHaveLength(1);
418
418
  });
419
419
 
420
420
  it('removes focus class from main container', () => {
@@ -566,7 +566,7 @@ describe('GlTokenSelector', () => {
566
566
 
567
567
  textInput.trigger('keydown');
568
568
 
569
- expect(wrapper.emitted('keydown')).toBeTruthy();
569
+ expect(wrapper.emitted('keydown')).toHaveLength(1);
570
570
  });
571
571
  });
572
572
  });
@@ -624,7 +624,7 @@ describe('GlTokenSelector', () => {
624
624
 
625
625
  container.trigger('click');
626
626
 
627
- expect(wrapper.emitted('focus')).toBeTruthy();
627
+ expect(wrapper.emitted('focus')).toHaveLength(1);
628
628
  });
629
629
  });
630
630
 
@@ -314,7 +314,7 @@ describe('GlTokenSelectorDropdown', () => {
314
314
 
315
315
  dropdownEventHandlers.handleDownArrow();
316
316
 
317
- expect(wrapper.emitted('show')).toBeTruthy();
317
+ expect(wrapper.emitted('show')).toHaveLength(1);
318
318
  });
319
319
  });
320
320
 
@@ -55,7 +55,7 @@ describe('column chart component', () => {
55
55
  it('emits "created" when onCreated is called', () => {
56
56
  wrapper.vm.onCreated(wrapper.vm.chart);
57
57
 
58
- expect(wrapper.emitted('created')).toBeTruthy();
58
+ expect(wrapper.emitted('created')).toHaveLength(1);
59
59
  });
60
60
 
61
61
  it('calls event listener when "chartItemClicked" is emitted on the Chart component', () => {
@@ -119,7 +119,7 @@ describe('sparkline chart component', () => {
119
119
  });
120
120
 
121
121
  it('shows the tooltip when mousing over an axis point in the component', async () => {
122
- expect(getTooltip().attributes('show')).toBeFalsy();
122
+ expect(getTooltip().attributes('show')).toBe(undefined);
123
123
 
124
124
  const mockData = { seriesData: [{ data: [5, 8] }] };
125
125
  getXAxisLabelFormatter()(mockData);
@@ -137,7 +137,7 @@ describe('sparkline chart component', () => {
137
137
  wrapper.trigger('mouseleave');
138
138
  await wrapper.vm.$nextTick();
139
139
 
140
- expect(getTooltip().attributes('show')).toBeFalsy();
140
+ expect(getTooltip().attributes('show')).toBe(undefined);
141
141
  });
142
142
 
143
143
  it('adds the right content to the tooltip', async () => {
@@ -76,15 +76,15 @@ describe('resize observer directive', () => {
76
76
  });
77
77
 
78
78
  expect(observersCount()).toBe(1);
79
- expect(wrapper.element.glResizeHandler).not.toBeFalsy();
79
+ expect(wrapper.element.glResizeHandler).not.toBe(undefined);
80
80
 
81
81
  await wrapper.setData({ isEnabled: false });
82
82
 
83
- expect(wrapper.element.glResizeHandler).toBeFalsy();
83
+ expect(wrapper.element.glResizeHandler).toBe(undefined);
84
84
 
85
85
  await wrapper.setData({ isEnabled: true });
86
86
 
87
- expect(wrapper.element.glResizeHandler).not.toBeFalsy();
87
+ expect(wrapper.element.glResizeHandler).not.toBe(undefined);
88
88
  });
89
89
 
90
90
  it('does a clean up when the component is destroyed', () => {
@@ -92,11 +92,11 @@ describe('resize observer directive', () => {
92
92
 
93
93
  const { element } = wrapper;
94
94
 
95
- expect(element.glResizeHandler).not.toBeFalsy();
95
+ expect(element.glResizeHandler).not.toBe(undefined);
96
96
 
97
97
  wrapper.destroy();
98
98
 
99
- expect(element.glResizeHandler).toBeFalsy();
99
+ expect(element.glResizeHandler).toBe(undefined);
100
100
  });
101
101
 
102
102
  describe('check directive value', () => {