@gitlab/ui 78.2.2 → 78.2.3
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.
- package/CHANGELOG.md +8 -0
- package/dist/components/base/new_dropdowns/base_dropdown/base_dropdown.js +3 -2
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/package.json +1 -1
- package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.spec.js +26 -0
- package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.vue +3 -1
- package/src/components/base/new_dropdowns/listbox/listbox.spec.js +14 -0
- package/src/components/experimental/duo/chat/duo_chat.spec.js +33 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [78.2.3](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.2.2...v78.2.3) (2024-03-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **GlBaseDropdown:** Check focused element before closing the dropdown ([54948dd](https://gitlab.com/gitlab-org/gitlab-ui/commit/54948dd3d8848f5ac0fc8d3cb225745401fbe7ea))
|
|
7
|
+
* **GlBaseDropdown:** Close menu with escape key on toggle ([990f65d](https://gitlab.com/gitlab-org/gitlab-ui/commit/990f65d07b831a784ddb8ec1c494e4e055d54c5c))
|
|
8
|
+
|
|
1
9
|
## [78.2.2](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.2.1...v78.2.2) (2024-03-20)
|
|
2
10
|
|
|
3
11
|
|
|
@@ -376,8 +376,9 @@ var script = {
|
|
|
376
376
|
if (!this.visible) {
|
|
377
377
|
return;
|
|
378
378
|
}
|
|
379
|
+
const hadFocusWithin = this.$el.contains(document.activeElement);
|
|
379
380
|
const hasToggled = await this.toggle(event);
|
|
380
|
-
if (!
|
|
381
|
+
if (!hadFocusWithin) {
|
|
381
382
|
return;
|
|
382
383
|
}
|
|
383
384
|
if (hasToggled) {
|
|
@@ -424,7 +425,7 @@ var script = {
|
|
|
424
425
|
const __vue_script__ = script;
|
|
425
426
|
|
|
426
427
|
/* template */
|
|
427
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"outside",rawName:"v-outside",value:(_vm.close),expression:"close"}],class:[_vm.$options.BASE_DROPDOWN_CLASS, { 'gl-display-block!': _vm.block }]},[_c(_vm.toggleComponent,_vm._g(_vm._b({ref:"toggle",tag:"component",attrs:{"id":_vm.toggleId,"data-testid":"base-dropdown-toggle"}},'component',_vm.toggleAttributes,false),_vm.toggleListeners),[_vm._t("toggle",function(){return [_c('span',{staticClass:"gl-new-dropdown-button-text",class:{ 'gl-sr-only': _vm.textSrOnly }},[_vm._v("\n "+_vm._s(_vm.toggleText)+"\n ")]),_vm._v(" "),(!_vm.noCaret)?_c('gl-icon',{staticClass:"gl-button-icon gl-new-dropdown-chevron",attrs:{"name":"chevron-down"}}):_vm._e()]})],2),_vm._v(" "),_c('div',{ref:"content",staticClass:"gl-new-dropdown-panel",class:_vm.panelClasses,attrs:{"id":_vm.baseDropdownId,"data-testid":"base-dropdown-menu"},on:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }$event.stopPropagation();$event.preventDefault();return _vm.closeAndFocus.apply(null, arguments)}}},[_c('div',{staticClass:"gl-new-dropdown-inner"},[_vm._t("default")],2)])],1)};
|
|
428
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"outside",rawName:"v-outside",value:(_vm.close),expression:"close"}],class:[_vm.$options.BASE_DROPDOWN_CLASS, { 'gl-display-block!': _vm.block }]},[_c(_vm.toggleComponent,_vm._g(_vm._b({ref:"toggle",tag:"component",attrs:{"id":_vm.toggleId,"data-testid":"base-dropdown-toggle"},on:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }$event.stopPropagation();$event.preventDefault();return _vm.close.apply(null, arguments)}}},'component',_vm.toggleAttributes,false),_vm.toggleListeners),[_vm._t("toggle",function(){return [_c('span',{staticClass:"gl-new-dropdown-button-text",class:{ 'gl-sr-only': _vm.textSrOnly }},[_vm._v("\n "+_vm._s(_vm.toggleText)+"\n ")]),_vm._v(" "),(!_vm.noCaret)?_c('gl-icon',{staticClass:"gl-button-icon gl-new-dropdown-chevron",attrs:{"name":"chevron-down"}}):_vm._e()]})],2),_vm._v(" "),_c('div',{ref:"content",staticClass:"gl-new-dropdown-panel",class:_vm.panelClasses,attrs:{"id":_vm.baseDropdownId,"data-testid":"base-dropdown-menu"},on:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }$event.stopPropagation();$event.preventDefault();return _vm.closeAndFocus.apply(null, arguments)}}},[_c('div',{staticClass:"gl-new-dropdown-inner"},[_vm._t("default")],2)])],1)};
|
|
428
429
|
var __vue_staticRenderFns__ = [];
|
|
429
430
|
|
|
430
431
|
/* style */
|
package/dist/tokens/js/tokens.js
CHANGED
package/package.json
CHANGED
|
@@ -337,6 +337,20 @@ describe('base dropdown', () => {
|
|
|
337
337
|
expect(toggle.element).toHaveFocus();
|
|
338
338
|
});
|
|
339
339
|
|
|
340
|
+
it('should close menu on Escape when focus is on toggle', async () => {
|
|
341
|
+
const toggle = findDefaultDropdownToggle();
|
|
342
|
+
const menu = findDropdownMenu();
|
|
343
|
+
|
|
344
|
+
await toggle.trigger('click');
|
|
345
|
+
expect(menu.classes('gl-display-block!')).toBe(true);
|
|
346
|
+
expect(toggle.attributes('aria-expanded')).toBe('true');
|
|
347
|
+
|
|
348
|
+
await toggle.trigger('keydown.esc');
|
|
349
|
+
expect(menu.classes('gl-display-block!')).toBe(false);
|
|
350
|
+
expect(toggle.attributes('aria-expanded')).toBe('false');
|
|
351
|
+
expect(wrapper.emitted(GL_DROPDOWN_HIDDEN)).toHaveLength(1);
|
|
352
|
+
});
|
|
353
|
+
|
|
340
354
|
describe('when the consumer takes over the focus', () => {
|
|
341
355
|
let consumerButton;
|
|
342
356
|
|
|
@@ -487,6 +501,18 @@ describe('base dropdown', () => {
|
|
|
487
501
|
expect(wrapper.emitted(GL_DROPDOWN_HIDDEN)).toHaveLength(1);
|
|
488
502
|
expect(toggle.find(`[data-testid="${customToggleTestId}"]`).element).toHaveFocus();
|
|
489
503
|
});
|
|
504
|
+
|
|
505
|
+
it('should close menu on Escape when focus is on toggle', async () => {
|
|
506
|
+
const toggle = findCustomDropdownToggle();
|
|
507
|
+
const menu = findDropdownMenu();
|
|
508
|
+
|
|
509
|
+
await toggle.trigger('click');
|
|
510
|
+
expect(menu.classes('gl-display-block!')).toBe(true);
|
|
511
|
+
|
|
512
|
+
await toggle.trigger('keydown.esc');
|
|
513
|
+
expect(menu.classes('gl-display-block!')).toBe(false);
|
|
514
|
+
expect(wrapper.emitted(GL_DROPDOWN_HIDDEN)).toHaveLength(1);
|
|
515
|
+
});
|
|
490
516
|
});
|
|
491
517
|
|
|
492
518
|
it('should emit `GL_DROPDOWN_FOCUS_CONTENT` event on `ARROW_DOWN`', () => {
|
|
@@ -400,9 +400,10 @@ export default {
|
|
|
400
400
|
return;
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
+
const hadFocusWithin = this.$el.contains(document.activeElement);
|
|
403
404
|
const hasToggled = await this.toggle(event);
|
|
404
405
|
|
|
405
|
-
if (!
|
|
406
|
+
if (!hadFocusWithin) {
|
|
406
407
|
return;
|
|
407
408
|
}
|
|
408
409
|
|
|
@@ -459,6 +460,7 @@ export default {
|
|
|
459
460
|
ref="toggle"
|
|
460
461
|
data-testid="base-dropdown-toggle"
|
|
461
462
|
v-on="toggleListeners"
|
|
463
|
+
@keydown.esc.stop.prevent="close"
|
|
462
464
|
>
|
|
463
465
|
<!-- @slot Custom toggle button content -->
|
|
464
466
|
<slot name="toggle">
|
|
@@ -59,6 +59,7 @@ describe('GlCollapsibleListbox', () => {
|
|
|
59
59
|
const findSelectAllButton = () => wrapper.find("[data-testid='listbox-select-all-button']");
|
|
60
60
|
const findIntersectionObserver = () => wrapper.findComponent(GlIntersectionObserver);
|
|
61
61
|
const findDropdownMenu = () => wrapper.find("[data-testid='base-dropdown-menu']");
|
|
62
|
+
const findDropdownToggle = () => wrapper.find("[data-testid='base-dropdown-toggle'");
|
|
62
63
|
|
|
63
64
|
it('passes custom offset to the base dropdown', () => {
|
|
64
65
|
const dropdownOffset = { mainAxis: 10, crossAxis: 40 };
|
|
@@ -927,4 +928,17 @@ describe('GlCollapsibleListbox', () => {
|
|
|
927
928
|
expect(findDropdownMenu().classes()).not.toContain('gl-display-block!');
|
|
928
929
|
});
|
|
929
930
|
});
|
|
931
|
+
|
|
932
|
+
it('focuses the toggle when closed by ESC key while item had focus', async () => {
|
|
933
|
+
buildWrapper({
|
|
934
|
+
selected: mockOptions[1].value,
|
|
935
|
+
items: mockOptions,
|
|
936
|
+
startOpened: true,
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
await nextTick();
|
|
940
|
+
findListItem(1).trigger('keydown.esc');
|
|
941
|
+
await nextTick();
|
|
942
|
+
expect(findDropdownToggle().element).toHaveFocus();
|
|
943
|
+
});
|
|
930
944
|
});
|
|
@@ -39,16 +39,11 @@ const generatePartialSlashCommands = () => {
|
|
|
39
39
|
describe('GlDuoChat', () => {
|
|
40
40
|
let wrapper;
|
|
41
41
|
|
|
42
|
-
const createComponent = ({ propsData = {},
|
|
42
|
+
const createComponent = ({ propsData = {}, slots = {} } = {}) => {
|
|
43
43
|
jest.spyOn(DuoChatLoader.methods, 'computeTransitionWidth').mockImplementation();
|
|
44
44
|
|
|
45
45
|
wrapper = shallowMount(GlDuoChat, {
|
|
46
46
|
propsData,
|
|
47
|
-
data() {
|
|
48
|
-
return {
|
|
49
|
-
...data,
|
|
50
|
-
};
|
|
51
|
-
},
|
|
52
47
|
slots,
|
|
53
48
|
stubs: {
|
|
54
49
|
DuoChatLoader,
|
|
@@ -76,6 +71,8 @@ describe('GlDuoChat', () => {
|
|
|
76
71
|
const findSlashCommands = () => wrapper.findAllComponents(GlDropdownItem);
|
|
77
72
|
const findSelectedSlashCommand = () => wrapper.find('.active-command');
|
|
78
73
|
|
|
74
|
+
const setPromptInput = (val) => findChatInput().vm.$emit('input', val);
|
|
75
|
+
|
|
79
76
|
beforeEach(() => {
|
|
80
77
|
createComponent();
|
|
81
78
|
});
|
|
@@ -321,8 +318,8 @@ describe('GlDuoChat', () => {
|
|
|
321
318
|
`('$event should $action the prompt form', ({ trigger, expectEmitted } = {}) => {
|
|
322
319
|
createComponent({
|
|
323
320
|
propsData: { messages: [], isChatAvailable: true },
|
|
324
|
-
data: { prompt: promptStr },
|
|
325
321
|
});
|
|
322
|
+
setPromptInput(promptStr);
|
|
326
323
|
trigger();
|
|
327
324
|
expect(wrapper.emitted('send-chat-prompt')).toEqual(expectEmitted);
|
|
328
325
|
});
|
|
@@ -335,8 +332,8 @@ describe('GlDuoChat', () => {
|
|
|
335
332
|
`('prevents submission when loading $desc', ({ msgs } = {}) => {
|
|
336
333
|
createComponent({
|
|
337
334
|
propsData: { isChatAvailable: true, isLoading: true, messages: msgs },
|
|
338
|
-
data: { prompt: promptStr },
|
|
339
335
|
});
|
|
336
|
+
setPromptInput(promptStr);
|
|
340
337
|
clickSubmit();
|
|
341
338
|
expect(wrapper.emitted('send-chat-prompt')).toBe(undefined);
|
|
342
339
|
});
|
|
@@ -352,18 +349,21 @@ describe('GlDuoChat', () => {
|
|
|
352
349
|
])('prevents submission when streaming (messages = "%o")', (msgs = []) => {
|
|
353
350
|
createComponent({
|
|
354
351
|
propsData: { isChatAvailable: true, messages: msgs },
|
|
355
|
-
data: { prompt: promptStr },
|
|
356
352
|
});
|
|
353
|
+
setPromptInput(promptStr);
|
|
357
354
|
clickSubmit();
|
|
358
355
|
expect(wrapper.emitted('send-chat-prompt')).toBe(undefined);
|
|
359
356
|
});
|
|
360
357
|
|
|
361
358
|
it('resets the prompt after form submission', async () => {
|
|
362
359
|
const prompt = 'foo';
|
|
363
|
-
createComponent(
|
|
360
|
+
createComponent();
|
|
361
|
+
await setPromptInput(prompt);
|
|
364
362
|
expect(findChatInput().props('value')).toBe(prompt);
|
|
363
|
+
|
|
365
364
|
clickSubmit();
|
|
366
365
|
await nextTick();
|
|
366
|
+
|
|
367
367
|
expect(findChatInput().props('value')).toBe('');
|
|
368
368
|
});
|
|
369
369
|
|
|
@@ -372,7 +372,8 @@ describe('GlDuoChat', () => {
|
|
|
372
372
|
jest.spyOn(HTMLElement.prototype, 'focus').mockImplementation(function focusMockImpl() {
|
|
373
373
|
focusSpy(this);
|
|
374
374
|
});
|
|
375
|
-
createComponent(
|
|
375
|
+
createComponent();
|
|
376
|
+
await setPromptInput('TEST!');
|
|
376
377
|
|
|
377
378
|
clickSubmit();
|
|
378
379
|
await nextTick();
|
|
@@ -385,8 +386,8 @@ describe('GlDuoChat', () => {
|
|
|
385
386
|
it('emits the event with the reset prompt', () => {
|
|
386
387
|
createComponent({
|
|
387
388
|
propsData: { messages, isChatAvailable: true },
|
|
388
|
-
data: { prompt: CHAT_RESET_MESSAGE },
|
|
389
389
|
});
|
|
390
|
+
setPromptInput(CHAT_RESET_MESSAGE);
|
|
390
391
|
clickSubmit();
|
|
391
392
|
|
|
392
393
|
expect(wrapper.emitted('send-chat-prompt')).toEqual([[CHAT_RESET_MESSAGE]]);
|
|
@@ -396,8 +397,8 @@ describe('GlDuoChat', () => {
|
|
|
396
397
|
it('reset does nothing when chat is loading', () => {
|
|
397
398
|
createComponent({
|
|
398
399
|
propsData: { messages, isChatAvailable: true, isLoading: true },
|
|
399
|
-
data: { prompt: CHAT_RESET_MESSAGE },
|
|
400
400
|
});
|
|
401
|
+
setPromptInput(CHAT_RESET_MESSAGE);
|
|
401
402
|
clickSubmit();
|
|
402
403
|
|
|
403
404
|
expect(wrapper.emitted('send-chat-prompt')).toBeUndefined();
|
|
@@ -407,8 +408,8 @@ describe('GlDuoChat', () => {
|
|
|
407
408
|
it('reset does nothing when there are no messages', () => {
|
|
408
409
|
createComponent({
|
|
409
410
|
propsData: { messages: [], isChatAvailable: true },
|
|
410
|
-
data: { prompt: CHAT_RESET_MESSAGE },
|
|
411
411
|
});
|
|
412
|
+
setPromptInput(CHAT_RESET_MESSAGE);
|
|
412
413
|
clickSubmit();
|
|
413
414
|
|
|
414
415
|
expect(wrapper.emitted('send-chat-prompt')).toBeUndefined();
|
|
@@ -429,8 +430,8 @@ describe('GlDuoChat', () => {
|
|
|
429
430
|
messages: existingMessages,
|
|
430
431
|
isChatAvailable: true,
|
|
431
432
|
},
|
|
432
|
-
data: { prompt: CHAT_RESET_MESSAGE },
|
|
433
433
|
});
|
|
434
|
+
setPromptInput(CHAT_RESET_MESSAGE);
|
|
434
435
|
clickSubmit();
|
|
435
436
|
|
|
436
437
|
expect(wrapper.emitted('send-chat-prompt')).toBeUndefined();
|
|
@@ -442,16 +443,17 @@ describe('GlDuoChat', () => {
|
|
|
442
443
|
});
|
|
443
444
|
});
|
|
444
445
|
|
|
445
|
-
describe('
|
|
446
|
-
|
|
446
|
+
describe('when closed', () => {
|
|
447
|
+
beforeEach(async () => {
|
|
447
448
|
findCloseButton().vm.$emit('click');
|
|
448
449
|
await nextTick();
|
|
449
|
-
expect(findChatComponent().exists()).toBe(false);
|
|
450
450
|
});
|
|
451
451
|
|
|
452
|
-
it('
|
|
453
|
-
createComponent({ data: { isHidden: true } });
|
|
452
|
+
it('is hidden', () => {
|
|
454
453
|
expect(findChatComponent().exists()).toBe(false);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('when starts loading, resets hidden status', async () => {
|
|
455
457
|
// setProps is justified here because we are testing the component's
|
|
456
458
|
// reactive behavior which consistutes an exception
|
|
457
459
|
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
@@ -461,7 +463,9 @@ describe('GlDuoChat', () => {
|
|
|
461
463
|
await nextTick();
|
|
462
464
|
expect(findChatComponent().exists()).toBe(true);
|
|
463
465
|
});
|
|
466
|
+
});
|
|
464
467
|
|
|
468
|
+
describe('interaction', () => {
|
|
465
469
|
it('renders custom loader when isLoading', () => {
|
|
466
470
|
createComponent({ propsData: { isLoading: true } });
|
|
467
471
|
expect(findCustomLoader().exists()).toBe(true);
|
|
@@ -554,11 +558,8 @@ describe('GlDuoChat', () => {
|
|
|
554
558
|
});
|
|
555
559
|
|
|
556
560
|
it('does not render slash commands when prompt is "/"', async () => {
|
|
557
|
-
createComponent(
|
|
558
|
-
|
|
559
|
-
prompt: '/',
|
|
560
|
-
},
|
|
561
|
-
});
|
|
561
|
+
createComponent();
|
|
562
|
+
setPromptInput('/');
|
|
562
563
|
|
|
563
564
|
await nextTick();
|
|
564
565
|
expect(findSlashCommandsCard().exists()).toBe(false);
|
|
@@ -582,10 +583,8 @@ describe('GlDuoChat', () => {
|
|
|
582
583
|
propsData: {
|
|
583
584
|
slashCommands,
|
|
584
585
|
},
|
|
585
|
-
data: {
|
|
586
|
-
prompt: '/',
|
|
587
|
-
},
|
|
588
586
|
});
|
|
587
|
+
setPromptInput('/');
|
|
589
588
|
|
|
590
589
|
await nextTick();
|
|
591
590
|
expect(findSlashCommandsCard().exists()).toBe(true);
|
|
@@ -615,10 +614,8 @@ describe('GlDuoChat', () => {
|
|
|
615
614
|
propsData: {
|
|
616
615
|
slashCommands,
|
|
617
616
|
},
|
|
618
|
-
data: {
|
|
619
|
-
prompt,
|
|
620
|
-
},
|
|
621
617
|
});
|
|
618
|
+
setPromptInput(prompt);
|
|
622
619
|
|
|
623
620
|
await nextTick();
|
|
624
621
|
expect(findSlashCommandsCard().exists()).toBe(false);
|
|
@@ -634,10 +631,8 @@ describe('GlDuoChat', () => {
|
|
|
634
631
|
propsData: {
|
|
635
632
|
slashCommands,
|
|
636
633
|
},
|
|
637
|
-
data: {
|
|
638
|
-
prompt,
|
|
639
|
-
},
|
|
640
634
|
});
|
|
635
|
+
setPromptInput(prompt);
|
|
641
636
|
|
|
642
637
|
await nextTick();
|
|
643
638
|
expect(findSlashCommandsCard().exists()).toBe(true);
|
|
@@ -653,10 +648,8 @@ describe('GlDuoChat', () => {
|
|
|
653
648
|
propsData: {
|
|
654
649
|
slashCommands,
|
|
655
650
|
},
|
|
656
|
-
data: {
|
|
657
|
-
prompt,
|
|
658
|
-
},
|
|
659
651
|
});
|
|
652
|
+
setPromptInput(prompt);
|
|
660
653
|
|
|
661
654
|
await nextTick();
|
|
662
655
|
expect(findSlashCommandsCard().exists()).toBe(false);
|
|
@@ -688,10 +681,8 @@ describe('GlDuoChat', () => {
|
|
|
688
681
|
propsData: {
|
|
689
682
|
slashCommands,
|
|
690
683
|
},
|
|
691
|
-
data: {
|
|
692
|
-
prompt,
|
|
693
|
-
},
|
|
694
684
|
});
|
|
685
|
+
setPromptInput(prompt);
|
|
695
686
|
|
|
696
687
|
await nextTick();
|
|
697
688
|
expect(findSlashCommands()).toHaveLength(expectedCommands.length);
|
|
@@ -709,10 +700,8 @@ describe('GlDuoChat', () => {
|
|
|
709
700
|
slashCommands,
|
|
710
701
|
messages,
|
|
711
702
|
},
|
|
712
|
-
data: {
|
|
713
|
-
prompt: '/',
|
|
714
|
-
},
|
|
715
703
|
});
|
|
704
|
+
setPromptInput('/');
|
|
716
705
|
});
|
|
717
706
|
|
|
718
707
|
it('toggles through commands on ArrowDown', async () => {
|
|
@@ -777,10 +766,8 @@ describe('GlDuoChat', () => {
|
|
|
777
766
|
slashCommands,
|
|
778
767
|
messages,
|
|
779
768
|
},
|
|
780
|
-
data: {
|
|
781
|
-
prompt: '/',
|
|
782
|
-
},
|
|
783
769
|
});
|
|
770
|
+
setPromptInput('/');
|
|
784
771
|
});
|
|
785
772
|
|
|
786
773
|
it('updates the selected command when hovering over it', async () => {
|