Commit 854c64da authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch '332258-replace-dropdowntitle-component-with-sidebareditableitem' into 'master'

Replace `DropdownTitle` component with `SidebarEditableItem`

See merge request gitlab-org/gitlab!67966
parents 3c83847b a689dbbf
...@@ -258,6 +258,7 @@ export function mountSidebarLabels() { ...@@ -258,6 +258,7 @@ export function mountSidebarLabels() {
allowScopedLabels: parseBoolean(el.dataset.allowScopedLabels), allowScopedLabels: parseBoolean(el.dataset.allowScopedLabels),
initiallySelectedLabels: JSON.parse(el.dataset.selectedLabels), initiallySelectedLabels: JSON.parse(el.dataset.selectedLabels),
variant: DropdownVariant.Sidebar, variant: DropdownVariant.Sidebar,
canUpdate: parseBoolean(el.dataset.canEdit),
}, },
render: (createElement) => createElement(SidebarLabels), render: (createElement) => createElement(SidebarLabels),
}); });
......
...@@ -60,7 +60,7 @@ export default { ...@@ -60,7 +60,7 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions(['toggleDropdownContentsCreateView', 'toggleDropdownContents']), ...mapActions(['toggleDropdownContentsCreateView']),
}, },
}; };
</script> </script>
...@@ -83,7 +83,7 @@ export default { ...@@ -83,7 +83,7 @@ export default {
size="small" size="small"
class="js-btn-back dropdown-header-button p-0" class="js-btn-back dropdown-header-button p-0"
icon="arrow-left" icon="arrow-left"
@click="toggleDropdownContentsCreateView" @click.stop="toggleDropdownContentsCreateView"
/> />
<span class="flex-grow-1">{{ dropdownTitle }}</span> <span class="flex-grow-1">{{ dropdownTitle }}</span>
<gl-button <gl-button
...@@ -92,7 +92,7 @@ export default { ...@@ -92,7 +92,7 @@ export default {
size="small" size="small"
class="dropdown-header-button gl-p-0!" class="dropdown-header-button gl-p-0!"
icon="close" icon="close"
@click="toggleDropdownContents" @click="$emit('closeDropdown')"
/> />
</div> </div>
<component <component
...@@ -103,7 +103,7 @@ export default { ...@@ -103,7 +103,7 @@ export default {
:footer-create-label-title="footerCreateLabelTitle" :footer-create-label-title="footerCreateLabelTitle"
:footer-manage-label-title="footerManageLabelTitle" :footer-manage-label-title="footerManageLabelTitle"
@hideCreateView="toggleDropdownContentsCreateView" @hideCreateView="toggleDropdownContentsCreateView"
@closeDropdown="$emit('closeDropdown', $event)" @setLabels="$emit('setLabels', $event)"
@toggleDropdownContentsCreateView="toggleDropdownContentsCreateView" @toggleDropdownContentsCreateView="toggleDropdownContentsCreateView"
/> />
</div> </div>
......
<script> <script>
import { GlTooltipDirective, GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui'; import { GlTooltipDirective, GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui';
import produce from 'immer';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import createLabelMutation from './graphql/create_label.mutation.graphql'; import createLabelMutation from './graphql/create_label.mutation.graphql';
import projectLabelsQuery from './graphql/project_labels.query.graphql';
const errorMessage = __('Error creating label.'); const errorMessage = __('Error creating label.');
...@@ -47,6 +49,25 @@ export default { ...@@ -47,6 +49,25 @@ export default {
handleColorClick(color) { handleColorClick(color) {
this.selectedColor = this.getColorCode(color); this.selectedColor = this.getColorCode(color);
}, },
updateLabelsInCache(store, label) {
const sourceData = store.readQuery({
query: projectLabelsQuery,
variables: { fullPath: this.projectPath, searchTerm: '' },
});
const collator = new Intl.Collator('en');
const data = produce(sourceData, (draftData) => {
const { nodes } = draftData.workspace.labels;
nodes.push(label);
nodes.sort((a, b) => collator.compare(a.title, b.title));
});
store.writeQuery({
query: projectLabelsQuery,
variables: { fullPath: this.projectPath, searchTerm: '' },
data,
});
},
async createLabel() { async createLabel() {
this.labelCreateInProgress = true; this.labelCreateInProgress = true;
try { try {
...@@ -59,6 +80,14 @@ export default { ...@@ -59,6 +80,14 @@ export default {
color: this.selectedColor, color: this.selectedColor,
projectPath: this.projectPath, projectPath: this.projectPath,
}, },
update: (
store,
{
data: {
labelCreate: { label },
},
},
) => this.updateLabelsInCache(store, label),
}); });
if (labelCreate.errors.length) { if (labelCreate.errors.length) {
createFlash({ message: errorMessage }); createFlash({ message: errorMessage });
......
...@@ -112,7 +112,7 @@ export default { ...@@ -112,7 +112,7 @@ export default {
this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS); this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
}, },
beforeDestroy() { beforeDestroy() {
this.$emit('closeDropdown', this.localSelectedLabels); this.$emit('setLabels', this.localSelectedLabels);
this.debouncedSearchKeyUpdate.cancel(); this.debouncedSearchKeyUpdate.cancel();
}, },
methods: { methods: {
...@@ -166,7 +166,7 @@ export default { ...@@ -166,7 +166,7 @@ export default {
this.updateSelectedLabels(this.visibleLabels[this.currentHighlightItem]); this.updateSelectedLabels(this.visibleLabels[this.currentHighlightItem]);
this.searchKey = ''; this.searchKey = '';
} else if (e.keyCode === ESC_KEY_CODE) { } else if (e.keyCode === ESC_KEY_CODE) {
this.$emit('closeDropdown', this.localSelectedLabels); this.$emit('setLabels', this.localSelectedLabels);
} }
if (e.keyCode !== ESC_KEY_CODE) { if (e.keyCode !== ESC_KEY_CODE) {
...@@ -180,7 +180,7 @@ export default { ...@@ -180,7 +180,7 @@ export default {
handleLabelClick(label) { handleLabelClick(label) {
this.updateSelectedLabels(label); this.updateSelectedLabels(label);
if (!this.allowMultiselect) { if (!this.allowMultiselect) {
this.$emit('closeDropdown', this.localSelectedLabels); this.$emit('setLabels', this.localSelectedLabels);
} }
}, },
setSearchKey(value) { setSearchKey(value) {
...@@ -240,7 +240,7 @@ export default { ...@@ -240,7 +240,7 @@ export default {
<gl-link <gl-link
class="gl-display-flex gl-flex-direction-row gl-w-full gl-overflow-break-word label-item" class="gl-display-flex gl-flex-direction-row gl-w-full gl-overflow-break-word label-item"
data-testid="create-label-button" data-testid="create-label-button"
@click="$emit('toggleDropdownContentsCreateView')" @click.stop="$emit('toggleDropdownContentsCreateView')"
> >
{{ footerCreateLabelTitle }} {{ footerCreateLabelTitle }}
</gl-link> </gl-link>
......
<script>
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
export default {
components: {
GlButton,
GlLoadingIcon,
},
props: {
labelsSelectInProgress: {
type: Boolean,
required: true,
},
},
computed: {
...mapState(['allowLabelEdit', 'labelsFetchInProgress']),
},
methods: {
...mapActions(['toggleDropdownContents']),
},
};
</script>
<template>
<div class="title hide-collapsed gl-mb-3">
{{ __('Labels') }}
<template v-if="allowLabelEdit">
<gl-loading-icon v-show="labelsSelectInProgress" size="sm" inline />
<gl-button
category="tertiary"
size="small"
class="float-right js-sidebar-dropdown-toggle gl-mr-n2"
data-qa-selector="labels_edit_button"
@click="toggleDropdownContents"
>{{ __('Edit') }}</gl-button
>
</template>
</div>
</template>
...@@ -6,9 +6,7 @@ mutation createLabel($title: String!, $color: String, $projectPath: ID, $groupPa ...@@ -6,9 +6,7 @@ mutation createLabel($title: String!, $color: String, $projectPath: ID, $groupPa
id id
color color
description description
descriptionHtml
title title
textColor
} }
errors errors
} }
......
<script> <script>
import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import Vuex, { mapState, mapActions, mapGetters } from 'vuex'; import Vuex, { mapState, mapActions, mapGetters } from 'vuex';
import { isInViewport } from '~/lib/utils/common_utils'; import { isInViewport } from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import { DropdownVariant } from './constants'; import { DropdownVariant } from './constants';
import DropdownButton from './dropdown_button.vue'; import DropdownButton from './dropdown_button.vue';
import DropdownContents from './dropdown_contents.vue'; import DropdownContents from './dropdown_contents.vue';
import DropdownTitle from './dropdown_title.vue';
import DropdownValue from './dropdown_value.vue'; import DropdownValue from './dropdown_value.vue';
import DropdownValueCollapsed from './dropdown_value_collapsed.vue'; import DropdownValueCollapsed from './dropdown_value_collapsed.vue';
import issueLabelsQuery from './graphql/issue_labels.query.graphql'; import issueLabelsQuery from './graphql/issue_labels.query.graphql';
...@@ -19,11 +17,11 @@ Vue.use(Vuex); ...@@ -19,11 +17,11 @@ Vue.use(Vuex);
export default { export default {
store: new Vuex.Store(labelsSelectModule()), store: new Vuex.Store(labelsSelectModule()),
components: { components: {
DropdownTitle,
DropdownValue, DropdownValue,
DropdownButton, DropdownButton,
DropdownContents, DropdownContents,
DropdownValueCollapsed, DropdownValueCollapsed,
SidebarEditableItem,
}, },
inject: ['iid', 'projectPath'], inject: ['iid', 'projectPath'],
props: { props: {
...@@ -139,15 +137,12 @@ export default { ...@@ -139,15 +137,12 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(['showDropdownButton', 'showDropdownContents']), ...mapState(['showDropdownContents']),
...mapGetters([ ...mapGetters([
'isDropdownVariantSidebar', 'isDropdownVariantSidebar',
'isDropdownVariantStandalone', 'isDropdownVariantStandalone',
'isDropdownVariantEmbedded', 'isDropdownVariantEmbedded',
]), ]),
dropdownButtonVisible() {
return this.isDropdownVariantSidebar ? this.showDropdownButton : true;
},
}, },
watch: { watch: {
selectedLabels(selectedLabels) { selectedLabels(selectedLabels) {
...@@ -182,99 +177,20 @@ export default { ...@@ -182,99 +177,20 @@ export default {
footerCreateLabelTitle: this.footerCreateLabelTitle, footerCreateLabelTitle: this.footerCreateLabelTitle,
footerManageLabelTitle: this.footerManageLabelTitle, footerManageLabelTitle: this.footerManageLabelTitle,
}); });
this.$store.subscribeAction({
after: this.handleVuexActionDispatch,
});
document.addEventListener('mousedown', this.handleDocumentMousedown);
document.addEventListener('click', this.handleDocumentClick);
},
beforeDestroy() {
document.removeEventListener('mousedown', this.handleDocumentMousedown);
document.removeEventListener('click', this.handleDocumentClick);
}, },
methods: { methods: {
...mapActions(['setInitialState', 'toggleDropdownContents']), ...mapActions(['setInitialState']),
/**
* This method stores a mousedown event's target.
* Required by the click listener because the click
* event itself has no reference to this element.
*/
handleDocumentMousedown({ target }) {
this.mousedownTarget = target;
},
/**
* This method listens for document-wide click event
* and toggle dropdown if user clicks anywhere outside
* the dropdown while dropdown is visible.
*/
handleDocumentClick({ target }) {
// We also perform the toggle exception check for the
// last mousedown event's target to avoid hiding the
// box when the mousedown happened inside the box and
// only the mouseup did not.
if (
this.showDropdownContents &&
!this.preventDropdownToggleOnClick(target) &&
!this.preventDropdownToggleOnClick(this.mousedownTarget)
) {
this.toggleDropdownContents();
}
},
/**
* This method checks whether a given click target
* should prevent the dropdown from being toggled.
*/
preventDropdownToggleOnClick(target) {
// This approach of element detection is needed
// as the dropdown wrapper is not using `GlDropdown` as
// it will also require us to use `BDropdownForm`
// which is yet to be implemented in GitLab UI.
const hasExceptionClass = [
'js-dropdown-button',
'js-btn-cancel-create',
'js-sidebar-dropdown-toggle',
].some(
(className) =>
target?.classList.contains(className) ||
target?.parentElement?.classList.contains(className),
);
const hasExceptionParent = ['.js-btn-back', '.js-labels-list'].some(
(className) => $(target).parents(className).length,
);
const isInDropdownButtonCollapsed = this.$refs.dropdownButtonCollapsed?.$el.contains(target);
const isInDropdownContents = this.$refs.dropdownContents?.$el.contains(target);
return (
hasExceptionClass ||
hasExceptionParent ||
isInDropdownButtonCollapsed ||
isInDropdownContents
);
},
handleDropdownClose(labels) { handleDropdownClose(labels) {
// Only emit label updates if there are any labels to update
// on UI.
if (this.showDropdownContents) {
this.toggleDropdownContents();
}
if (labels.length) this.$emit('updateSelectedLabels', labels); if (labels.length) this.$emit('updateSelectedLabels', labels);
this.$emit('onDropdownClose'); this.$emit('onDropdownClose');
}, },
collapseDropdown() {
this.$refs.editable.collapse();
},
handleCollapsedValueClick() { handleCollapsedValueClick() {
this.$emit('toggleCollapse'); this.$emit('toggleCollapse');
}, },
setContentIsOnViewport(showDropdownContents) { setContentIsOnViewport() {
if (!showDropdownContents) {
this.contentIsOnViewport = true;
return;
}
this.$nextTick(() => { this.$nextTick(() => {
if (this.$refs.dropdownContents) { if (this.$refs.dropdownContents) {
this.contentIsOnViewport = isInViewport(this.$refs.dropdownContents.$el); this.contentIsOnViewport = isInViewport(this.$refs.dropdownContents.$el);
...@@ -299,10 +215,14 @@ export default { ...@@ -299,10 +215,14 @@ export default {
:labels="issueLabels" :labels="issueLabels"
@onValueClick="handleCollapsedValueClick" @onValueClick="handleCollapsedValueClick"
/> />
<dropdown-title <sidebar-editable-item
:allow-label-edit="allowLabelEdit" ref="editable"
:labels-select-in-progress="labelsSelectInProgress" :title="__('Labels')"
/> :loading="labelsSelectInProgress"
@open="setContentIsOnViewport"
@close="contentIsOnViewport = true"
>
<template #collapsed>
<dropdown-value <dropdown-value
:disable-labels="labelsSelectInProgress" :disable-labels="labelsSelectInProgress"
:selected-labels="issueLabels" :selected-labels="issueLabels"
...@@ -314,9 +234,23 @@ export default { ...@@ -314,9 +234,23 @@ export default {
> >
<slot></slot> <slot></slot>
</dropdown-value> </dropdown-value>
<dropdown-button v-show="dropdownButtonVisible" class="gl-mt-2" /> </template>
<template #default="{ edit }">
<dropdown-value
:disable-labels="labelsSelectInProgress"
:selected-labels="issueLabels"
:allow-label-remove="allowLabelRemove"
:allow-scoped-labels="allowScopedLabels"
:labels-filter-base-path="labelsFilterBasePath"
:labels-filter-param="labelsFilterParam"
class="gl-mb-2"
@onLabelRemove="$emit('onLabelRemove', $event)"
>
<slot></slot>
</dropdown-value>
<dropdown-button />
<dropdown-contents <dropdown-contents
v-if="dropdownButtonVisible && showDropdownContents" v-if="edit"
ref="dropdownContents" ref="dropdownContents"
:allow-multiselect="allowMultiselect" :allow-multiselect="allowMultiselect"
:labels-list-title="labelsListTitle" :labels-list-title="labelsListTitle"
...@@ -325,22 +259,11 @@ export default { ...@@ -325,22 +259,11 @@ export default {
:render-on-top="!contentIsOnViewport" :render-on-top="!contentIsOnViewport"
:labels-create-title="labelsCreateTitle" :labels-create-title="labelsCreateTitle"
:selected-labels="selectedLabels" :selected-labels="selectedLabels"
@closeDropdown="handleDropdownClose" @closeDropdown="collapseDropdown"
@setLabels="handleDropdownClose"
/> />
</template> </template>
<template v-if="isDropdownVariantStandalone || isDropdownVariantEmbedded"> </sidebar-editable-item>
<dropdown-button v-show="dropdownButtonVisible" />
<dropdown-contents
v-if="dropdownButtonVisible && showDropdownContents"
ref="dropdownContents"
:allow-multiselect="allowMultiselect"
:labels-list-title="labelsListTitle"
:footer-create-label-title="footerCreateLabelTitle"
:footer-manage-label-title="footerManageLabelTitle"
:render-on-top="!contentIsOnViewport"
:selected-labels="selectedLabels"
@closeDropdown="handleDropdownClose"
/>
</template> </template>
</div> </div>
</template> </template>
...@@ -7,7 +7,12 @@ import waitForPromises from 'helpers/wait_for_promises'; ...@@ -7,7 +7,12 @@ import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import DropdownContentsCreateView from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue'; import DropdownContentsCreateView from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue';
import createLabelMutation from '~/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql'; import createLabelMutation from '~/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql';
import { mockSuggestedColors, createLabelSuccessfulResponse } from './mock_data'; import projectLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql';
import {
mockSuggestedColors,
createLabelSuccessfulResponse,
labelsQueryResponse,
} from './mock_data';
jest.mock('~/flash'); jest.mock('~/flash');
...@@ -44,6 +49,14 @@ describe('DropdownContentsCreateView', () => { ...@@ -44,6 +49,14 @@ describe('DropdownContentsCreateView', () => {
const createComponent = ({ mutationHandler = createLabelSuccessHandler } = {}) => { const createComponent = ({ mutationHandler = createLabelSuccessHandler } = {}) => {
const mockApollo = createMockApollo([[createLabelMutation, mutationHandler]]); const mockApollo = createMockApollo([[createLabelMutation, mutationHandler]]);
mockApollo.clients.defaultClient.cache.writeQuery({
query: projectLabelsQuery,
data: labelsQueryResponse.data,
variables: {
fullPath: '',
searchTerm: '',
},
});
wrapper = shallowMount(DropdownContentsCreateView, { wrapper = shallowMount(DropdownContentsCreateView, {
localVue, localVue,
......
...@@ -137,12 +137,6 @@ describe('DropdownContentsLabelsView', () => { ...@@ -137,12 +137,6 @@ describe('DropdownContentsLabelsView', () => {
expect(findLabels().at(0).attributes('islabelset')).toBe('true'); expect(findLabels().at(0).attributes('islabelset')).toBe('true');
}); });
it('emits `closeDropdown event` when Esc button is pressed', () => {
findDropdownWrapper().trigger('keydown.esc');
expect(wrapper.emitted('closeDropdown')).toEqual([[selectedLabels]]);
});
}); });
it('when search returns 0 results', async () => { it('when search returns 0 results', async () => {
...@@ -205,7 +199,7 @@ describe('DropdownContentsLabelsView', () => { ...@@ -205,7 +199,7 @@ describe('DropdownContentsLabelsView', () => {
}); });
it('emits `toggleDropdownContentsCreateView` event on create label button click', () => { it('emits `toggleDropdownContentsCreateView` event on create label button click', () => {
findCreateLabelButton().vm.$emit('click'); findCreateLabelButton().vm.$emit('click', new MouseEvent('click'));
expect(wrapper.emitted('toggleDropdownContentsCreateView')).toEqual([[]]); expect(wrapper.emitted('toggleDropdownContentsCreateView')).toEqual([[]]);
}); });
......
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import DropdownTitle from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue';
import labelsSelectModule from '~/vue_shared/components/sidebar/labels_select_widget/store';
import { mockConfig } from './mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
const createComponent = (initialState = mockConfig) => {
const store = new Vuex.Store(labelsSelectModule());
store.dispatch('setInitialState', initialState);
return shallowMount(DropdownTitle, {
localVue,
store,
propsData: {
labelsSelectInProgress: false,
},
});
};
describe('DropdownTitle', () => {
let wrapper;
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('template', () => {
it('renders component container element with string "Labels"', () => {
expect(wrapper.text()).toContain('Labels');
});
it('renders edit link', () => {
const editBtnEl = wrapper.find(GlButton);
expect(editBtnEl.exists()).toBe(true);
expect(editBtnEl.text()).toBe('Edit');
});
it('renders loading icon element when `labelsSelectInProgress` prop is true', () => {
wrapper.setProps({
labelsSelectInProgress: true,
});
return wrapper.vm.$nextTick(() => {
expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true);
});
});
});
});
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import { isInViewport } from '~/lib/utils/common_utils';
import { DropdownVariant } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
import DropdownButton from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_button.vue';
import DropdownContents from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue'; import DropdownContents from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue';
import DropdownTitle from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue';
import DropdownValue from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue'; import DropdownValue from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue';
import DropdownValueCollapsed from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_value_collapsed.vue'; import DropdownValueCollapsed from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_value_collapsed.vue';
import LabelsSelectRoot from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue'; import LabelsSelectRoot from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue';
...@@ -32,11 +28,13 @@ describe('LabelsSelectRoot', () => { ...@@ -32,11 +28,13 @@ describe('LabelsSelectRoot', () => {
store, store,
propsData: config, propsData: config,
stubs: { stubs: {
'dropdown-contents': DropdownContents, DropdownContents,
SidebarEditableItem,
}, },
provide: { provide: {
iid: '1', iid: '1',
projectPath: 'test', projectPath: 'test',
canUpdate: true,
}, },
}); });
}; };
...@@ -49,41 +47,9 @@ describe('LabelsSelectRoot', () => { ...@@ -49,41 +47,9 @@ describe('LabelsSelectRoot', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('methods', () => {
describe('handleDropdownClose', () => {
beforeEach(() => {
createComponent();
});
it('emits `updateSelectedLabels` & `onDropdownClose` events on component when provided `labels` param is not empty', () => {
wrapper.vm.handleDropdownClose([{ id: 1 }, { id: 2 }]);
expect(wrapper.emitted().updateSelectedLabels).toBeTruthy();
expect(wrapper.emitted().onDropdownClose).toBeTruthy();
});
it('emits only `onDropdownClose` event on component when provided `labels` param is empty', () => {
wrapper.vm.handleDropdownClose([]);
expect(wrapper.emitted().updateSelectedLabels).toBeFalsy();
expect(wrapper.emitted().onDropdownClose).toBeTruthy();
});
});
describe('handleCollapsedValueClick', () => {
it('emits `toggleCollapse` event on component', () => {
createComponent();
wrapper.vm.handleCollapsedValueClick();
expect(wrapper.emitted().toggleCollapse).toBeTruthy();
});
});
});
describe('template', () => {
it('renders component with classes `labels-select-wrapper position-relative`', () => { it('renders component with classes `labels-select-wrapper position-relative`', () => {
createComponent(); createComponent();
expect(wrapper.attributes('class')).toContain('labels-select-wrapper position-relative'); expect(wrapper.classes()).toEqual(['labels-select-wrapper', 'position-relative']);
}); });
it.each` it.each`
...@@ -110,12 +76,6 @@ describe('LabelsSelectRoot', () => { ...@@ -110,12 +76,6 @@ describe('LabelsSelectRoot', () => {
expect(wrapper.find(DropdownValueCollapsed).exists()).toBe(true); expect(wrapper.find(DropdownValueCollapsed).exists()).toBe(true);
}); });
it('renders `dropdown-title` component', async () => {
createComponent();
await wrapper.vm.$nextTick;
expect(wrapper.find(DropdownTitle).exists()).toBe(true);
});
it('renders `dropdown-value` component', async () => { it('renders `dropdown-value` component', async () => {
createComponent(mockConfig, { createComponent(mockConfig, {
default: 'None', default: 'None',
...@@ -127,67 +87,4 @@ describe('LabelsSelectRoot', () => { ...@@ -127,67 +87,4 @@ describe('LabelsSelectRoot', () => {
expect(valueComp.exists()).toBe(true); expect(valueComp.exists()).toBe(true);
expect(valueComp.text()).toBe('None'); expect(valueComp.text()).toBe('None');
}); });
it('renders `dropdown-button` component when `showDropdownButton` prop is `true`', async () => {
createComponent();
wrapper.vm.$store.dispatch('toggleDropdownButton');
await wrapper.vm.$nextTick;
expect(wrapper.find(DropdownButton).exists()).toBe(true);
});
it('renders `dropdown-contents` component when `showDropdownButton` & `showDropdownContents` prop is `true`', async () => {
createComponent();
wrapper.vm.$store.dispatch('toggleDropdownContents');
await wrapper.vm.$nextTick;
expect(wrapper.find(DropdownContents).exists()).toBe(true);
});
describe('sets content direction based on viewport', () => {
describe.each(Object.values(DropdownVariant))(
'when labels variant is "%s"',
({ variant }) => {
beforeEach(() => {
createComponent({ ...mockConfig, variant });
wrapper.vm.$store.dispatch('toggleDropdownContents');
});
it('set direction when out of viewport', () => {
isInViewport.mockImplementation(() => false);
wrapper.vm.setContentIsOnViewport(wrapper.vm.$store.state);
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find(DropdownContents).props('renderOnTop')).toBe(true);
});
});
it('does not set direction when inside of viewport', () => {
isInViewport.mockImplementation(() => true);
wrapper.vm.setContentIsOnViewport(wrapper.vm.$store.state);
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find(DropdownContents).props('renderOnTop')).toBe(false);
});
});
},
);
});
});
it('calls toggleDropdownContents action when isEditing prop is changing to true', async () => {
createComponent();
jest.spyOn(store, 'dispatch').mockResolvedValue();
await wrapper.setProps({ isEditing: true });
expect(store.dispatch).toHaveBeenCalledWith('toggleDropdownContents');
});
it('does not call toggleDropdownContents action when isEditing prop is changing to false', async () => {
createComponent();
jest.spyOn(store, 'dispatch').mockResolvedValue();
await wrapper.setProps({ isEditing: false });
expect(store.dispatch).not.toHaveBeenCalled();
});
}); });
...@@ -83,9 +83,7 @@ export const createLabelSuccessfulResponse = { ...@@ -83,9 +83,7 @@ export const createLabelSuccessfulResponse = {
id: 'gid://gitlab/ProjectLabel/126', id: 'gid://gitlab/ProjectLabel/126',
color: '#dc143c', color: '#dc143c',
description: null, description: null,
descriptionHtml: '',
title: 'ewrwrwer', title: 'ewrwrwer',
textColor: '#FFFFFF',
__typename: 'Label', __typename: 'Label',
}, },
errors: [], errors: [],
......
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