gitlab-org--gitlab-foss/spec/frontend/milestones/project_milestone_combobox_spec.js

186 lines
5.2 KiB
JavaScript

import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { shallowMount } from '@vue/test-utils';
import { GlDropdown, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui';
import { ENTER_KEY } from '~/lib/utils/keys';
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 TEST_SEARCH = 'TEST_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 findSearchBox = () => wrapper.find(GlSearchBoxByType);
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(GlDropdown)).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, []);
findSearchBox().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',
},
]);
findSearchBox().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);
});
});
describe('when Enter is pressed', () => {
beforeEach(() => {
factory({
propsData: {
projectId,
preselectedMilestones,
extraLinks,
},
data() {
return {
searchQuery: 'TEST_SEARCH',
};
},
});
mock
.onGet(TEST_SEARCH_ENDPOINT, { params: { search: 'TEST_SEARCH', scope: 'milestones' } })
.reply(200, []);
});
it('should trigger a search', async () => {
mock.resetHistory();
findSearchBox().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY }));
await axios.waitForAll();
expect(mock.history.get.length).toBe(1);
expect(mock.history.get[0].url).toBe(TEST_SEARCH_ENDPOINT);
});
});
});