diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-02 21:12:04 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-02 21:12:04 +0300 |
commit | eed7260f13c0a3139876e3659603f3d803e8fcd7 (patch) | |
tree | f877bb301ff936d73516241ad608271bc5a624fd /spec/frontend/vue_shared/components | |
parent | ef211f6aff22891e232a700b61d2d3bf567ed6bf (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/entity_select/entity_select_spec.js | 4 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/list_selector/group_item_spec.js | 55 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/list_selector/index_spec.js | 123 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/list_selector/mock_data.js | 24 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/list_selector/user_item_spec.js (renamed from spec/frontend/vue_shared/components/list_selector/user_spec.js) | 6 |
5 files changed, 193 insertions, 19 deletions
diff --git a/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js b/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js index 72d9f699821..1376133ec37 100644 --- a/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js +++ b/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js @@ -71,7 +71,7 @@ describe('EntitySelect', () => { fetchItemsMock = jest.fn().mockImplementation(() => ({ items: [itemMock], totalPages: 1 })); }); - describe('GlCollapsableListbox props', () => { + describe('GlCollapsibleListbox props', () => { beforeEach(() => { createComponent(); }); @@ -81,7 +81,7 @@ describe('EntitySelect', () => { ${'block'} | ${block} ${'toggleClass'} | ${toggleClass} ${'headerText'} | ${headerText} - `('passes the $prop prop to GlCollapsableListbox', ({ prop, expectedValue }) => { + `('passes the $prop prop to GlCollapsibleListbox', ({ prop, expectedValue }) => { expect(findListbox().props(prop)).toBe(expectedValue); }); }); diff --git a/spec/frontend/vue_shared/components/list_selector/group_item_spec.js b/spec/frontend/vue_shared/components/list_selector/group_item_spec.js new file mode 100644 index 00000000000..b59e4c734c1 --- /dev/null +++ b/spec/frontend/vue_shared/components/list_selector/group_item_spec.js @@ -0,0 +1,55 @@ +import { GlAvatar } from '@gitlab/ui'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import GroupItem from '~/vue_shared/components/list_selector/group_item.vue'; + +describe('GroupItem spec', () => { + let wrapper; + + const MOCK_GROUP = { fullName: 'Group 1', name: 'group1', avatarUrl: 'some/avatar.jpg' }; + + const createComponent = (props) => { + wrapper = mountExtended(GroupItem, { + propsData: { + data: MOCK_GROUP, + ...props, + }, + }); + }; + + const findAvatar = () => wrapper.findComponent(GlAvatar); + const findDeleteButton = () => wrapper.findByRole('button', { fullName: 'Delete Group 1' }); + + beforeEach(() => createComponent()); + + it('renders an Avatar component', () => { + expect(findAvatar().props('size')).toBe(32); + expect(findAvatar().attributes()).toMatchObject({ + src: MOCK_GROUP.avatarUrl, + alt: MOCK_GROUP.fullName, + }); + }); + + it('renders a fullName and name', () => { + expect(wrapper.text()).toContain('Group 1'); + expect(wrapper.text()).toContain('@group1'); + }); + + it('does not render a delete button by default', () => { + expect(findDeleteButton().exists()).toBe(false); + }); + + describe('Delete button', () => { + beforeEach(() => createComponent({ canDelete: true })); + + it('renders a delete button', () => { + expect(findDeleteButton().exists()).toBe(true); + expect(findDeleteButton().props('icon')).toBe('remove'); + }); + + it('emits a delete event if the delete button is clicked', () => { + findDeleteButton().trigger('click'); + + expect(wrapper.emitted('delete')).toEqual([[MOCK_GROUP.name]]); + }); + }); +}); 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 96074519857..4222a28afe8 100644 --- a/spec/frontend/vue_shared/components/list_selector/index_spec.js +++ b/spec/frontend/vue_shared/components/list_selector/index_spec.js @@ -3,11 +3,13 @@ import VueApollo from 'vue-apollo'; import { GlCard, GlIcon, GlCollapsibleListbox, GlSearchBoxByType } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import ListSelector from '~/vue_shared/components/list_selector/index.vue'; -import User from '~/vue_shared/components/list_selector/user.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 } from './mock_data'; +import { USERS_RESPONSE_MOCK, GROUPS_RESPONSE_MOCK } from './mock_data'; Vue.use(VueApollo); @@ -15,21 +17,31 @@ describe('List Selector spec', () => { let wrapper; let fakeApollo; - const MOCK_PROPS = { + const USERS_MOCK_PROPS = { title: 'Users', projectPath: 'some/project/path', type: 'users', }; + const GROUPS_MOCK_PROPS = { + title: 'Groups', + projectPath: 'some/project/path', + type: 'groups', + }; + const usersAutocompleteQuerySuccess = jest.fn().mockResolvedValue(USERS_RESPONSE_MOCK); + const groupsAutocompleteQuerySuccess = jest.fn().mockResolvedValue(GROUPS_RESPONSE_MOCK); - const createComponent = async (props) => { - fakeApollo = createMockApollo([[usersAutocompleteQuery, usersAutocompleteQuerySuccess]]); + const createComponent = async ( + props, + query = usersAutocompleteQuery, + queryResponse = usersAutocompleteQuerySuccess, + ) => { + fakeApollo = createMockApollo([[query, queryResponse]]); wrapper = mountExtended(ListSelector, { apolloProvider: fakeApollo, propsData: { - ...MOCK_PROPS, ...props, }, }); @@ -38,21 +50,23 @@ describe('List Selector spec', () => { }; const findCard = () => wrapper.findComponent(GlCard); - const findTitle = () => wrapper.findByText(MOCK_PROPS.title); + const findTitle = () => findCard().find('[data-testid="list-selector-title"]'); const findIcon = () => wrapper.findComponent(GlIcon); const findListBox = () => wrapper.findComponent(GlCollapsibleListbox); const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); - const findAllUserComponents = () => wrapper.findAllComponents(User); + const findAllUserComponents = () => wrapper.findAllComponents(UserItem); + const findAllGroupComponents = () => wrapper.findAllComponents(GroupItem); describe('Users type', () => { - beforeEach(() => createComponent({ type: 'users' })); + beforeEach(() => createComponent(USERS_MOCK_PROPS)); it('renders a Card component', () => { expect(findCard().exists()).toBe(true); }); - it('renders a title', () => { + it('renders a correct title', () => { expect(findTitle().exists()).toBe(true); + expect(findTitle().text()).toContain('Users'); }); it('renders the correct icon', () => { @@ -81,7 +95,7 @@ describe('List Selector spec', () => { it('calls query with correct variables when Search box receives an input', () => { expect(usersAutocompleteQuerySuccess).toHaveBeenCalledWith({ - fullPath: MOCK_PROPS.projectPath, + fullPath: USERS_MOCK_PROPS.projectPath, isProject: true, search, }); @@ -108,11 +122,11 @@ describe('List Selector spec', () => { describe('selected items', () => { const selectedUser = { username: 'root' }; const selectedItems = [selectedUser]; - beforeEach(() => createComponent({ selectedItems })); + beforeEach(() => createComponent({ ...USERS_MOCK_PROPS, selectedItems })); it('renders a heading with the total selected items', () => { - expect(findCard().text()).toContain('Users'); - expect(findCard().text()).toContain('1'); + expect(findTitle().text()).toContain('Users'); + expect(findTitle().text()).toContain('1'); }); it('renders a user component for each selected item', () => { @@ -131,4 +145,85 @@ describe('List Selector spec', () => { }); }); }); + + describe('Groups type', () => { + beforeEach(() => + createComponent(GROUPS_MOCK_PROPS, groupsAutocompleteQuery, groupsAutocompleteQuerySuccess), + ); + + it('renders a correct title', () => { + expect(findTitle().exists()).toBe(true); + expect(findTitle().text()).toContain('Groups'); + }); + + it('renders the correct icon', () => { + expect(findIcon().props('name')).toBe('group'); + }); + + it('does not call query when search box has not received an input', () => { + expect(groupsAutocompleteQuerySuccess).not.toHaveBeenCalled(); + expect(findAllGroupComponents().length).toBe(0); + }); + + describe('searching', () => { + const searchResponse = GROUPS_RESPONSE_MOCK.data.groups.nodes; + const search = 'foo'; + + const emitSearchInput = async () => { + findSearchBox().vm.$emit('input', search); + await waitForPromises(); + }; + + beforeEach(() => emitSearchInput()); + + it('calls query with correct variables when Search box receives an input', () => { + expect(groupsAutocompleteQuerySuccess).toHaveBeenCalledWith({ + search, + }); + }); + + it('renders a List box component with the correct props', () => { + expect(findListBox().props()).toMatchObject({ multiple: true, items: searchResponse }); + }); + + it('renders a group component for each search result', () => { + expect(findAllGroupComponents().length).toBe(searchResponse.length); + }); + + it('emits an event when a search result is selected', () => { + const firstSearchResult = searchResponse[0]; + findAllGroupComponents().at(0).vm.$emit('select', firstSearchResult.name); + + expect(wrapper.emitted('select')).toEqual([ + [{ ...firstSearchResult, text: 'Flightjs', value: 'Flightjs' }], + ]); + }); + }); + + describe('selected items', () => { + const selectedGroup = { name: 'Flightjs' }; + const selectedItems = [selectedGroup]; + beforeEach(() => createComponent({ ...GROUPS_MOCK_PROPS, selectedItems })); + + it('renders a heading with the total selected items', () => { + expect(findTitle().text()).toContain('Groups'); + expect(findTitle().text()).toContain('1'); + }); + + it('renders a group component for each selected item', () => { + expect(findAllGroupComponents().length).toBe(selectedItems.length); + expect(findAllGroupComponents().at(0).props()).toMatchObject({ + data: selectedGroup, + canDelete: true, + }); + }); + + it('emits a delete event when a delete event is emitted from the group component', () => { + const name = 'Flightjs'; + findAllGroupComponents().at(0).vm.$emit('delete', name); + + expect(wrapper.emitted('delete')).toEqual([[name]]); + }); + }); + }); }); 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 ce5d209a938..25ecac9632b 100644 --- a/spec/frontend/vue_shared/components/list_selector/mock_data.js +++ b/spec/frontend/vue_shared/components/list_selector/mock_data.js @@ -23,3 +23,27 @@ export const USERS_RESPONSE_MOCK = { }, }, }; + +export const GROUPS_RESPONSE_MOCK = { + data: { + groups: { + nodes: [ + { + id: 'gid://gitlab/Group/33', + name: 'Flightjs', + fullName: 'Flightjs', + avatarUrl: null, + __typename: 'Group', + }, + { + id: 'gid://gitlab/Group/34', + name: 'Flight 2', + fullName: 'Flight2', + avatarUrl: null, + __typename: 'Group', + }, + ], + __typename: 'GroupConnection', + }, + }, +}; diff --git a/spec/frontend/vue_shared/components/list_selector/user_spec.js b/spec/frontend/vue_shared/components/list_selector/user_item_spec.js index 5ce21f6672b..d84a29c67e0 100644 --- a/spec/frontend/vue_shared/components/list_selector/user_spec.js +++ b/spec/frontend/vue_shared/components/list_selector/user_item_spec.js @@ -1,14 +1,14 @@ import { GlAvatar } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; -import User from '~/vue_shared/components/list_selector/user.vue'; +import UserItem from '~/vue_shared/components/list_selector/user_item.vue'; -describe('User spec', () => { +describe('UserItem spec', () => { let wrapper; const MOCK_USER = { name: 'Admin', username: 'root', avatarUrl: 'some/avatar.jpg' }; const createComponent = (props) => { - wrapper = mountExtended(User, { + wrapper = mountExtended(UserItem, { propsData: { data: MOCK_USER, ...props, |