Commit 348aebfa authored by Phil Hughes's avatar Phil Hughes

Merge branch '254997-fix-labels-search-scroll' into 'master'

Fix Vue Labels Select dropdown keyboard scroll

See merge request gitlab-org/gitlab!43874
parents 5afa19f9 b060e23f
...@@ -3,5 +3,3 @@ export const DropdownVariant = { ...@@ -3,5 +3,3 @@ export const DropdownVariant = {
Standalone: 'standalone', Standalone: 'standalone',
Embedded: 'embedded', Embedded: 'embedded',
}; };
export const LIST_BUFFER_SIZE = 5;
<script> <script>
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import { GlLoadingIcon, GlButton, GlSearchBoxByType, GlLink } from '@gitlab/ui'; import {
GlIntersectionObserver,
GlLoadingIcon,
GlButton,
GlSearchBoxByType,
GlLink,
} from '@gitlab/ui';
import fuzzaldrinPlus from 'fuzzaldrin-plus'; import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes'; import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
import LabelItem from './label_item.vue'; import LabelItem from './label_item.vue';
import { LIST_BUFFER_SIZE } from './constants';
export default { export default {
LIST_BUFFER_SIZE,
components: { components: {
GlIntersectionObserver,
GlLoadingIcon, GlLoadingIcon,
GlButton, GlButton,
GlSearchBoxByType, GlSearchBoxByType,
GlLink, GlLink,
SmartVirtualList,
LabelItem, LabelItem,
}, },
data() { data() {
...@@ -46,15 +48,8 @@ export default { ...@@ -46,15 +48,8 @@ export default {
} }
return this.labels; return this.labels;
}, },
showListContainer() {
if (this.isDropdownVariantSidebar) {
return !this.labelsFetchInProgress;
}
return true;
},
showNoMatchingResultsMessage() { showNoMatchingResultsMessage() {
return !this.labelsFetchInProgress && !this.visibleLabels.length; return Boolean(this.searchKey) && this.visibleLabels.length === 0;
}, },
}, },
watch: { watch: {
...@@ -67,14 +62,12 @@ export default { ...@@ -67,14 +62,12 @@ export default {
} }
}, },
}, },
mounted() {
this.fetchLabels();
},
methods: { methods: {
...mapActions([ ...mapActions([
'toggleDropdownContents', 'toggleDropdownContents',
'toggleDropdownContentsCreateView', 'toggleDropdownContentsCreateView',
'fetchLabels', 'fetchLabels',
'receiveLabelsSuccess',
'updateSelectedLabels', 'updateSelectedLabels',
'toggleDropdownContents', 'toggleDropdownContents',
]), ]),
...@@ -99,6 +92,17 @@ export default { ...@@ -99,6 +92,17 @@ export default {
} }
} }
}, },
/**
* We want to remove loaded labels to ensure component
* fetches fresh set of labels every time when shown.
*/
handleComponentDisappear() {
this.receiveLabelsSuccess([]);
},
handleCreateLabelClick() {
this.receiveLabelsSuccess([]);
this.toggleDropdownContentsCreateView();
},
/** /**
* This method enables keyboard navigation support for * This method enables keyboard navigation support for
* the dropdown. * the dropdown.
...@@ -135,12 +139,8 @@ export default { ...@@ -135,12 +139,8 @@ export default {
</script> </script>
<template> <template>
<gl-intersection-observer @appear="fetchLabels" @disappear="handleComponentDisappear">
<div class="labels-select-contents-list js-labels-list" @keydown="handleKeyDown"> <div class="labels-select-contents-list js-labels-list" @keydown="handleKeyDown">
<gl-loading-icon
v-if="labelsFetchInProgress"
class="labels-fetch-loading position-absolute gl-display-flex gl-align-items-center w-100 h-100"
size="md"
/>
<div <div
v-if="isDropdownVariantSidebar || isDropdownVariantEmbedded" v-if="isDropdownVariantSidebar || isDropdownVariantEmbedded"
class="dropdown-title gl-display-flex gl-align-items-center gl-pt-0 gl-pb-3!" class="dropdown-title gl-display-flex gl-align-items-center gl-pt-0 gl-pb-3!"
...@@ -160,35 +160,29 @@ export default { ...@@ -160,35 +160,29 @@ export default {
<gl-search-box-by-type <gl-search-box-by-type
v-model="searchKey" v-model="searchKey"
:autofocus="true" :autofocus="true"
:disabled="labelsFetchInProgress"
data-qa-selector="dropdown_input_field" data-qa-selector="dropdown_input_field"
/> />
</div> </div>
<div <div ref="labelsListContainer" class="dropdown-content" data-testid="dropdown-content">
v-show="showListContainer" <gl-loading-icon
ref="labelsListContainer" v-if="labelsFetchInProgress"
class="dropdown-content" class="labels-fetch-loading gl-align-items-center w-100 h-100"
data-testid="dropdown-content" size="md"
> />
<smart-virtual-list <ul v-else class="list-unstyled mb-0">
:length="visibleLabels.length"
:remain="$options.LIST_BUFFER_SIZE"
:size="$options.LIST_BUFFER_SIZE"
wclass="list-unstyled mb-0"
wtag="ul"
class="h-100"
>
<li v-for="(label, index) in visibleLabels" :key="label.id" class="d-block text-left">
<label-item <label-item
v-for="(label, index) in visibleLabels"
:key="label.id"
:label="label" :label="label"
:is-label-set="label.set" :is-label-set="label.set"
:highlight="index === currentHighlightItem" :highlight="index === currentHighlightItem"
@clickLabel="handleLabelClick(label)" @clickLabel="handleLabelClick(label)"
/> />
</li>
<li v-show="showNoMatchingResultsMessage" class="gl-p-3 gl-text-center"> <li v-show="showNoMatchingResultsMessage" class="gl-p-3 gl-text-center">
{{ __('No matching results') }} {{ __('No matching results') }}
</li> </li>
</smart-virtual-list> </ul>
</div> </div>
<div <div
v-if="isDropdownVariantSidebar || isDropdownVariantEmbedded" v-if="isDropdownVariantSidebar || isDropdownVariantEmbedded"
...@@ -199,7 +193,7 @@ export default { ...@@ -199,7 +193,7 @@ export default {
<li v-if="allowLabelCreate"> <li v-if="allowLabelCreate">
<gl-link <gl-link
class="gl-display-flex w-100 flex-row text-break-word label-item" class="gl-display-flex w-100 flex-row text-break-word label-item"
@click="toggleDropdownContentsCreateView" @click="handleCreateLabelClick"
> >
{{ footerCreateLabelTitle }} {{ footerCreateLabelTitle }}
</gl-link> </gl-link>
...@@ -215,4 +209,5 @@ export default { ...@@ -215,4 +209,5 @@ export default {
</ul> </ul>
</div> </div>
</div> </div>
</gl-intersection-observer>
</template> </template>
<script> <script>
import { GlIcon, GlLink } from '@gitlab/ui'; import { GlLink, GlIcon } from '@gitlab/ui';
export default { export default {
components: { functional: true,
GlIcon,
GlLink,
},
props: { props: {
label: { label: {
type: Object, type: Object,
...@@ -21,46 +18,65 @@ export default { ...@@ -21,46 +18,65 @@ export default {
default: false, default: false,
}, },
}, },
data() { render(h, { props, listeners }) {
return { const { label, highlight, isLabelSet } = props;
isSet: this.isLabelSet,
}; const labelColorBox = h('span', {
class: 'dropdown-label-box',
style: {
backgroundColor: label.color,
},
attrs: {
'data-testid': 'label-color-box',
},
});
const checkedIcon = h(GlIcon, {
class: {
'mr-2 align-self-center': true,
hidden: !isLabelSet,
},
props: {
name: 'mobile-issue-close',
},
});
const noIcon = h('span', {
class: {
'mr-3 pr-2': true,
hidden: isLabelSet,
},
attrs: {
'data-testid': 'no-icon',
}, },
computed: { });
labelBoxStyle() {
return { const labelTitle = h('span', label.title);
backgroundColor: this.label.color,
}; const labelLink = h(
GlLink,
{
class: 'd-flex align-items-baseline text-break-word label-item',
on: {
click: () => {
listeners.clickLabel(label);
}, },
}, },
watch: {
/**
* This watcher assures that if user used
* `Enter` key to set/unset label, changes
* are reflected here too.
*/
isLabelSet(value) {
this.isSet = value;
}, },
[noIcon, checkedIcon, labelColorBox, labelTitle],
);
return h(
'li',
{
class: {
'd-block': true,
'text-left': true,
'is-focused': highlight,
}, },
methods: {
handleClick() {
this.isSet = !this.isSet;
this.$emit('clickLabel', this.label);
}, },
[labelLink],
);
}, },
}; };
</script> </script>
<template>
<gl-link
class="d-flex align-items-baseline text-break-word label-item"
:class="{ 'is-focused': highlight }"
@click="handleClick"
>
<gl-icon v-show="isSet" name="mobile-issue-close" class="mr-2 align-self-center" />
<span v-show="!isSet" data-testid="no-icon" class="mr-3 pr-2"></span>
<span class="dropdown-label-box" data-testid="label-color-box" :style="labelBoxStyle"></span>
<span>{{ label.title }}</span>
</gl-link>
</template>
...@@ -266,7 +266,7 @@ export default { ...@@ -266,7 +266,7 @@ export default {
</dropdown-value> </dropdown-value>
<dropdown-button v-show="dropdownButtonVisible" class="gl-mt-2" /> <dropdown-button v-show="dropdownButtonVisible" class="gl-mt-2" />
<dropdown-contents <dropdown-contents
v-if="dropdownButtonVisible && showDropdownContents" v-show="dropdownButtonVisible && showDropdownContents"
ref="dropdownContents" ref="dropdownContents"
/> />
</template> </template>
......
...@@ -1017,6 +1017,23 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu { ...@@ -1017,6 +1017,23 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu {
} }
} }
li {
&:hover,
&.is-focused {
.label-item {
@include dropdown-item-hover;
text-decoration: none;
}
}
}
.labels-select-dropdown-button {
.gl-button-text {
width: 100%;
}
}
.labels-select-dropdown-contents { .labels-select-dropdown-contents {
min-height: $dropdown-min-height; min-height: $dropdown-min-height;
max-height: 330px; max-height: 330px;
...@@ -1050,13 +1067,6 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu { ...@@ -1050,13 +1067,6 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu {
.label-item { .label-item {
padding: 8px 20px; padding: 8px 20px;
&:hover,
&.is-focused {
@include dropdown-item-hover;
text-decoration: none;
}
} }
.color-input-container { .color-input-container {
......
---
title: Fix Vue Labels Select dropdown keyboard scroll
merge_request: 43874
author:
type: fixed
...@@ -149,6 +149,7 @@ export default { ...@@ -149,6 +149,7 @@ export default {
<sidebar-todo <sidebar-todo
v-show="sidebarCollapsed && isUserSignedIn" v-show="sidebarCollapsed && isUserSignedIn"
:sidebar-collapsed="sidebarCollapsed" :sidebar-collapsed="sidebarCollapsed"
data-testid="todo"
/> />
<sidebar-date-picker <sidebar-date-picker
v-show="!sidebarCollapsed" v-show="!sidebarCollapsed"
...@@ -167,6 +168,7 @@ export default { ...@@ -167,6 +168,7 @@ export default {
:date-from-milestones="startDateTimeFromMilestones" :date-from-milestones="startDateTimeFromMilestones"
:selected-date="startDateTime" :selected-date="startDateTime"
:is-date-invalid="isDateInvalid" :is-date-invalid="isDateInvalid"
data-testid="start-date"
block-class="start-date" block-class="start-date"
@toggleCollapse="toggleSidebar({ sidebarCollapsed })" @toggleCollapse="toggleSidebar({ sidebarCollapsed })"
@toggleDateType="changeStartDateType" @toggleDateType="changeStartDateType"
...@@ -188,6 +190,7 @@ export default { ...@@ -188,6 +190,7 @@ export default {
:date-from-milestones="dueDateTimeFromMilestones" :date-from-milestones="dueDateTimeFromMilestones"
:selected-date="dueDateTime" :selected-date="dueDateTime"
:is-date-invalid="isDateInvalid" :is-date-invalid="isDateInvalid"
data-testid="due-date"
block-class="due-date" block-class="due-date"
@toggleDateType="changeDueDateType" @toggleDateType="changeDueDateType"
@saveDate="saveDueDate" @saveDate="saveDueDate"
...@@ -199,9 +202,13 @@ export default { ...@@ -199,9 +202,13 @@ export default {
:max-date="dueDateForCollapsedSidebar" :max-date="dueDateForCollapsedSidebar"
@toggleCollapse="toggleSidebar({ sidebarCollapsed })" @toggleCollapse="toggleSidebar({ sidebarCollapsed })"
/> />
<sidebar-labels :can-update="canUpdate" :sidebar-collapsed="sidebarCollapsed" /> <sidebar-labels
:can-update="canUpdate"
:sidebar-collapsed="sidebarCollapsed"
data-testid="labels-select"
/>
<div v-if="allowSubEpics" class="block ancestors"> <div v-if="allowSubEpics" class="block ancestors">
<ancestors-tree :ancestors="ancestors" :is-fetching="false" /> <ancestors-tree :ancestors="ancestors" :is-fetching="false" data-testid="ancestors" />
</div> </div>
<confidential-issue-sidebar <confidential-issue-sidebar
...@@ -216,7 +223,7 @@ export default { ...@@ -216,7 +223,7 @@ export default {
@toggleSidebar="toggleSidebar({ sidebarCollapsed })" @toggleSidebar="toggleSidebar({ sidebarCollapsed })"
/> />
</div> </div>
<sidebar-subscription :sidebar-collapsed="sidebarCollapsed" /> <sidebar-subscription :sidebar-collapsed="sidebarCollapsed" data-testid="subscribe" />
</div> </div>
</aside> </aside>
</template> </template>
...@@ -22,6 +22,7 @@ describe('SidebarLabelsComponent', () => { ...@@ -22,6 +22,7 @@ describe('SidebarLabelsComponent', () => {
propsData: { canUpdate: false, sidebarCollapsed: false }, propsData: { canUpdate: false, sidebarCollapsed: false },
store, store,
stubs: { stubs: {
LabelsSelectVue: true,
GlLabel: true, GlLabel: true,
}, },
}); });
......
import Vuex from 'vuex'; import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlButton, GlLoadingIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui'; import {
GlIntersectionObserver,
GlButton,
GlLoadingIcon,
GlSearchBoxByType,
GlLink,
} from '@gitlab/ui';
import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes'; import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
import DropdownContentsLabelsView from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue'; import DropdownContentsLabelsView from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue';
import LabelItem from '~/vue_shared/components/sidebar/labels_select_vue/label_item.vue'; import LabelItem from '~/vue_shared/components/sidebar/labels_select_vue/label_item.vue';
...@@ -88,20 +93,25 @@ describe('DropdownContentsLabelsView', () => { ...@@ -88,20 +93,25 @@ describe('DropdownContentsLabelsView', () => {
}); });
}); });
describe('showListContainer', () => { describe('showNoMatchingResultsMessage', () => {
it.each` it.each`
variant | loading | showList searchKey | labels | labelsDescription | returnValue
${'sidebar'} | ${false} | ${true} ${''} | ${[]} | ${'empty'} | ${false}
${'sidebar'} | ${true} | ${false} ${'bug'} | ${[]} | ${'empty'} | ${true}
${'not-sidebar'} | ${true} | ${true} ${''} | ${mockLabels} | ${'not empty'} | ${false}
${'not-sidebar'} | ${false} | ${true} ${'bug'} | ${mockLabels} | ${'not empty'} | ${false}
`( `(
'returns $showList if `state.variant` is "$variant" and `labelsFetchInProgress` is $loading', 'returns $returnValue when searchKey is "$searchKey" and visibleLabels is $labelsDescription',
({ variant, loading, showList }) => { async ({ searchKey, labels, returnValue }) => {
createComponent({ ...mockConfig, variant }); wrapper.setData({
wrapper.vm.$store.state.labelsFetchInProgress = loading; searchKey,
});
wrapper.vm.$store.dispatch('receiveLabelsSuccess', labels);
await wrapper.vm.$nextTick();
expect(wrapper.vm.showListContainer).toBe(showList); expect(wrapper.vm.showNoMatchingResultsMessage).toBe(returnValue);
}, },
); );
}); });
...@@ -118,6 +128,28 @@ describe('DropdownContentsLabelsView', () => { ...@@ -118,6 +128,28 @@ describe('DropdownContentsLabelsView', () => {
}); });
}); });
describe('handleComponentDisappear', () => {
it('calls action `receiveLabelsSuccess` with empty array', () => {
jest.spyOn(wrapper.vm, 'receiveLabelsSuccess');
wrapper.vm.handleComponentDisappear();
expect(wrapper.vm.receiveLabelsSuccess).toHaveBeenCalledWith([]);
});
});
describe('handleCreateLabelClick', () => {
it('calls actions `receiveLabelsSuccess` with empty array and `toggleDropdownContentsCreateView`', () => {
jest.spyOn(wrapper.vm, 'receiveLabelsSuccess');
jest.spyOn(wrapper.vm, 'toggleDropdownContentsCreateView');
wrapper.vm.handleCreateLabelClick();
expect(wrapper.vm.receiveLabelsSuccess).toHaveBeenCalledWith([]);
expect(wrapper.vm.toggleDropdownContentsCreateView).toHaveBeenCalled();
});
});
describe('handleKeyDown', () => { describe('handleKeyDown', () => {
it('decreases `currentHighlightItem` value by 1 when Up arrow key is pressed', () => { it('decreases `currentHighlightItem` value by 1 when Up arrow key is pressed', () => {
wrapper.setData({ wrapper.setData({
...@@ -226,8 +258,8 @@ describe('DropdownContentsLabelsView', () => { ...@@ -226,8 +258,8 @@ describe('DropdownContentsLabelsView', () => {
}); });
describe('template', () => { describe('template', () => {
it('renders component container element with class `labels-select-contents-list`', () => { it('renders gl-intersection-observer as component root', () => {
expect(wrapper.attributes('class')).toContain('labels-select-contents-list'); expect(wrapper.find(GlIntersectionObserver).exists()).toBe(true);
}); });
it('renders gl-loading-icon component when `labelsFetchInProgress` prop is true', () => { it('renders gl-loading-icon component when `labelsFetchInProgress` prop is true', () => {
...@@ -272,15 +304,11 @@ describe('DropdownContentsLabelsView', () => { ...@@ -272,15 +304,11 @@ describe('DropdownContentsLabelsView', () => {
expect(searchInputEl.attributes('autofocus')).toBe('true'); expect(searchInputEl.attributes('autofocus')).toBe('true');
}); });
it('renders smart-virtual-list element', () => {
expect(wrapper.find(SmartVirtualList).exists()).toBe(true);
});
it('renders label elements for all labels', () => { it('renders label elements for all labels', () => {
expect(wrapper.findAll(LabelItem)).toHaveLength(mockLabels.length); expect(wrapper.findAll(LabelItem)).toHaveLength(mockLabels.length);
}); });
it('renders label element with "is-focused" when value of `currentHighlightItem` is more than -1', () => { it('renders label element with `highlight` set to true when value of `currentHighlightItem` is more than -1', () => {
wrapper.setData({ wrapper.setData({
currentHighlightItem: 0, currentHighlightItem: 0,
}); });
...@@ -288,7 +316,7 @@ describe('DropdownContentsLabelsView', () => { ...@@ -288,7 +316,7 @@ describe('DropdownContentsLabelsView', () => {
return wrapper.vm.$nextTick(() => { return wrapper.vm.$nextTick(() => {
const labelItemEl = findDropdownContent().find(LabelItem); const labelItemEl = findDropdownContent().find(LabelItem);
expect(labelItemEl.props('highlight')).toBe(true); expect(labelItemEl.attributes('highlight')).toBe('true');
}); });
}); });
...@@ -310,9 +338,12 @@ describe('DropdownContentsLabelsView', () => { ...@@ -310,9 +338,12 @@ describe('DropdownContentsLabelsView', () => {
return wrapper.vm.$nextTick(() => { return wrapper.vm.$nextTick(() => {
const dropdownContent = findDropdownContent(); const dropdownContent = findDropdownContent();
const loadingIcon = findLoadingIcon();
expect(dropdownContent.exists()).toBe(true); expect(dropdownContent.exists()).toBe(true);
expect(dropdownContent.isVisible()).toBe(false); expect(dropdownContent.isVisible()).toBe(true);
expect(loadingIcon.exists()).toBe(true);
expect(loadingIcon.isVisible()).toBe(true);
}); });
}); });
......
...@@ -6,11 +6,15 @@ import { mockRegularLabel } from './mock_data'; ...@@ -6,11 +6,15 @@ import { mockRegularLabel } from './mock_data';
const mockLabel = { ...mockRegularLabel, set: true }; const mockLabel = { ...mockRegularLabel, set: true };
const createComponent = ({ label = mockLabel, highlight = true } = {}) => const createComponent = ({
label = mockLabel,
isLabelSet = mockLabel.set,
highlight = true,
} = {}) =>
shallowMount(LabelItem, { shallowMount(LabelItem, {
propsData: { propsData: {
label, label,
isLabelSet: label.set, isLabelSet,
highlight, highlight,
}, },
}); });
...@@ -26,94 +30,44 @@ describe('LabelItem', () => { ...@@ -26,94 +30,44 @@ describe('LabelItem', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('computed', () => {
describe('labelBoxStyle', () => {
it('returns an object containing `backgroundColor` based on `label` prop', () => {
expect(wrapper.vm.labelBoxStyle).toEqual(
expect.objectContaining({
backgroundColor: mockLabel.color,
}),
);
});
});
});
describe('watchers', () => {
describe('isLabelSet', () => {
it('sets value of `isLabelSet` to `isSet` data prop', () => {
expect(wrapper.vm.isSet).toBe(true);
wrapper.setProps({
isLabelSet: false,
});
return wrapper.vm.$nextTick(() => {
expect(wrapper.vm.isSet).toBe(false);
});
});
});
});
describe('methods', () => {
describe('handleClick', () => {
it('sets value of `isSet` data prop to opposite of its current value', () => {
wrapper.setData({
isSet: true,
});
wrapper.vm.handleClick();
expect(wrapper.vm.isSet).toBe(false);
wrapper.vm.handleClick();
expect(wrapper.vm.isSet).toBe(true);
});
it('emits event `clickLabel` on component with `label` prop as param', () => {
wrapper.vm.handleClick();
expect(wrapper.emitted('clickLabel')).toBeTruthy();
expect(wrapper.emitted('clickLabel')[0]).toEqual([mockLabel]);
});
});
});
describe('template', () => { describe('template', () => {
it('renders gl-link component', () => { it('renders gl-link component', () => {
expect(wrapper.find(GlLink).exists()).toBe(true); expect(wrapper.find(GlLink).exists()).toBe(true);
}); });
it('renders gl-link component with class `is-focused` when `highlight` prop is true', () => { it('renders component root with class `is-focused` when `highlight` prop is true', () => {
wrapper.setProps({ const wrapperTemp = createComponent({
highlight: true, highlight: true,
}); });
return wrapper.vm.$nextTick(() => { expect(wrapperTemp.classes()).toContain('is-focused');
expect(wrapper.find(GlLink).classes()).toContain('is-focused');
}); wrapperTemp.destroy();
}); });
it('renders visible gl-icon component when `isSet` prop is true', () => { it('renders visible gl-icon component when `isLabelSet` prop is true', () => {
wrapper.setData({ const wrapperTemp = createComponent({
isSet: true, isLabelSet: true,
}); });
return wrapper.vm.$nextTick(() => { const iconEl = wrapperTemp.find(GlIcon);
const iconEl = wrapper.find(GlIcon);
expect(iconEl.isVisible()).toBe(true); expect(iconEl.isVisible()).toBe(true);
expect(iconEl.props('name')).toBe('mobile-issue-close'); expect(iconEl.props('name')).toBe('mobile-issue-close');
});
wrapperTemp.destroy();
}); });
it('renders visible span element as placeholder instead of gl-icon when `isSet` prop is false', () => { it('renders visible span element as placeholder instead of gl-icon when `isLabelSet` prop is false', () => {
wrapper.setData({ const wrapperTemp = createComponent({
isSet: false, isLabelSet: false,
}); });
return wrapper.vm.$nextTick(() => { const placeholderEl = wrapperTemp.find('[data-testid="no-icon"]');
const placeholderEl = wrapper.find('[data-testid="no-icon"]');
expect(placeholderEl.isVisible()).toBe(true); expect(placeholderEl.isVisible()).toBe(true);
});
wrapperTemp.destroy();
}); });
it('renders label color element', () => { it('renders label color element', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment