import { GlFilteredSearchSuggestion, GlLoadingIcon, GlToken } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import { nextTick } from 'vue'; import waitForPromises from 'helpers/wait_for_promises'; import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import TagToken, { TAG_SUGGESTIONS_PATH } from '~/runner/components/search_tokens/tag_token.vue'; import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import { getRecentlyUsedSuggestions } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils'; jest.mock('~/flash'); jest.mock('~/vue_shared/components/filtered_search_bar/filtered_search_utils', () => ({ ...jest.requireActual('~/vue_shared/components/filtered_search_bar/filtered_search_utils'), getRecentlyUsedSuggestions: jest.fn(), })); const mockStorageKey = 'stored-recent-tags'; const mockTags = [ { id: 1, name: 'linux' }, { id: 2, name: 'windows' }, { id: 3, name: 'mac' }, ]; const mockTagsFiltered = [mockTags[0]]; const mockSearchTerm = mockTags[0].name; const GlFilteredSearchTokenStub = { template: `
`, }; const mockTagTokenConfig = { icon: 'tag', title: 'Tags', type: 'tag', token: TagToken, recentSuggestionsStorageKey: mockStorageKey, operators: OPERATOR_IS_ONLY, }; describe('TagToken', () => { let mock; let wrapper; const createComponent = (props = {}) => { wrapper = mount(TagToken, { propsData: { config: mockTagTokenConfig, value: { data: '' }, active: false, ...props, }, provide: { portalName: 'fake target', alignSuggestions: function fakeAlignSuggestions() {}, filteredSearchSuggestionListInstance: { register: jest.fn(), unregister: jest.fn(), }, }, stubs: { GlFilteredSearchToken: GlFilteredSearchTokenStub, }, }); }; const findGlFilteredSearchSuggestions = () => wrapper.findAllComponents(GlFilteredSearchSuggestion); const findGlFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchTokenStub); const findToken = () => wrapper.findComponent(GlToken); const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); beforeEach(async () => { mock = new MockAdapter(axios); mock.onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } }).reply(200, mockTags); mock .onGet(TAG_SUGGESTIONS_PATH, { params: { search: mockSearchTerm } }) .reply(200, mockTagsFiltered); getRecentlyUsedSuggestions.mockReturnValue([]); createComponent(); await waitForPromises(); }); afterEach(() => { getRecentlyUsedSuggestions.mockReset(); wrapper.destroy(); }); describe('when the tags token is displayed', () => { it('requests tags suggestions', () => { expect(mock.history.get[0].params).toEqual({ search: '' }); }); it('displays tags suggestions', () => { mockTags.forEach(({ name }, i) => { expect(findGlFilteredSearchSuggestions().at(i).text()).toBe(name); }); }); }); describe('when suggestions are stored', () => { const storedSuggestions = [{ id: 4, value: 'docker', text: 'docker' }]; beforeEach(async () => { getRecentlyUsedSuggestions.mockReturnValue(storedSuggestions); createComponent(); await waitForPromises(); }); it('suggestions are loaded from a correct key', () => { expect(getRecentlyUsedSuggestions).toHaveBeenCalledWith(mockStorageKey); }); it('displays stored tags suggestions', () => { expect(findGlFilteredSearchSuggestions()).toHaveLength( mockTags.length + storedSuggestions.length, ); expect(findGlFilteredSearchSuggestions().at(0).text()).toBe(storedSuggestions[0].text); }); }); describe('when the users filters suggestions', () => { beforeEach(async () => { findGlFilteredSearchToken().vm.$emit('input', { data: mockSearchTerm }); jest.runAllTimers(); }); it('requests filtered tags suggestions', async () => { await waitForPromises(); expect(mock.history.get[1].params).toEqual({ search: mockSearchTerm }); }); it('shows the loading icon', async () => { await nextTick(); expect(findGlLoadingIcon().exists()).toBe(true); }); it('displays filtered tags suggestions', async () => { await waitForPromises(); expect(findGlFilteredSearchSuggestions()).toHaveLength(mockTagsFiltered.length); expect(findGlFilteredSearchSuggestions().at(0).text()).toBe(mockTagsFiltered[0].name); }); }); describe('when suggestions cannot be loaded', () => { beforeEach(async () => { mock.onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } }).reply(500); createComponent(); await waitForPromises(); }); it('error is shown', async () => { expect(createAlert).toHaveBeenCalledTimes(1); expect(createAlert).toHaveBeenCalledWith({ message: expect.any(String) }); }); }); describe('when the user selects a value', () => { beforeEach(async () => { createComponent({ value: { data: mockTags[0].name } }); findGlFilteredSearchToken().vm.$emit('select'); await waitForPromises(); }); it('selected tag is displayed', async () => { expect(findToken().exists()).toBe(true); }); }); });