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>2020-12-23 12:10:13 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-23 12:10:13 +0300
commit65fdda8d39a9af414dbe5aa3a385b9bcba00960b (patch)
tree8cdac4fe05966ae74301044522ad5be1e7087ed1 /spec/frontend/boards/project_select_spec.js
parentde64b03b15fb40a3fc2f1897e8e4f6be50fd4403 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/boards/project_select_spec.js')
-rw-r--r--spec/frontend/boards/project_select_spec.js267
1 files changed, 267 insertions, 0 deletions
diff --git a/spec/frontend/boards/project_select_spec.js b/spec/frontend/boards/project_select_spec.js
new file mode 100644
index 00000000000..e187828702e
--- /dev/null
+++ b/spec/frontend/boards/project_select_spec.js
@@ -0,0 +1,267 @@
+import { mount } from '@vue/test-utils';
+import axios from 'axios';
+import AxiosMockAdapter from 'axios-mock-adapter';
+import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlLoadingIcon } from '@gitlab/ui';
+import httpStatus from '~/lib/utils/http_status';
+import { featureAccessLevel } from '~/pages/projects/shared/permissions/constants';
+import { ListType } from '~/boards/constants';
+import eventHub from '~/boards/eventhub';
+import { deprecatedCreateFlash as flash } from '~/flash';
+
+import ProjectSelect from '~/boards/components/project_select.vue';
+
+import { listObj, mockRawGroupProjects } from './mock_data';
+
+jest.mock('~/boards/eventhub');
+jest.mock('~/flash');
+
+const dummyGon = {
+ api_version: 'v4',
+ relative_url_root: '/gitlab',
+};
+
+const mockGroupId = 1;
+const mockProjectsList1 = mockRawGroupProjects.slice(0, 1);
+const mockProjectsList2 = mockRawGroupProjects.slice(1);
+const mockDefaultFetchOptions = {
+ with_issues_enabled: true,
+ with_shared: false,
+ include_subgroups: true,
+ order_by: 'similarity',
+};
+
+const itemsPerPage = 20;
+
+describe('ProjectSelect component', () => {
+ let wrapper;
+ let axiosMock;
+
+ const findLabel = () => wrapper.find("[data-testid='header-label']");
+ const findGlDropdown = () => wrapper.find(GlDropdown);
+ const findGlDropdownLoadingIcon = () =>
+ findGlDropdown()
+ .find('button:first-child')
+ .find(GlLoadingIcon);
+ const findGlSearchBoxByType = () => wrapper.find(GlSearchBoxByType);
+ const findGlDropdownItems = () => wrapper.findAll(GlDropdownItem);
+ const findFirstGlDropdownItem = () => findGlDropdownItems().at(0);
+ const findInMenuLoadingIcon = () => wrapper.find("[data-testid='dropdown-text-loading-icon']");
+ const findEmptySearchMessage = () => wrapper.find("[data-testid='empty-result-message']");
+
+ const mockGetRequest = (data = [], statusCode = httpStatus.OK) => {
+ axiosMock
+ .onGet(`/gitlab/api/v4/groups/${mockGroupId}/projects.json`)
+ .replyOnce(statusCode, data);
+ };
+
+ const searchForProject = async (keyword, waitForAll = true) => {
+ findGlSearchBoxByType().vm.$emit('input', keyword);
+
+ if (waitForAll) {
+ await axios.waitForAll();
+ }
+ };
+
+ const createWrapper = async ({ list = listObj } = {}, waitForAll = true) => {
+ wrapper = mount(ProjectSelect, {
+ propsData: {
+ list,
+ },
+ provide: {
+ groupId: 1,
+ },
+ });
+
+ if (waitForAll) {
+ await axios.waitForAll();
+ }
+ };
+
+ beforeEach(() => {
+ axiosMock = new AxiosMockAdapter(axios);
+ window.gon = dummyGon;
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ axiosMock.restore();
+ jest.clearAllMocks();
+ });
+
+ it('displays a header title', async () => {
+ createWrapper({});
+
+ expect(findLabel().text()).toBe('Projects');
+ });
+
+ it('renders a default dropdown text', async () => {
+ createWrapper({});
+
+ expect(findGlDropdown().exists()).toBe(true);
+ expect(findGlDropdown().text()).toContain('Select a project');
+ });
+
+ describe('when mounted', () => {
+ it('displays a loading icon while projects are being fetched', async () => {
+ mockGetRequest([]);
+
+ createWrapper({}, false);
+
+ expect(findGlDropdownLoadingIcon().exists()).toBe(true);
+
+ await axios.waitForAll();
+
+ expect(axiosMock.history.get[0].params).toMatchObject({ search: '' });
+ expect(axiosMock.history.get[0].url).toBe(
+ `/gitlab/api/v4/groups/${mockGroupId}/projects.json`,
+ );
+
+ expect(findGlDropdownLoadingIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('when dropdown menu is open', () => {
+ describe('by default', () => {
+ beforeEach(async () => {
+ mockGetRequest(mockProjectsList1);
+
+ await createWrapper();
+ });
+
+ it('shows GlSearchBoxByType with default attributes', () => {
+ expect(findGlSearchBoxByType().exists()).toBe(true);
+ expect(findGlSearchBoxByType().vm.$attrs).toMatchObject({
+ placeholder: 'Search projects',
+ debounce: '250',
+ });
+ });
+
+ it("displays the fetched project's name", () => {
+ expect(findFirstGlDropdownItem().exists()).toBe(true);
+ expect(findFirstGlDropdownItem().text()).toContain(mockProjectsList1[0].name);
+ });
+
+ it("doesn't render loading icon in the menu", () => {
+ expect(findInMenuLoadingIcon().isVisible()).toBe(false);
+ });
+
+ it('renders empty search result message', async () => {
+ await createWrapper();
+
+ expect(findEmptySearchMessage().exists()).toBe(true);
+ });
+ });
+
+ describe('when a project is selected', () => {
+ beforeEach(async () => {
+ mockGetRequest(mockProjectsList1);
+
+ await createWrapper();
+
+ await findFirstGlDropdownItem()
+ .find('button')
+ .trigger('click');
+ });
+
+ it('emits setSelectedProject with correct project metadata', () => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('setSelectedProject', {
+ id: mockProjectsList1[0].id,
+ path: mockProjectsList1[0].path_with_namespace,
+ name: mockProjectsList1[0].name,
+ namespacedName: mockProjectsList1[0].name_with_namespace,
+ });
+ });
+
+ it('renders the name of the selected project', () => {
+ expect(
+ findGlDropdown()
+ .find('.gl-new-dropdown-button-text')
+ .text(),
+ ).toBe(mockProjectsList1[0].name);
+ });
+ });
+
+ describe('when user searches for a project', () => {
+ beforeEach(async () => {
+ mockGetRequest(mockProjectsList1);
+
+ await createWrapper();
+ });
+
+ it('calls API with correct parameters with default fetch options', async () => {
+ await searchForProject('foobar');
+
+ const expectedApiParams = {
+ search: 'foobar',
+ per_page: itemsPerPage,
+ ...mockDefaultFetchOptions,
+ };
+
+ expect(axiosMock.history.get[1].params).toMatchObject(expectedApiParams);
+ expect(axiosMock.history.get[1].url).toBe(
+ `/gitlab/api/v4/groups/${mockGroupId}/projects.json`,
+ );
+ });
+
+ describe("when list type is defined and isn't backlog", () => {
+ it('calls API with an additional fetch option (min_access_level)', async () => {
+ axiosMock.reset();
+
+ await createWrapper({ list: { ...listObj, type: ListType.label } });
+
+ await searchForProject('foobar');
+
+ const expectedApiParams = {
+ search: 'foobar',
+ per_page: itemsPerPage,
+ ...mockDefaultFetchOptions,
+ min_access_level: featureAccessLevel.EVERYONE,
+ };
+
+ expect(axiosMock.history.get[1].params).toMatchObject(expectedApiParams);
+ expect(axiosMock.history.get[1].url).toBe(
+ `/gitlab/api/v4/groups/${mockGroupId}/projects.json`,
+ );
+ });
+ });
+
+ it('displays and hides gl-loading-icon while and after fetching data', async () => {
+ await searchForProject('some keyword', false);
+
+ await wrapper.vm.$nextTick();
+
+ expect(findInMenuLoadingIcon().isVisible()).toBe(true);
+
+ await axios.waitForAll();
+
+ expect(findInMenuLoadingIcon().isVisible()).toBe(false);
+ });
+
+ it('flashes an error message when fetching fails', async () => {
+ mockGetRequest([], httpStatus.INTERNAL_SERVER_ERROR);
+
+ await searchForProject('foobar');
+
+ expect(flash).toHaveBeenCalledTimes(1);
+ expect(flash).toHaveBeenCalledWith('Something went wrong while fetching projects');
+ });
+
+ describe('with non-empty search result', () => {
+ beforeEach(async () => {
+ mockGetRequest(mockProjectsList2);
+
+ await searchForProject('foobar');
+ });
+
+ it('displays the retrieved list of projects', async () => {
+ expect(findFirstGlDropdownItem().text()).toContain(mockProjectsList2[0].name);
+ });
+
+ it('does not render empty search result message', async () => {
+ expect(findEmptySearchMessage().exists()).toBe(false);
+ });
+ });
+ });
+ });
+});