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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-10-31 21:07:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-10-31 21:07:22 +0300
commit1d21e1712158ee4e3cf8b71b45ead662529fc3f8 (patch)
treea8435cf28a026d7d7ef681d459e905bcf5609f65 /spec/frontend
parent47bf4294773cf15aa755193cdd7df9a491a49f52 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/design_management/components/design_notes/design_note_spec.js43
-rw-r--r--spec/frontend/issues/show/components/header_actions_spec.js52
-rw-r--r--spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js358
-rw-r--r--spec/frontend/work_items/components/work_item_milestone_spec.js53
-rw-r--r--spec/frontend/work_items/components/work_item_parent_spec.js5
5 files changed, 183 insertions, 328 deletions
diff --git a/spec/frontend/design_management/components/design_notes/design_note_spec.js b/spec/frontend/design_management/components/design_notes/design_note_spec.js
index 91c6acd8890..28b264cede9 100644
--- a/spec/frontend/design_management/components/design_notes/design_note_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_note_spec.js
@@ -51,13 +51,19 @@ describe('Design note component', () => {
const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
const findDropdownItems = () => findDropdown().findAllComponents(GlDisclosureDropdownItem);
const findEditDropdownItem = () => findDropdownItems().at(0);
- const findDeleteDropdownItem = () => findDropdownItems().at(1);
+ const findCopyLinkDropdownItem = () => findDropdownItems().at(1);
+ const findDeleteDropdownItem = () => findDropdownItems().at(2);
+
+ const showToast = jest.fn();
function createComponent({
props = {},
data = { isEditing: false },
mountFn = mountExtended,
mocks = {
+ $toast: {
+ show: showToast,
+ },
$route,
$apollo: {
mutate: jest.fn().mockResolvedValue({ data: { updateNote: {} } }),
@@ -239,6 +245,7 @@ describe('Design note component', () => {
expect(findDropdown().exists()).toBe(true);
expect(findEditDropdownItem().exists()).toBe(true);
+ expect(findCopyLinkDropdownItem().exists()).toBe(true);
expect(findDeleteDropdownItem().exists()).toBe(true);
expect(findDropdown().props('items')[0].extraAttrs.class).toBe('gl-sm-display-none!');
});
@@ -266,6 +273,40 @@ describe('Design note component', () => {
expect(wrapper.emitted()).toEqual({ 'delete-note': [[{ ...payload }]] });
});
+ it('shows a success toast after copying the url to the clipboard', () => {
+ createComponent({
+ props: {
+ note: {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ },
+ },
+ });
+
+ findCopyLinkDropdownItem().find('button').trigger('click');
+
+ expect(showToast).toHaveBeenCalledWith('Link copied to clipboard.');
+ });
+
+ it('has data-clipboard-text set to the correct url', () => {
+ createComponent({
+ props: {
+ note: {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ },
+ },
+ });
+
+ expect(findCopyLinkDropdownItem().props('item').extraAttrs['data-clipboard-text']).toBe(
+ 'http://test.host/#note_123',
+ );
+ });
+
describe('when user has award emoji permissions', () => {
const findEmojiPicker = () => wrapper.findComponent(EmojiPicker);
const propsData = {
diff --git a/spec/frontend/issues/show/components/header_actions_spec.js b/spec/frontend/issues/show/components/header_actions_spec.js
index e508045eff3..d0c2a1a5f1b 100644
--- a/spec/frontend/issues/show/components/header_actions_spec.js
+++ b/spec/frontend/issues/show/components/header_actions_spec.js
@@ -1,9 +1,16 @@
import Vue, { nextTick } from 'vue';
-import { GlDropdown, GlDropdownItem, GlLink, GlModal, GlButton } from '@gitlab/ui';
+import {
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlLink,
+ GlModal,
+ GlButton,
+} from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import VueApollo from 'vue-apollo';
+import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import { mockTracking } from 'helpers/tracking_helper';
import { createAlert, VARIANT_SUCCESS } from '~/alert';
@@ -120,8 +127,10 @@ describe('HeaderActions component', () => {
const findDropdownBy = (dataTestId) => wrapper.find(`[data-testid="${dataTestId}"]`);
const findMobileDropdown = () => findDropdownBy('mobile-dropdown');
const findDesktopDropdown = () => findDropdownBy('desktop-dropdown');
- const findMobileDropdownItems = () => findMobileDropdown().findAllComponents(GlDropdownItem);
- const findDesktopDropdownItems = () => findDesktopDropdown().findAllComponents(GlDropdownItem);
+ const findMobileDropdownItems = () =>
+ findMobileDropdown().findAllComponents(GlDisclosureDropdownItem);
+ const findDesktopDropdownItems = () =>
+ findDesktopDropdown().findAllComponents(GlDisclosureDropdownItem);
const findAbuseCategorySelector = () => wrapper.findComponent(AbuseCategorySelector);
const findReportAbuseButton = () => wrapper.find(`[data-testid="report-abuse-item"]`);
const findNotificationWidget = () => wrapper.find(`[data-testid="notification-toggle"]`);
@@ -179,6 +188,11 @@ describe('HeaderActions component', () => {
},
stubs: {
GlButton,
+ GlDisclosureDropdown: stubComponent(GlDisclosureDropdown, {
+ methods: {
+ close: jest.fn(),
+ },
+ }),
},
});
};
@@ -217,7 +231,7 @@ describe('HeaderActions component', () => {
});
it('calls apollo mutation', () => {
- findToggleIssueStateButton().vm.$emit('click');
+ findToggleIssueStateButton().vm.$emit('action');
expect(updateIssueMutationResponseHandler).toHaveBeenCalledWith({
input: {
@@ -229,7 +243,7 @@ describe('HeaderActions component', () => {
});
it('dispatches a custom event to update the issue page', async () => {
- findToggleIssueStateButton().vm.$emit('click');
+ findToggleIssueStateButton().vm.$emit('action');
await waitForPromises();
@@ -286,7 +300,11 @@ describe('HeaderActions component', () => {
it(`${isItemVisible ? 'shows' : 'hides'} "${itemText}" item`, () => {
expect(
findDropdownItems()
- .filter((item) => item.text() === itemText)
+ .filter((item) => {
+ return item.props('item')
+ ? item.props('item').text === itemText
+ : item.text() === itemText;
+ })
.exists(),
).toBe(isItemVisible);
});
@@ -313,7 +331,7 @@ describe('HeaderActions component', () => {
it('should trigger "open.form" event when clicked', async () => {
expect(issuesEventHub.$emit).not.toHaveBeenCalled();
- await findEditButton().trigger('click');
+ await findEditButton().vm.$emit('click');
expect(issuesEventHub.$emit).toHaveBeenCalledWith('open.form');
});
});
@@ -328,7 +346,7 @@ describe('HeaderActions component', () => {
});
it('tracks clicking on button', () => {
- findDesktopDropdownItems().at(4).vm.$emit('click');
+ findDesktopDropdownItems().at(4).vm.$emit('action');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_dropdown', {
label: 'delete_issue',
@@ -345,7 +363,7 @@ describe('HeaderActions component', () => {
promoteToEpicHandler: promoteToEpicMutationSuccessResponseHandler,
});
- wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
+ wrapper.find('[data-testid="promote-button"]').vm.$emit('action');
await waitForPromises();
});
@@ -381,7 +399,7 @@ describe('HeaderActions component', () => {
promoteToEpicHandler: promoteToEpicMutationErrorHandler,
});
- wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
+ wrapper.find('[data-testid="promote-button"]').vm.$emit('action');
await waitForPromises();
});
@@ -483,7 +501,7 @@ describe('HeaderActions component', () => {
});
it('opens the abuse category drawer', async () => {
- findReportAbuseButton().vm.$emit('click');
+ findReportAbuseButton().vm.$emit('action');
await nextTick();
@@ -491,7 +509,7 @@ describe('HeaderActions component', () => {
});
it('closes the abuse category drawer', async () => {
- await findReportAbuseButton().vm.$emit('click');
+ await findReportAbuseButton().vm.$emit('action');
expect(findAbuseCategorySelector().exists()).toEqual(true);
await findAbuseCategorySelector().vm.$emit('close-drawer');
@@ -603,7 +621,7 @@ describe('HeaderActions component', () => {
});
it('shows toast message', () => {
- findCopyRefenceDropdownItem().vm.$emit('click');
+ findCopyRefenceDropdownItem().vm.$emit('action');
expect(toast).toHaveBeenCalledWith('Reference copied');
});
@@ -652,7 +670,7 @@ describe('HeaderActions component', () => {
});
it('shows toast message', () => {
- findCopyEmailItem().vm.$emit('click');
+ findCopyEmailItem().vm.$emit('action');
expect(toast).toHaveBeenCalledWith('Email address copied');
});
@@ -710,11 +728,13 @@ describe('HeaderActions component', () => {
props: { issueType, issuableEmailAddress: 'mock-email-address' },
});
- expect(wrapper.findComponent(GlDropdown).attributes('text')).toBe(
+ expect(wrapper.findComponent(GlDisclosureDropdown).props('toggleText')).toBe(
`${capitalizeFirstCharacter(expectedText)} actions`,
);
expect(findDropdownBy('copy-email').text()).toBe(`Copy ${expectedText} email address`);
- expect(findDesktopDropdownItems().at(1).text()).toBe(`New related ${expectedText}`);
+ expect(findDesktopDropdownItems().at(1).props('item').text).toBe(
+ `New related ${expectedText}`,
+ );
});
});
});
diff --git a/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js b/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
index 56c915c4cae..f049001ba45 100644
--- a/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
+++ b/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
@@ -1,19 +1,9 @@
-import { nextTick } from 'vue';
-import {
- GlIcon,
- GlLoadingIcon,
- GlDropdown,
- GlDropdownForm,
- GlDropdownItem,
- GlSearchBoxByType,
- GlButton,
-} from '@gitlab/ui';
+import { GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import IssuableMoveDropdown from '~/sidebar/components/move/issuable_move_dropdown.vue';
-import { stubComponent } from 'helpers/stub_component';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
const mockProjects = [
@@ -42,318 +32,136 @@ const mockProps = {
disabled: false,
};
-const mockEvent = {
- stopPropagation: jest.fn(),
- preventDefault: jest.fn(),
-};
-
-const focusInputMock = jest.fn();
-const hideMock = jest.fn();
-
describe('IssuableMoveDropdown', () => {
let mock;
let wrapper;
- const createComponent = (propsData = mockProps) => {
- wrapper = shallowMountExtended(IssuableMoveDropdown, {
- propsData,
- stubs: {
- GlDropdown: stubComponent(GlDropdown, {
- methods: {
- hide: hideMock,
- },
- }),
- GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
- methods: {
- focusInput: focusInputMock,
- },
- }),
- },
- });
+ const createComponent = (propsData = {}) => {
+ wrapper = mountExtended(IssuableMoveDropdown, { propsData: { ...mockProps, ...propsData } });
};
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, mockProjects);
-
- createComponent();
});
afterEach(() => {
mock.restore();
});
- const findCollapsedEl = () => wrapper.findByTestId('move-collapsed');
- const findFooter = () => wrapper.findByTestId('footer');
- const findHeader = () => wrapper.findByTestId('header');
- const findFailedLoadResults = () => wrapper.findByTestId('failed-load-results');
- const findDropdownContent = () => wrapper.findByTestId('content');
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findDropdownEl = () => wrapper.findComponent(GlDropdown);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
-
- describe('watch', () => {
- describe('searchKey', () => {
- it('calls `fetchProjects` with value of the prop', async () => {
- jest.spyOn(axios, 'get');
- findSearchBox().vm.$emit('input', 'foo');
-
- await waitForPromises();
-
- expect(axios.get).toHaveBeenCalledWith('/-/autocomplete/projects?project_id=1', {
- params: { search: 'foo' },
- });
- });
- });
- });
-
- describe('methods', () => {
- describe('fetchProjects', () => {
- it('sets projectsListLoading to true and projectsListLoadFailed to false', async () => {
- findDropdownEl().vm.$emit('shown');
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findFailedLoadResults().exists()).toBe(false);
- });
-
- it('calls `axios.get` with `projectsFetchPath` and query param `search`', async () => {
- jest.spyOn(axios, 'get');
-
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
-
- expect(axios.get).toHaveBeenCalledWith(
- mockProps.projectsFetchPath,
- expect.objectContaining({
- params: {
- search: 'foo',
- },
- }),
- );
- });
-
- it('sets response to `projects` and focuses on searchInput when request is successful', async () => {
- jest.spyOn(axios, 'get');
-
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
+ const findDropdownButton = () => wrapper.findByTestId('dropdown-button');
+ const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
+ const findDropdownMoveButton = () => wrapper.findByTestId('dropdown-move-button');
+ const findDropdownItemsText = () =>
+ wrapper.findAllComponents(GlListboxItem).wrappers.map((item) => item.text());
- expect(findAllDropdownItems()).toHaveLength(mockProjects.length);
- expect(focusInputMock).toHaveBeenCalled();
- });
-
- it('sets projectsListLoadFailed to true when request fails', async () => {
- jest.spyOn(axios, 'get').mockRejectedValue({});
-
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
-
- expect(findFailedLoadResults().exists()).toBe(true);
- });
-
- it('sets projectsListLoading to false when request completes', async () => {
- jest.spyOn(axios, 'get');
-
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
- });
-
- describe('isSelectedProject', () => {
- it.each`
- projectIndex | selectedProjectIndex | title | returnValue
- ${0} | ${0} | ${'are same projects'} | ${true}
- ${0} | ${1} | ${'are different projects'} | ${false}
- `(
- 'returns $returnValue when selectedProject and provided project param $title',
- async ({ projectIndex, selectedProjectIndex, returnValue }) => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
-
- findAllDropdownItems().at(selectedProjectIndex).vm.$emit('click', mockEvent);
-
- await nextTick();
-
- expect(findAllDropdownItems().at(projectIndex).props('isChecked')).toBe(returnValue);
- },
- );
-
- it('returns false when selectedProject is null', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('renders a dropdown button with provided title and header', () => {
+ createComponent();
- expect(findAllDropdownItems().at(0).props('isChecked')).toBe(false);
- });
- });
+ expect(findDropdownButton().text()).toBe(mockProps.dropdownButtonTitle);
+ expect(findDropdown().props('headerText')).toBe(mockProps.dropdownHeaderTitle);
});
- describe('template', () => {
- it('renders collapsed state element with icon', () => {
- const collapsedEl = findCollapsedEl();
-
- expect(collapsedEl.exists()).toBe(true);
- expect(collapsedEl.attributes('title')).toBe(mockProps.dropdownButtonTitle);
- expect(collapsedEl.findComponent(GlIcon).exists()).toBe(true);
- expect(collapsedEl.findComponent(GlIcon).props('name')).toBe('arrow-right');
- });
-
- describe('gl-dropdown component', () => {
- it('renders component container element', () => {
- expect(findDropdownEl().exists()).toBe(true);
- expect(findDropdownEl().props('block')).toBe(true);
- });
+ it('renders the dropdown button as disabled when disabled prop is true', () => {
+ createComponent({ disabled: true });
- it('renders gl-dropdown-form component', () => {
- expect(findDropdownEl().findComponent(GlDropdownForm).exists()).toBe(true);
- });
-
- it('renders disabled dropdown when `disabled` is true', () => {
- createComponent({ ...mockProps, disabled: true });
- expect(findDropdownEl().props('disabled')).toBe(true);
- });
-
- it('renders header element', () => {
- const headerEl = findHeader();
-
- expect(headerEl.exists()).toBe(true);
- expect(headerEl.find('span').text()).toBe(mockProps.dropdownHeaderTitle);
- expect(headerEl.findComponent(GlButton).props('icon')).toBe('close');
- });
-
- it('renders gl-search-box-by-type component', () => {
- const searchEl = findDropdownEl().findComponent(GlSearchBoxByType);
-
- expect(searchEl.exists()).toBe(true);
- expect(searchEl.attributes()).toMatchObject({
- placeholder: 'Search project',
- debounce: '300',
- });
- });
-
- it('renders gl-loading-icon component when projectsListLoading prop is true', async () => {
- findDropdownEl().vm.$emit('shown');
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('renders gl-dropdown-item components for available projects', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
-
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
-
- expect(findAllDropdownItems()).toHaveLength(mockProjects.length);
- expect(findAllDropdownItems().at(0).props()).toMatchObject({
- isCheckItem: true,
- isChecked: true,
- });
- expect(findAllDropdownItems().at(0).text()).toBe(mockProjects[0].name_with_namespace);
- });
-
- it('renders string "No matching results" when search does not yield any matches', async () => {
- mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, []);
+ expect(findDropdownButton().props('disabled')).toBe(true);
+ });
- findSearchBox().vm.$emit('input', 'foo');
- await waitForPromises();
+ it('triggers a project search when dropdown button is clicked', async () => {
+ createComponent();
- expect(findDropdownContent().text()).toContain('No matching results');
- });
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- it('renders string "Failed to load projects" when loading projects list fails', async () => {
- mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, []);
- jest.spyOn(axios, 'get').mockRejectedValue({});
+ expect(mock.history.get).toHaveLength(1);
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ expect(findDropdownItemsText()).toEqual([
+ 'Gitlab Org / Gitlab Shell',
+ 'Gnuwget / Wget2',
+ 'Commit451 / Lab Coat',
+ ]);
+ });
- expect(findDropdownContent().text()).toContain('Failed to load projects');
- });
+ it('shows "No matching results" when no projects are found', async () => {
+ createComponent();
- it('renders gl-button within footer', async () => {
- const moveButtonEl = findFooter().findComponent(GlButton);
+ mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, []);
- expect(moveButtonEl.text()).toBe('Move');
- expect(moveButtonEl.attributes('disabled')).toBeDefined();
+ await findDropdown().vm.$emit('search', 'foobar');
+ await waitForPromises();
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ expect(findDropdown().text()).toContain('No matching results');
+ expect(findDropdownItemsText()).toEqual([]);
+ });
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ it('shows "Failed to load projects" when request fails', async () => {
+ createComponent();
- expect(findFooter().findComponent(GlButton).attributes('disabled')).not.toBeDefined();
- });
- });
+ mock.onGet(mockProps.projectsFetchPath).networkError();
- describe('events', () => {
- it('collapsed state element emits `toggle-collapse` event on component when clicked', () => {
- findCollapsedEl().trigger('click');
+ await findDropdown().vm.$emit('search', 'foobar');
+ await waitForPromises();
- expect(wrapper.emitted('toggle-collapse')).toHaveLength(1);
- });
+ expect(findDropdown().text()).toContain('Failed to load projects');
+ expect(findDropdownItemsText()).toEqual([]);
+ });
- it('gl-dropdown component calls `fetchProjects` on `shown` event', () => {
- jest.spyOn(axios, 'get');
+ it('disables the Move issuable button if no project is selected', async () => {
+ createComponent();
- findDropdownEl().vm.$emit('shown');
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- expect(axios.get).toHaveBeenCalled();
- });
+ expect(findDropdownMoveButton().props('disabled')).toBe(true);
+ });
- it('gl-dropdown component prevents dropdown body from closing on `hide` event when `projectItemClick` prop is true', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('shows search results when search is successful', async () => {
+ createComponent();
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ mock.onGet(mockProps.projectsFetchPath).reply(HTTP_STATUS_OK, [
+ {
+ id: 2,
+ name_with_namespace: 'Gitlab Org / Gitlab Shell',
+ full_path: 'gitlab-org/gitlab-shell',
+ },
+ ]);
- findDropdownEl().vm.$emit('hide', mockEvent);
+ await findDropdown().vm.$emit('search', 'shell');
+ await waitForPromises();
- expect(mockEvent.preventDefault).toHaveBeenCalled();
- });
+ expect(findDropdownItemsText()).toEqual(['Gitlab Org / Gitlab Shell']);
+ });
- it('gl-dropdown component emits `dropdown-close` event on component from `hide` event', () => {
- findDropdownEl().vm.$emit('hide');
+ it('emits "move-issuable" event when Move issuable button is clicked', async () => {
+ createComponent();
- expect(wrapper.emitted('dropdown-close')).toHaveLength(1);
- });
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- it('close icon in dropdown header closes the dropdown when clicked', async () => {
- findHeader().findComponent(GlButton).vm.$emit('click', mockEvent);
+ await wrapper.findAllComponents(GlListboxItem).wrappers[0].trigger('click');
+ await findDropdownMoveButton().trigger('click');
- await nextTick();
- expect(hideMock).toHaveBeenCalled();
- });
+ expect(wrapper.emitted('move-issuable')).toEqual([[mockProjects[0]]]);
+ });
- it('sets project for clicked gl-dropdown-item to selectedProject', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('disables the Move issuable button when moveInProgress prop is true', async () => {
+ createComponent({ moveInProgress: true });
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- expect(findAllDropdownItems().at(0).props('isChecked')).toBe(true);
- });
+ expect(findDropdownMoveButton().props('disabled')).toBe(true);
+ });
- it('hides dropdown and emits `move-issuable` event when move button is clicked', async () => {
- findDropdownEl().vm.$emit('shown');
- await waitForPromises();
+ it('emits "dropdown-close" event when dropdown is hidden', async () => {
+ createComponent();
- findAllDropdownItems().at(0).vm.$emit('click', mockEvent);
- await nextTick();
+ await findDropdownButton().trigger('click');
+ await waitForPromises();
- findFooter().findComponent(GlButton).vm.$emit('click');
+ await findDropdown().vm.$emit('hidden');
- expect(hideMock).toHaveBeenCalled();
- expect(wrapper.emitted('move-issuable')).toHaveLength(1);
- expect(wrapper.emitted('move-issuable')[0]).toEqual([mockProjects[0]]);
- });
- });
+ expect(wrapper.emitted('dropdown-close')).toHaveLength(1);
});
});
diff --git a/spec/frontend/work_items/components/work_item_milestone_spec.js b/spec/frontend/work_items/components/work_item_milestone_spec.js
index e303ad4b481..fc2c5eb2af2 100644
--- a/spec/frontend/work_items/components/work_item_milestone_spec.js
+++ b/spec/frontend/work_items/components/work_item_milestone_spec.js
@@ -1,14 +1,8 @@
-import {
- GlDropdown,
- GlDropdownItem,
- GlSearchBoxByType,
- GlSkeletonLoader,
- GlFormGroup,
- GlDropdownText,
-} from '@gitlab/ui';
+import { GlCollapsibleListbox, GlListboxItem, GlSkeletonLoader, GlFormGroup } from '@gitlab/ui';
+
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
-import WorkItemMilestone from '~/work_items/components/work_item_milestone.vue';
+import WorkItemMilestone, { noMilestoneId } from '~/work_items/components/work_item_milestone.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -32,17 +26,13 @@ describe('WorkItemMilestone component', () => {
const workItemId = 'gid://gitlab/WorkItem/1';
const workItemType = 'Task';
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
- const findNoMilestoneDropdownItem = () => wrapper.findByTestId('no-milestone');
- const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findFirstDropdownItem = () => findDropdownItems().at(0);
- const findDropdownTexts = () => wrapper.findAllComponents(GlDropdownText);
- const findDropdownItemAtIndex = (index) => findDropdownItems().at(index);
+ const findNoMilestoneDropdownItem = () => wrapper.findByTestId('listbox-item-no-milestone-id');
+ const findDropdownItems = () => wrapper.findAllComponents(GlListboxItem);
const findDisabledTextSpan = () => wrapper.findByTestId('disabled-text');
- const findDropdownTextAtIndex = (index) => findDropdownTexts().at(index);
const findInputGroup = () => wrapper.findComponent(GlFormGroup);
+ const findNoResultsText = () => wrapper.findByTestId('no-results-text');
const successSearchQueryHandler = jest.fn().mockResolvedValue(projectMilestonesResponse);
const successSearchWithNoMatchingMilestones = jest
@@ -74,8 +64,7 @@ describe('WorkItemMilestone component', () => {
workItemType,
},
stubs: {
- GlDropdown,
- GlSearchBoxByType,
+ GlCollapsibleListbox,
},
});
};
@@ -106,7 +95,7 @@ describe('WorkItemMilestone component', () => {
it(`has a value of "Add to milestone"`, () => {
createComponent({ canUpdate: true, milestone: null });
- expect(findDropdown().props('text')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
+ expect(findDropdown().props('toggleText')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
});
});
@@ -114,7 +103,7 @@ describe('WorkItemMilestone component', () => {
it('has the search box', () => {
createComponent();
- expect(findSearchBox().exists()).toBe(true);
+ expect(findDropdown().props('searchable')).toBe(true);
});
it('shows no matching results when no items', () => {
@@ -122,9 +111,8 @@ describe('WorkItemMilestone component', () => {
searchQueryHandler: successSearchWithNoMatchingMilestones,
});
- expect(findDropdownTextAtIndex(0).text()).toBe(WorkItemMilestone.i18n.NO_MATCHING_RESULTS);
+ expect(findNoResultsText().text()).toBe(WorkItemMilestone.i18n.NO_MATCHING_RESULTS);
expect(findDropdownItems()).toHaveLength(1);
- expect(findDropdownTexts()).toHaveLength(1);
});
});
@@ -165,16 +153,18 @@ describe('WorkItemMilestone component', () => {
it('changes the milestone to null when clicked on no milestone', async () => {
showDropdown();
- findFirstDropdownItem().vm.$emit('click');
+ findDropdown().vm.$emit('select', noMilestoneId);
hideDropdown();
await nextTick();
expect(findDropdown().props('loading')).toBe(true);
await waitForPromises();
-
- expect(findDropdown().props('loading')).toBe(false);
- expect(findDropdown().props('text')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
+ expect(findDropdown().props()).toMatchObject({
+ loading: false,
+ toggleText: WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER,
+ toggleClass: expect.arrayContaining(['gl-text-gray-500!']),
+ });
});
it('changes the milestone to the selected milestone', async () => {
@@ -182,15 +172,16 @@ describe('WorkItemMilestone component', () => {
/** the index is -1 since no matching results is also a dropdown item */
const milestoneAtIndex =
projectMilestonesResponse.data.workspace.attributes.nodes[milestoneIndex - 1];
+
showDropdown();
await waitForPromises();
- findDropdownItemAtIndex(milestoneIndex).vm.$emit('click');
+ findDropdown().vm.$emit('select', milestoneAtIndex.id);
hideDropdown();
await waitForPromises();
- expect(findDropdown().props('text')).toBe(milestoneAtIndex.title);
+ expect(findDropdown().props('toggleText')).toBe(milestoneAtIndex.title);
});
});
@@ -208,7 +199,7 @@ describe('WorkItemMilestone component', () => {
});
showDropdown();
- findFirstDropdownItem().vm.$emit('click');
+ findDropdown().vm.$emit('select', noMilestoneId);
hideDropdown();
await waitForPromises();
@@ -224,7 +215,7 @@ describe('WorkItemMilestone component', () => {
createComponent({ canUpdate: true });
showDropdown();
- findFirstDropdownItem().vm.$emit('click');
+ findDropdown().vm.$emit('select', noMilestoneId);
hideDropdown();
await waitForPromises();
diff --git a/spec/frontend/work_items/components/work_item_parent_spec.js b/spec/frontend/work_items/components/work_item_parent_spec.js
index a977e7d396f..c60620d210a 100644
--- a/spec/frontend/work_items/components/work_item_parent_spec.js
+++ b/spec/frontend/work_items/components/work_item_parent_spec.js
@@ -87,7 +87,6 @@ describe('WorkItemParent component', () => {
headerText: 'Assign parent',
category: 'tertiary',
loading: false,
- noCaret: true,
isCheckCentered: true,
searchable: true,
searching: false,
@@ -96,7 +95,6 @@ describe('WorkItemParent component', () => {
toggleText: 'None',
searchPlaceholder: 'Search',
resetButtonLabel: 'Unassign',
- block: true,
});
});
@@ -104,14 +102,12 @@ describe('WorkItemParent component', () => {
createComponent({ canUpdate: false, parent: mockParentWidgetResponse });
expect(findCollapsibleListbox().exists()).toBe(false);
- expect(findParentText().exists()).toBe(true);
expect(findParentText().text()).toBe('Objective 101');
});
it('shows loading while searching', async () => {
await findCollapsibleListbox().vm.$emit('shown');
expect(findCollapsibleListbox().props('searching')).toBe(true);
- expect(findCollapsibleListbox().props('no-caret')).toBeUndefined();
});
});
@@ -170,7 +166,6 @@ describe('WorkItemParent component', () => {
describe('listbox', () => {
const selectWorkItem = async (workItem) => {
- await findCollapsibleListbox().vm.$emit('shown');
await findCollapsibleListbox().vm.$emit('select', workItem);
};