import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { shallowMount } from '@vue/test-utils'; import { GlNewDropdown, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui'; import MilestoneCombobox from '~/milestones/project_milestone_combobox.vue'; import { milestones as projectMilestones } from './mock_data'; const TEST_SEARCH_ENDPOINT = '/api/v4/projects/8/search'; const extraLinks = [ { text: 'Create new', url: 'http://127.0.0.1:3000/h5bp/html5-boilerplate/-/milestones/new' }, { text: 'Manage milestones', url: '/h5bp/html5-boilerplate/-/milestones' }, ]; const preselectedMilestones = []; const projectId = '8'; describe('Milestone selector', () => { let wrapper; let mock; const findNoResultsMessage = () => wrapper.find({ ref: 'noResults' }); const factory = (options = {}) => { wrapper = shallowMount(MilestoneCombobox, { ...options, }); }; beforeEach(() => { mock = new MockAdapter(axios); gon.api_version = 'v4'; mock.onGet('/api/v4/projects/8/milestones').reply(200, projectMilestones); factory({ propsData: { projectId, preselectedMilestones, extraLinks, }, }); }); afterEach(() => { mock.restore(); wrapper.destroy(); wrapper = null; }); it('renders the dropdown', () => { expect(wrapper.find(GlNewDropdown)).toExist(); }); it('renders additional links', () => { const links = wrapper.findAll('[href]'); links.wrappers.forEach((item, idx) => { expect(item.text()).toBe(extraLinks[idx].text); expect(item.attributes('href')).toBe(extraLinks[idx].url); }); }); describe('before results', () => { it('should show a loading icon', () => { const request = mock.onGet(TEST_SEARCH_ENDPOINT, { params: { search: 'TEST_SEARCH', scope: 'milestones' }, }); expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); return wrapper.vm.$nextTick().then(() => { request.reply(200, []); }); }); it('should not show any dropdown items', () => { expect(wrapper.findAll('[role="milestone option"]')).toHaveLength(0); }); it('should have "No milestone" as the button text', () => { expect(wrapper.find({ ref: 'buttonText' }).text()).toBe('No milestone'); }); }); describe('with empty results', () => { beforeEach(() => { mock .onGet(TEST_SEARCH_ENDPOINT, { params: { search: 'TEST_SEARCH', scope: 'milestones' } }) .reply(200, []); wrapper.find(GlSearchBoxByType).vm.$emit('input', 'TEST_SEARCH'); return axios.waitForAll(); }); it('should display that no matching items are found', () => { expect(findNoResultsMessage().exists()).toBe(true); }); }); describe('with results', () => { let items; beforeEach(() => { mock .onGet(TEST_SEARCH_ENDPOINT, { params: { search: 'v0.1', scope: 'milestones' } }) .reply(200, [ { id: 41, iid: 6, project_id: 8, title: 'v0.1', description: '', state: 'active', created_at: '2020-04-04T01:30:40.051Z', updated_at: '2020-04-04T01:30:40.051Z', due_date: null, start_date: null, web_url: 'http://127.0.0.1:3000/h5bp/html5-boilerplate/-/milestones/6', }, ]); wrapper.find(GlSearchBoxByType).vm.$emit('input', 'v0.1'); return axios.waitForAll().then(() => { items = wrapper.findAll('[role="milestone option"]'); }); }); it('should display one item per result', () => { expect(items).toHaveLength(1); }); it('should emit a change if an item is clicked', () => { items.at(0).vm.$emit('click'); expect(wrapper.emitted().change.length).toBe(1); expect(wrapper.emitted().change[0]).toEqual([[{ title: 'v0.1' }]]); }); it('should not have a selecton icon on any item', () => { items.wrappers.forEach(item => { expect(item.find('.selected-item').exists()).toBe(false); }); }); it('should have a selecton icon if an item is clicked', () => { items.at(0).vm.$emit('click'); expect(wrapper.find('.selected-item').exists()).toBe(true); }); it('should not display a message about no results', () => { expect(findNoResultsMessage().exists()).toBe(false); }); }); });