diff options
Diffstat (limited to 'spec/frontend/admin/topics/components/topic_select_spec.js')
-rw-r--r-- | spec/frontend/admin/topics/components/topic_select_spec.js | 122 |
1 files changed, 97 insertions, 25 deletions
diff --git a/spec/frontend/admin/topics/components/topic_select_spec.js b/spec/frontend/admin/topics/components/topic_select_spec.js index f61af6203f0..738cbd88c4c 100644 --- a/spec/frontend/admin/topics/components/topic_select_spec.js +++ b/spec/frontend/admin/topics/components/topic_select_spec.js @@ -1,39 +1,66 @@ -import { GlAvatarLabeled, GlDropdown, GlDropdownItem } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; +import { GlAvatarLabeled, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui'; +import { mount } from '@vue/test-utils'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; import TopicSelect from '~/admin/topics/components/topic_select.vue'; +import searchProjectTopics from '~/graphql_shared/queries/project_topics_search.query.graphql'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; const mockTopics = [ - { id: 1, name: 'topic1', title: 'Topic 1', avatarUrl: 'avatar.com/topic1.png' }, - { id: 2, name: 'GitLab', title: 'GitLab', avatarUrl: 'avatar.com/GitLab.png' }, + { + id: 'gid://gitlab/Projects::Topic/6', + name: 'topic1', + title: 'Topic 1', + avatarUrl: 'avatar.com/topic1.png', + __typename: 'Topic', + }, + { + id: 'gid://gitlab/Projects::Topic/5', + name: 'gitlab', + title: 'GitLab', + avatarUrl: 'avatar.com/GitLab.png', + __typename: 'Topic', + }, ]; +const mockTopicsQueryResponse = { + data: { + topics: { + nodes: mockTopics, + __typename: 'TopicConnection', + }, + }, +}; + describe('TopicSelect', () => { let wrapper; + const mockSearchTopicsSuccess = jest.fn().mockResolvedValue(mockTopicsQueryResponse); + + const findListbox = () => wrapper.findComponent(GlCollapsibleListbox); + const findAllListboxItems = () => wrapper.findAllComponents(GlListboxItem); - const findDropdown = () => wrapper.findComponent(GlDropdown); - const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); + function createMockApolloProvider({ mockSearchTopicsQuery = mockSearchTopicsSuccess } = {}) { + Vue.use(VueApollo); + + return createMockApollo([[searchProjectTopics, mockSearchTopicsQuery]]); + } - function createComponent(props = {}) { - wrapper = shallowMount(TopicSelect, { + function createComponent({ props = {}, mockApollo } = {}) { + wrapper = mount(TopicSelect, { + apolloProvider: mockApollo || createMockApolloProvider(), propsData: props, data() { return { topics: mockTopics, - search: '', }; }, - mocks: { - $apollo: { - queries: { - topics: { loading: false }, - }, - }, - }, }); } afterEach(() => { wrapper.destroy(); + jest.clearAllMocks(); }); it('mounts', () => { @@ -57,17 +84,27 @@ describe('TopicSelect', () => { it('renders default text if no selected topic', () => { createComponent(); - expect(findDropdown().props('text')).toBe('Select a topic'); + expect(findListbox().props('toggleText')).toBe('Select a topic'); }); it('renders selected topic', () => { - createComponent({ selectedTopic: mockTopics[0] }); + const mockTopic = mockTopics[0]; - expect(findDropdown().props('text')).toBe('topic1'); + createComponent({ + props: { + selectedTopic: mockTopic, + }, + }); + + expect(findListbox().props('toggleText')).toBe(mockTopic.name); }); it('renders label', () => { - createComponent({ labelText: 'my label' }); + createComponent({ + props: { + labelText: 'my label', + }, + }); expect(wrapper.find('label').text()).toBe('my label'); }); @@ -75,17 +112,52 @@ describe('TopicSelect', () => { it('renders dropdown items', () => { createComponent(); - const dropdownItems = findAllDropdownItems(); + const listboxItems = findAllListboxItems(); + + expect(listboxItems.at(0).findComponent(GlAvatarLabeled).props('label')).toBe('Topic 1'); + expect(listboxItems.at(1).findComponent(GlAvatarLabeled).props('label')).toBe('GitLab'); + }); + + it('dropdown `toggledAriaLabelledBy` prop is not set if `labelText` prop is null', () => { + createComponent(); - expect(dropdownItems.at(0).findComponent(GlAvatarLabeled).props('label')).toBe('Topic 1'); - expect(dropdownItems.at(1).findComponent(GlAvatarLabeled).props('label')).toBe('GitLab'); + expect(findListbox().props('toggle-aria-labelled-by')).toBe(undefined); }); - it('emits `click` event when topic selected', () => { + it('emits `click` event when topic selected', async () => { createComponent(); - findAllDropdownItems().at(0).vm.$emit('click'); + await findAllListboxItems().at(0).trigger('click'); expect(wrapper.emitted('click')).toEqual([[mockTopics[0]]]); }); + + describe('when searching a topic', () => { + const searchTopic = (searchTerm) => findListbox().vm.$emit('search', searchTerm); + const mockSearchTerm = 'gitl'; + + it('toggles loading state', async () => { + createComponent(); + jest.runOnlyPendingTimers(); + + await searchTopic(mockSearchTerm); + + expect(findListbox().props('searching')).toBe(true); + + await waitForPromises(); + + expect(findListbox().props('searching')).toBe(false); + }); + + it('fetches topics matching search string', async () => { + createComponent(); + + await searchTopic(mockSearchTerm); + jest.runOnlyPendingTimers(); + + expect(mockSearchTopicsSuccess).toHaveBeenCalledWith({ + search: mockSearchTerm, + }); + }); + }); }); |