Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js')
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js267
1 files changed, 267 insertions, 0 deletions
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js
new file mode 100644
index 00000000000..2995c268966
--- /dev/null
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js
@@ -0,0 +1,267 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+import { IssuableType } from '~/issues/constants';
+import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
+import DropdownContents from '~/sidebar/components/labels/labels_select_widget/dropdown_contents.vue';
+import DropdownValue from '~/sidebar/components/labels/labels_select_widget/dropdown_value.vue';
+import EmbeddedLabelsList from '~/sidebar/components/labels/labels_select_widget/embedded_labels_list.vue';
+import issueLabelsQuery from '~/sidebar/components/labels/labels_select_widget/graphql/issue_labels.query.graphql';
+import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
+import updateMergeRequestLabelsMutation from '~/sidebar/queries/update_merge_request_labels.mutation.graphql';
+import issuableLabelsSubscription from 'ee_else_ce/sidebar/queries/issuable_labels.subscription.graphql';
+import updateEpicLabelsMutation from '~/sidebar/components/labels/labels_select_widget/graphql/epic_update_labels.mutation.graphql';
+import LabelsSelectRoot from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue';
+import {
+ mockConfig,
+ issuableLabelsQueryResponse,
+ updateLabelsMutationResponse,
+ issuableLabelsSubscriptionResponse,
+ mockLabels,
+ mockRegularLabel,
+} from './mock_data';
+
+jest.mock('~/flash');
+
+Vue.use(VueApollo);
+
+const successfulQueryHandler = jest.fn().mockResolvedValue(issuableLabelsQueryResponse);
+const successfulMutationHandler = jest.fn().mockResolvedValue(updateLabelsMutationResponse);
+const subscriptionHandler = jest.fn().mockResolvedValue(issuableLabelsSubscriptionResponse);
+const errorQueryHandler = jest.fn().mockRejectedValue('Houston, we have a problem');
+
+const updateLabelsMutation = {
+ [IssuableType.Issue]: updateIssueLabelsMutation,
+ [IssuableType.MergeRequest]: updateMergeRequestLabelsMutation,
+ [IssuableType.Epic]: updateEpicLabelsMutation,
+};
+
+describe('LabelsSelectRoot', () => {
+ let wrapper;
+
+ const findSidebarEditableItem = () => wrapper.findComponent(SidebarEditableItem);
+ const findDropdownValue = () => wrapper.findComponent(DropdownValue);
+ const findDropdownContents = () => wrapper.findComponent(DropdownContents);
+ const findEmbeddedLabelsList = () => wrapper.findComponent(EmbeddedLabelsList);
+
+ const createComponent = ({
+ config = mockConfig,
+ slots = {},
+ issuableType = IssuableType.Issue,
+ queryHandler = successfulQueryHandler,
+ mutationHandler = successfulMutationHandler,
+ } = {}) => {
+ const mockApollo = createMockApollo([
+ [issueLabelsQuery, queryHandler],
+ [updateLabelsMutation[issuableType], mutationHandler],
+ [issuableLabelsSubscription, subscriptionHandler],
+ ]);
+
+ wrapper = shallowMount(LabelsSelectRoot, {
+ slots,
+ apolloProvider: mockApollo,
+ propsData: {
+ ...config,
+ issuableType,
+ labelCreateType: 'project',
+ workspaceType: 'project',
+ },
+ stubs: {
+ SidebarEditableItem,
+ },
+ provide: {
+ canUpdate: true,
+ allowLabelEdit: true,
+ allowLabelCreate: true,
+ labelsManagePath: 'test',
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders component with classes `labels-select-wrapper gl-relative`', () => {
+ createComponent();
+ expect(wrapper.classes()).toEqual(['labels-select-wrapper', 'gl-relative']);
+ });
+
+ it.each`
+ variant | cssClass
+ ${'standalone'} | ${'is-standalone'}
+ ${'embedded'} | ${'is-embedded'}
+ `(
+ 'renders component root element with CSS class `$cssClass` when `state.variant` is "$variant"',
+ async ({ variant, cssClass }) => {
+ createComponent({
+ config: { ...mockConfig, variant },
+ });
+
+ await nextTick();
+ expect(wrapper.classes()).toContain(cssClass);
+ },
+ );
+
+ describe('if dropdown variant is `sidebar`', () => {
+ it('renders sidebar editable item', () => {
+ createComponent();
+ expect(findSidebarEditableItem().exists()).toBe(true);
+ });
+
+ it('passes true `loading` prop to sidebar editable item when loading labels', () => {
+ createComponent();
+ expect(findSidebarEditableItem().props('loading')).toBe(true);
+ });
+
+ describe('when labels are fetched successfully', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('passes true `loading` prop to sidebar editable item', () => {
+ expect(findSidebarEditableItem().props('loading')).toBe(false);
+ });
+
+ it('renders dropdown value component when query labels is resolved', () => {
+ expect(findDropdownValue().exists()).toBe(true);
+ expect(findDropdownValue().props('selectedLabels')).toEqual([
+ {
+ __typename: 'Label',
+ color: '#330066',
+ description: null,
+ id: 'gid://gitlab/ProjectLabel/1',
+ title: 'Label1',
+ textColor: '#000000',
+ },
+ ]);
+ });
+
+ it('emits `onLabelRemove` event on dropdown value label remove event', () => {
+ const label = { id: 'gid://gitlab/ProjectLabel/1' };
+ findDropdownValue().vm.$emit('onLabelRemove', label);
+ expect(wrapper.emitted('onLabelRemove')).toEqual([[label]]);
+ });
+ });
+
+ it('creates flash with error message when query is rejected', async () => {
+ createComponent({ queryHandler: errorQueryHandler });
+ await waitForPromises();
+ expect(createAlert).toHaveBeenCalledWith({ message: 'Error fetching labels.' });
+ });
+ });
+
+ describe('if dropdown variant is `embedded`', () => {
+ it('shows the embedded labels list', () => {
+ createComponent({
+ config: { ...mockConfig, iid: '', variant: 'embedded', showEmbeddedLabelsList: true },
+ });
+
+ expect(findEmbeddedLabelsList().props()).toMatchObject({
+ disabled: false,
+ selectedLabels: [],
+ allowLabelRemove: false,
+ labelsFilterBasePath: mockConfig.labelsFilterBasePath,
+ labelsFilterParam: mockConfig.labelsFilterParam,
+ });
+ });
+
+ it('passes the selected labels if provided', () => {
+ createComponent({
+ config: {
+ ...mockConfig,
+ iid: '',
+ variant: 'embedded',
+ showEmbeddedLabelsList: true,
+ selectedLabels: mockLabels,
+ },
+ });
+
+ expect(findEmbeddedLabelsList().props('selectedLabels')).toStrictEqual(mockLabels);
+ expect(findDropdownContents().props('selectedLabels')).toStrictEqual(mockLabels);
+ });
+
+ it('emits the `onLabelRemove` when the embedded list triggers a removal', () => {
+ createComponent({
+ config: {
+ ...mockConfig,
+ iid: '',
+ variant: 'embedded',
+ showEmbeddedLabelsList: true,
+ selectedLabels: [mockRegularLabel],
+ },
+ });
+
+ findEmbeddedLabelsList().vm.$emit('onLabelRemove', [mockRegularLabel.id]);
+ expect(wrapper.emitted('onLabelRemove')).toStrictEqual([[[mockRegularLabel.id]]]);
+ });
+ });
+
+ it('emits `updateSelectedLabels` event on dropdown contents `setLabels` event if iid is not set', async () => {
+ const label = { id: 'gid://gitlab/ProjectLabel/1' };
+ createComponent({ config: { ...mockConfig, iid: undefined } });
+
+ findDropdownContents().vm.$emit('setLabels', [label]);
+ expect(wrapper.emitted('updateSelectedLabels')).toEqual([[{ labels: [label] }]]);
+ });
+
+ describe.each`
+ issuableType
+ ${IssuableType.Issue}
+ ${IssuableType.MergeRequest}
+ ${IssuableType.Epic}
+ `('when updating labels for $issuableType', ({ issuableType }) => {
+ const label = { id: 'gid://gitlab/ProjectLabel/2' };
+
+ it('sets the loading state', async () => {
+ createComponent({ issuableType });
+ await nextTick();
+ findDropdownContents().vm.$emit('setLabels', [label]);
+ await nextTick();
+
+ expect(findSidebarEditableItem().props('loading')).toBe(true);
+ });
+
+ it('updates labels correctly after successful mutation', async () => {
+ createComponent({ issuableType });
+ await nextTick();
+ findDropdownContents().vm.$emit('setLabels', [label]);
+ await waitForPromises();
+
+ expect(findDropdownValue().props('selectedLabels')).toEqual(
+ updateLabelsMutationResponse.data.updateIssuableLabels.issuable.labels.nodes,
+ );
+ });
+
+ it('displays an error if mutation was rejected', async () => {
+ createComponent({ issuableType, mutationHandler: errorQueryHandler });
+ await nextTick();
+ findDropdownContents().vm.$emit('setLabels', [label]);
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ captureError: true,
+ error: expect.anything(),
+ message: 'An error occurred while updating labels.',
+ });
+ });
+
+ it('emits `updateSelectedLabels` event when the subscription is triggered', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(wrapper.emitted('updateSelectedLabels')).toEqual([
+ [
+ {
+ id: '1',
+ labels: issuableLabelsSubscriptionResponse.data.issuableLabelsUpdated.labels.nodes,
+ },
+ ],
+ ]);
+ });
+ });
+});