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-11-07 18:19:19 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-11-07 18:19:19 +0300
commitd4fcd1794ea9fc10d83cdc75490f76a418e59d52 (patch)
treeb072bfe2c59dc666ddaa28c11e0c04a7971014e0 /spec/frontend/vue_shared/components
parentdfa6eac07553d5a3f254ee904e4298bd666b410f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/vue_shared/components')
-rw-r--r--spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js52
-rw-r--r--spec/frontend/vue_shared/components/list_selector/index_spec.js114
-rw-r--r--spec/frontend/vue_shared/components/list_selector/mock_data.js40
3 files changed, 112 insertions, 94 deletions
diff --git a/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js b/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
index 40232eb367a..810269257b6 100644
--- a/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
@@ -1,15 +1,16 @@
import {
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
GlSprintf,
- GlDropdown,
- GlDropdownItem,
- GlDropdownText,
GlSearchBoxByType,
+ GlIcon,
} from '@gitlab/ui';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { nextTick } from 'vue';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
import DiffStatsDropdown, { i18n } from '~/vue_shared/components/diff_stats_dropdown.vue';
+import { ARROW_DOWN_KEY } from '~/lib/utils/keys';
jest.mock('fuzzaldrin-plus', () => ({
filter: jest.fn().mockReturnValue([]),
@@ -42,7 +43,7 @@ describe('Diff Stats Dropdown', () => {
const focusInputMock = jest.fn();
const createComponent = ({ changed = 0, added = 0, deleted = 0, files = [] } = {}) => {
- wrapper = shallowMountExtended(DiffStatsDropdown, {
+ wrapper = mountExtended(DiffStatsDropdown, {
propsData: {
changed,
added,
@@ -51,7 +52,6 @@ describe('Diff Stats Dropdown', () => {
},
stubs: {
GlSprintf,
- GlDropdown,
GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
methods: { focusInput: focusInputMock },
}),
@@ -59,9 +59,8 @@ describe('Diff Stats Dropdown', () => {
});
};
- const findChanged = () => wrapper.findComponent(GlDropdown);
- const findChangedFiles = () => findChanged().findAllComponents(GlDropdownItem);
- const findNoFilesText = () => findChanged().findComponent(GlDropdownText);
+ const findChanged = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findChangedFiles = () => findChanged().findAllComponents(GlDisclosureDropdownItem);
const findCollapsed = () => wrapper.findByTestId('diff-stats-additions-deletions-expanded');
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
@@ -79,15 +78,14 @@ describe('Diff Stats Dropdown', () => {
const fileText = findChangedFiles().at(1).text();
expect(fileText).toContain(mockFiles[1].name);
expect(fileText).toContain(mockFiles[1].path);
- expect(fileData.props()).toMatchObject({
- iconName: mockFiles[1].icon,
- iconColor: mockFiles[1].iconColor,
- });
+ expect(fileData.findComponent(GlIcon).props('name')).toEqual(mockFiles[1].icon);
+ expect(fileData.findComponent(GlIcon).classes()).toContain('gl-text-red-500');
+ expect(fileData.find('a').attributes('href')).toEqual(mockFiles[1].href);
});
it('when no files changed', () => {
createComponent({ files: [] });
- expect(findNoFilesText().text()).toContain(i18n.noFilesFound);
+ expect(findChanged().text()).toContain(i18n.noFilesFound);
});
});
@@ -108,7 +106,7 @@ describe('Diff Stats Dropdown', () => {
});
it(`dropdown header should be '${expectedDropdownHeader}'`, () => {
- expect(findChanged().props('text')).toBe(expectedDropdownHeader);
+ expect(findChanged().props('toggleText')).toBe(expectedDropdownHeader);
});
it(`added and deleted count in collapsed section should be '${expectedAddedDeletedCollapsed}'`, () => {
@@ -137,27 +135,27 @@ describe('Diff Stats Dropdown', () => {
});
});
- describe('selecting file dropdown item', () => {
+ describe('on dropdown open', () => {
beforeEach(() => {
- createComponent({ files: mockFiles });
+ createComponent();
});
- it('updates the URL', () => {
- findChangedFiles().at(0).vm.$emit('click');
- expect(window.location.hash).toBe(mockFiles[0].href);
- findChangedFiles().at(1).vm.$emit('click');
- expect(window.location.hash).toBe(mockFiles[1].href);
+ it('should set the search input focus', () => {
+ findChanged().vm.$emit('shown');
+ expect(focusInputMock).toHaveBeenCalled();
});
});
- describe('on dropdown open', () => {
+ describe('keyboard nav', () => {
beforeEach(() => {
- createComponent();
+ createComponent({ files: mockFiles });
});
- it('should set the search input focus', () => {
- findChanged().vm.$emit('shown');
- expect(focusInputMock).toHaveBeenCalled();
+ it('focuses the first item when pressing the down key within the search box', () => {
+ const spy = jest.spyOn(wrapper.vm, 'focusFirstItem');
+ findSearchBox().vm.$emit('keydown', new KeyboardEvent({ key: ARROW_DOWN_KEY }));
+
+ expect(spy).toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/vue_shared/components/list_selector/index_spec.js b/spec/frontend/vue_shared/components/list_selector/index_spec.js
index 4222a28afe8..11e64a91eb0 100644
--- a/spec/frontend/vue_shared/components/list_selector/index_spec.js
+++ b/spec/frontend/vue_shared/components/list_selector/index_spec.js
@@ -1,16 +1,18 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { GlCard, GlIcon, GlCollapsibleListbox, GlSearchBoxByType } from '@gitlab/ui';
+import Api from '~/api';
+import { createAlert } from '~/alert';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import ListSelector from '~/vue_shared/components/list_selector/index.vue';
import UserItem from '~/vue_shared/components/list_selector/user_item.vue';
import GroupItem from '~/vue_shared/components/list_selector/group_item.vue';
-import usersAutocompleteQuery from '~/graphql_shared/queries/users_autocomplete.query.graphql';
import groupsAutocompleteQuery from '~/graphql_shared/queries/groups_autocomplete.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { USERS_RESPONSE_MOCK, GROUPS_RESPONSE_MOCK } from './mock_data';
+jest.mock('~/alert');
Vue.use(VueApollo);
describe('List Selector spec', () => {
@@ -20,6 +22,7 @@ describe('List Selector spec', () => {
const USERS_MOCK_PROPS = {
title: 'Users',
projectPath: 'some/project/path',
+ groupPath: 'some/group/path',
type: 'users',
};
@@ -29,15 +32,10 @@ describe('List Selector spec', () => {
type: 'groups',
};
- const usersAutocompleteQuerySuccess = jest.fn().mockResolvedValue(USERS_RESPONSE_MOCK);
const groupsAutocompleteQuerySuccess = jest.fn().mockResolvedValue(GROUPS_RESPONSE_MOCK);
- const createComponent = async (
- props,
- query = usersAutocompleteQuery,
- queryResponse = usersAutocompleteQuerySuccess,
- ) => {
- fakeApollo = createMockApollo([[query, queryResponse]]);
+ const createComponent = async (props) => {
+ fakeApollo = createMockApollo([[groupsAutocompleteQuery, groupsAutocompleteQuerySuccess]]);
wrapper = mountExtended(ListSelector, {
apolloProvider: fakeApollo,
@@ -52,12 +50,21 @@ describe('List Selector spec', () => {
const findCard = () => wrapper.findComponent(GlCard);
const findTitle = () => findCard().find('[data-testid="list-selector-title"]');
const findIcon = () => wrapper.findComponent(GlIcon);
- const findListBox = () => wrapper.findComponent(GlCollapsibleListbox);
+ const findAllListBoxComponents = () => wrapper.findAllComponents(GlCollapsibleListbox);
+ const findSearchResultsDropdown = () => findAllListBoxComponents().at(0);
+ const findNamespaceDropdown = () => findAllListBoxComponents().at(1);
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
const findAllUserComponents = () => wrapper.findAllComponents(UserItem);
const findAllGroupComponents = () => wrapper.findAllComponents(GroupItem);
+ beforeEach(() => {
+ jest.spyOn(Api, 'projectUsers').mockResolvedValue(USERS_RESPONSE_MOCK);
+ jest.spyOn(Api, 'groupMembers').mockResolvedValue({ data: USERS_RESPONSE_MOCK });
+ });
+
describe('Users type', () => {
+ const search = 'foo';
+
beforeEach(() => createComponent(USERS_MOCK_PROPS));
it('renders a Card component', () => {
@@ -77,47 +84,67 @@ describe('List Selector spec', () => {
expect(findSearchBox().exists()).toBe(true);
});
+ it('renders two namespace dropdown items', () => {
+ expect(findNamespaceDropdown().props('items').length).toBe(2);
+ });
+
it('does not call query when search box has not received an input', () => {
- expect(usersAutocompleteQuerySuccess).not.toHaveBeenCalled();
+ expect(Api.projectUsers).not.toHaveBeenCalled();
+ expect(Api.groupMembers).not.toHaveBeenCalled();
expect(findAllUserComponents().length).toBe(0);
});
- describe('searching', () => {
- const searchResponse = USERS_RESPONSE_MOCK.data.project.autocompleteUsers;
- const search = 'foo';
+ describe.each`
+ dropdownItemValue | apiMethod | apiParams | searchResponse
+ ${'false'} | ${'groupMembers'} | ${[USERS_MOCK_PROPS.groupPath, { query: search }]} | ${USERS_RESPONSE_MOCK}
+ ${'true'} | ${'projectUsers'} | ${[USERS_MOCK_PROPS.projectPath, search]} | ${USERS_RESPONSE_MOCK}
+ `(
+ 'searching based on namespace dropdown selection',
+ ({ dropdownItemValue, apiMethod, apiParams, searchResponse }) => {
+ const emitSearchInput = async () => {
+ findSearchBox().vm.$emit('input', search);
+ await waitForPromises();
+ };
+
+ beforeEach(async () => {
+ findNamespaceDropdown().vm.$emit('select', dropdownItemValue);
+ await emitSearchInput();
+ });
- const emitSearchInput = async () => {
- findSearchBox().vm.$emit('input', search);
- await waitForPromises();
- };
+ it('shows error alert when API fails', async () => {
+ jest.spyOn(Api, apiMethod).mockRejectedValueOnce();
+ await emitSearchInput();
- beforeEach(() => emitSearchInput());
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while fetching. Please try again.',
+ });
+ });
- it('calls query with correct variables when Search box receives an input', () => {
- expect(usersAutocompleteQuerySuccess).toHaveBeenCalledWith({
- fullPath: USERS_MOCK_PROPS.projectPath,
- isProject: true,
- search,
+ it('calls query with correct variables when Search box receives an input', () => {
+ expect(Api[apiMethod]).toHaveBeenCalledWith(...apiParams);
});
- });
- it('renders a List box component with the correct props', () => {
- expect(findListBox().props()).toMatchObject({ multiple: true, items: searchResponse });
- });
+ it('renders a List box component with the correct props', () => {
+ expect(findSearchResultsDropdown().props()).toMatchObject({
+ multiple: true,
+ items: searchResponse,
+ });
+ });
- it('renders a user component for each search result', () => {
- expect(findAllUserComponents().length).toBe(searchResponse.length);
- });
+ it('renders a user component for each search result', () => {
+ expect(findAllUserComponents().length).toBe(searchResponse.length);
+ });
- it('emits an event when a search result is selected', () => {
- const firstSearchResult = searchResponse[0];
- findAllUserComponents().at(0).vm.$emit('select', firstSearchResult.username);
+ it('emits an event when a search result is selected', () => {
+ const firstSearchResult = searchResponse[0];
+ findAllUserComponents().at(0).vm.$emit('select', firstSearchResult.username);
- expect(wrapper.emitted('select')).toEqual([
- [{ ...firstSearchResult, text: 'Administrator', value: 'root' }],
- ]);
- });
- });
+ expect(wrapper.emitted('select')).toEqual([
+ [{ ...firstSearchResult, text: 'Administrator', value: 'root' }],
+ ]);
+ });
+ },
+ );
describe('selected items', () => {
const selectedUser = { username: 'root' };
@@ -147,9 +174,7 @@ describe('List Selector spec', () => {
});
describe('Groups type', () => {
- beforeEach(() =>
- createComponent(GROUPS_MOCK_PROPS, groupsAutocompleteQuery, groupsAutocompleteQuerySuccess),
- );
+ beforeEach(() => createComponent(GROUPS_MOCK_PROPS));
it('renders a correct title', () => {
expect(findTitle().exists()).toBe(true);
@@ -182,8 +207,11 @@ describe('List Selector spec', () => {
});
});
- it('renders a List box component with the correct props', () => {
- expect(findListBox().props()).toMatchObject({ multiple: true, items: searchResponse });
+ it('renders a dropdown for the search results', () => {
+ expect(findSearchResultsDropdown().props()).toMatchObject({
+ multiple: true,
+ items: searchResponse,
+ });
});
it('renders a group component for each search result', () => {
diff --git a/spec/frontend/vue_shared/components/list_selector/mock_data.js b/spec/frontend/vue_shared/components/list_selector/mock_data.js
index 25ecac9632b..5b44a0c2a83 100644
--- a/spec/frontend/vue_shared/components/list_selector/mock_data.js
+++ b/spec/frontend/vue_shared/components/list_selector/mock_data.js
@@ -1,28 +1,20 @@
-export const USERS_RESPONSE_MOCK = {
- data: {
- project: {
- id: 'gid://gitlab/Project/20',
- autocompleteUsers: [
- {
- id: 'gid://gitlab/User/1',
- avatarUrl: '/uploads/-/system/user/avatar/1/avatar.png',
- name: 'Administrator',
- username: 'root',
- __typename: 'AutocompletedUser',
- },
- {
- id: 'gid://gitlab/User/15',
- avatarUrl:
- 'https://www.gravatar.com/avatar/c4ab964b90c3049c47882b319d3c5cc0?s=80\u0026d=identicon',
- name: 'Corrine Rath',
- username: 'laronda.graham',
- __typename: 'AutocompletedUser',
- },
- ],
- __typename: 'Project',
- },
+export const USERS_RESPONSE_MOCK = [
+ {
+ id: 'gid://gitlab/User/1',
+ avatarUrl: '/uploads/-/system/user/avatar/1/avatar.png',
+ name: 'Administrator',
+ username: 'root',
+ __typename: 'AutocompletedUser',
},
-};
+ {
+ id: 'gid://gitlab/User/15',
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/c4ab964b90c3049c47882b319d3c5cc0?s=80\u0026d=identicon',
+ name: 'Corrine Rath',
+ username: 'laronda.graham',
+ __typename: 'AutocompletedUser',
+ },
+];
export const GROUPS_RESPONSE_MOCK = {
data: {