Commit b7fa9dc4 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '34723-update-board-tests-to-use-vue-test-utils' into 'master'

Update board tests to use vue-test-utils

See merge request gitlab-org/gitlab!24452
parents ee79fa62 e5bf1b99
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import AssigneesListItem from 'ee/boards/components/boards_list_selector/assignees_list_item.vue'; import AssigneesListItem from 'ee/boards/components/boards_list_selector/assignees_list_item.vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import { mockAssigneesList } from 'jest/boards/mock_data'; import { mockAssigneesList } from 'jest/boards/mock_data';
const createComponent = () => {
const Component = Vue.extend(AssigneesListItem);
return mountComponent(Component, {
item: mockAssigneesList[0],
});
};
describe('AssigneesListItem', () => { describe('AssigneesListItem', () => {
let vm; const assignee = mockAssigneesList[0];
let wrapper;
beforeEach(() => { beforeEach(() => {
vm = createComponent(); wrapper = shallowMount(AssigneesListItem, {
propsData: {
item: assignee,
},
});
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
describe('computed', () => { it('renders component container element with class `filter-dropdown-item`', () => {
describe('avatarAltText', () => { expect(wrapper.contains('.filter-dropdown-item')).toBe(true);
it('returns computed alt text based on assignee.name', () => {
expect(vm.avatarAltText).toBe(`${mockAssigneesList[0].name}'s avatar`);
});
});
}); });
describe('methods', () => { it('emits `onItemSelect` event on component click and sends `assignee` as event param', () => {
describe('handleItemClick', () => { wrapper.find('.filter-dropdown-item').trigger('click');
it('emits `onItemSelect` event on component and sends `assignee` as event param', () => {
jest.spyOn(vm, '$emit');
const assignee = mockAssigneesList[0];
vm.handleItemClick(); expect(wrapper.emitted().onItemSelect[0]).toEqual([assignee]);
});
expect(vm.$emit).toHaveBeenCalledWith('onItemSelect', assignee); describe('avatar', () => {
it('has alt text', () => {
expect(wrapper.find('.avatar').attributes('alt')).toBe(`${assignee.name}'s avatar`);
}); });
it('has src url', () => {
expect(wrapper.find('.avatar').attributes('src')).toBe(assignee.avatar_url);
}); });
}); });
describe('template', () => { describe('user details', () => {
it('renders component container element with class `filter-dropdown-item`', () => { it('shows assignee name', () => {
expect(vm.$el.classList.contains('filter-dropdown-item')).toBe(true); expect(wrapper.find('.dropdown-user-details').text()).toContain(assignee.name);
}); });
it('renders user item button element', () => { it('shows assignee username', () => {
const assignee = mockAssigneesList[0]; expect(wrapper.find('.dropdown-user-details .dropdown-light-content').text()).toContain(
const buttonEl = vm.$el.querySelector('.dropdown-user'); `@${assignee.username}`,
);
expect(buttonEl).not.toBeNull();
expect(
buttonEl.querySelector('.avatar-container.s32 img.avatar.s32').getAttribute('src'),
).toBe(assignee.avatar_url);
expect(buttonEl.querySelector('.dropdown-user-details').innerText).toContain(assignee.name);
expect(
buttonEl.querySelector('.dropdown-user-details .dropdown-light-content').innerText,
).toContain(`@${assignee.username}`);
}); });
}); });
}); });
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import ListContainer from 'ee/boards/components/boards_list_selector/list_container.vue'; import ListContainer from 'ee/boards/components/boards_list_selector/list_container.vue';
import mountComponent from 'helpers/vue_mount_component_helper'; import ListFilter from 'ee/boards/components/boards_list_selector/list_filter.vue';
import ListContent from 'ee/boards/components/boards_list_selector/list_content.vue';
import { mockAssigneesList } from 'jest/boards/mock_data'; import { mockAssigneesList } from 'jest/boards/mock_data';
const createComponent = () => { describe('ListContainer', () => {
const Component = Vue.extend(ListContainer); let wrapper;
return mountComponent(Component, { beforeEach(() => {
wrapper = shallowMount(ListContainer, {
propsData: {
loading: false, loading: false,
items: mockAssigneesList, items: mockAssigneesList,
listType: 'assignees', listType: 'assignees',
},
}); });
};
describe('ListContainer', () => {
let vm;
beforeEach(() => {
vm = createComponent();
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
describe('computed', () => { describe('computed', () => {
describe('filteredItems', () => { describe('filteredItems', () => {
it('returns assignees list as it is when `query` is empty', () => { it('returns assignees list as it is when `query` is empty', () => {
vm.query = ''; wrapper.setData({ query: '' });
expect(vm.filteredItems.length).toBe(mockAssigneesList.length); expect(wrapper.vm.filteredItems.length).toBe(mockAssigneesList.length);
}); });
it('returns filtered assignees list as it is when `query` has name', () => { it('returns filtered assignees list as it is when `query` has name', () => {
const assignee = mockAssigneesList[0]; const assignee = mockAssigneesList[0];
vm.query = assignee.name; wrapper.setData({ query: assignee.name });
expect(vm.filteredItems.length).toBe(1); expect(wrapper.vm.filteredItems.length).toBe(1);
expect(vm.filteredItems[0].name).toBe(assignee.name); expect(wrapper.vm.filteredItems[0].name).toBe(assignee.name);
}); });
it('returns filtered assignees list as it is when `query` has username', () => { it('returns filtered assignees list as it is when `query` has username', () => {
const assignee = mockAssigneesList[0]; const assignee = mockAssigneesList[0];
vm.query = assignee.username; wrapper.setData({ query: assignee.username });
expect(vm.filteredItems.length).toBe(1); expect(wrapper.vm.filteredItems.length).toBe(1);
expect(vm.filteredItems[0].username).toBe(assignee.username); expect(wrapper.vm.filteredItems[0].username).toBe(assignee.username);
}); });
}); });
}); });
...@@ -58,39 +54,39 @@ describe('ListContainer', () => { ...@@ -58,39 +54,39 @@ describe('ListContainer', () => {
describe('handleSearch', () => { describe('handleSearch', () => {
it('sets value of param `query` to component prop `query`', () => { it('sets value of param `query` to component prop `query`', () => {
const query = 'foobar'; const query = 'foobar';
vm.handleSearch(query); wrapper.vm.handleSearch(query);
expect(vm.query).toBe(query); expect(wrapper.vm.query).toBe(query);
}); });
}); });
describe('handleItemClick', () => { describe('handleItemClick', () => {
it('emits `onItemSelect` event on component and sends `assignee` as event param', () => { it('emits `onItemSelect` event on component and sends `assignee` as event param', () => {
jest.spyOn(vm, '$emit');
const assignee = mockAssigneesList[0]; const assignee = mockAssigneesList[0];
vm.handleItemClick(assignee); wrapper.vm.handleItemClick(assignee);
expect(vm.$emit).toHaveBeenCalledWith('onItemSelect', assignee); expect(wrapper.emitted().onItemSelect[0]).toEqual([assignee]);
}); });
}); });
}); });
describe('template', () => { describe('template', () => {
it('renders component container element with class `dropdown-assignees-list`', () => { it('renders component container element with class `dropdown-assignees-list`', () => {
expect(vm.$el.classList.contains('dropdown-assignees-list')).toBe(true); expect(wrapper.classes('dropdown-assignees-list')).toBe(true);
}); });
it('renders loading animation when prop `loading` is true', () => { it('renders loading animation when prop `loading` is true', () => {
vm.loading = true; wrapper.setProps({ loading: true });
return Vue.nextTick().then(() => { return Vue.nextTick().then(() => {
expect(vm.$el.querySelector('.dropdown-loading')).not.toBeNull(); expect(wrapper.find('.dropdown-loading').exists()).toBe(true);
}); });
}); });
it('renders dropdown body elements', () => { it('renders dropdown body elements', () => {
expect(vm.$el.querySelector('.dropdown-input')).not.toBeNull(); expect(wrapper.find(ListFilter).exists()).toBe(true);
expect(vm.$el.querySelector('.dropdown-content')).not.toBeNull(); expect(wrapper.find(ListContent).exists()).toBe(true);
}); });
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import ListContent from 'ee/boards/components/boards_list_selector/list_content.vue'; import ListContent from 'ee/boards/components/boards_list_selector/list_content.vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import { mockAssigneesList } from 'jest/boards/mock_data'; import { mockAssigneesList } from 'jest/boards/mock_data';
const createComponent = () => { describe('ListContent', () => {
const Component = Vue.extend(ListContent); let wrapper;
return mountComponent(Component, { beforeEach(() => {
wrapper = shallowMount(ListContent, {
propsData: {
items: mockAssigneesList, items: mockAssigneesList,
listType: 'assignees', listType: 'assignees',
},
}); });
};
describe('ListContent', () => {
let vm;
beforeEach(() => {
vm = createComponent();
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
describe('methods', () => {
describe('handleItemClick', () => {
it('emits `onItemSelect` event on component and sends `assignee` as event param', () => { it('emits `onItemSelect` event on component and sends `assignee` as event param', () => {
jest.spyOn(vm, '$emit');
const assignee = mockAssigneesList[0]; const assignee = mockAssigneesList[0];
vm.handleItemClick(assignee); wrapper.vm.handleItemClick(assignee);
expect(vm.$emit).toHaveBeenCalledWith('onItemSelect', assignee); expect(wrapper.emitted().onItemSelect[0]).toEqual([assignee]);
});
});
}); });
describe('template', () => {
it('renders component container element with class `dropdown-content`', () => { it('renders component container element with class `dropdown-content`', () => {
expect(vm.$el.classList.contains('dropdown-content')).toBe(true); expect(wrapper.classes('dropdown-content')).toBe(true);
}); });
it('renders UL parent element as child within container', () => { it('renders UL parent element as child within container', () => {
expect(vm.$el.querySelector('ul')).not.toBeNull(); expect(wrapper.find('ul').exists()).toBe(true);
});
}); });
}); });
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import ListFilter from 'ee/boards/components/boards_list_selector/list_filter.vue'; import ListFilter from 'ee/boards/components/boards_list_selector/list_filter.vue';
import mountComponent from 'helpers/vue_mount_component_helper';
const createComponent = () => {
const Component = Vue.extend(ListFilter);
return mountComponent(Component);
};
describe('ListFilter', () => { describe('ListFilter', () => {
let vm; let wrapper;
beforeEach(() => { beforeEach(() => {
vm = createComponent(); wrapper = shallowMount(ListFilter);
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
describe('methods', () => { describe('input field', () => {
describe('handleInputChange', () => { it('emits `onSearchInput` event on keyup and sends input text as event param', () => {
it('emits `onSearchInput` event on component and sends `query` as event param', () => { const input = wrapper.find('input');
jest.spyOn(vm, '$emit'); input.setValue('foobar');
const query = 'foobar'; input.trigger('keyup');
vm.query = query;
vm.handleInputChange(); expect(wrapper.emitted().onSearchInput[0]).toEqual(['foobar']);
expect(vm.$emit).toHaveBeenCalledWith('onSearchInput', query);
}); });
}); });
describe('handleInputClear', () => { describe('clear button', () => {
it('clears value of prop `query` and calls `handleInputChange` method on component', () => { let input;
jest.spyOn(vm, 'handleInputChange');
vm.query = 'foobar';
vm.handleInputClear(); beforeEach(() => {
// Pre-populate input field with text
input = wrapper.find('input');
input.setValue('foobar');
input.trigger('keyup');
});
expect(vm.query).toBe(''); it('clears input field and emits `onSearchInput` event with empty value', () => {
expect(vm.handleInputChange).toHaveBeenCalled(); expect(input.element.value).toBe('foobar');
wrapper.find('.dropdown-input-clear').trigger('click');
return Vue.nextTick().then(() => {
expect(input.element.value).toBe('');
expect(wrapper.emitted().onSearchInput[1]).toEqual(['']);
}); });
}); });
}); });
describe('template', () => { describe('template', () => {
it('renders component container element with class `dropdown-input`', () => { it('renders component container element with class `dropdown-input`', () => {
expect(vm.$el.classList.contains('dropdown-input')).toBe(true); expect(wrapper.classes('dropdown-input')).toBe(true);
}); });
it('renders class `has-value` on container element when prop `query` is not empty', () => { it('renders class `has-value` on container element when prop `query` is not empty', () => {
vm.query = 'foobar'; wrapper.setData({ query: 'foobar' });
return Vue.nextTick().then(() => { return Vue.nextTick().then(() => {
expect(vm.$el.classList.contains('has-value')).toBe(true); expect(wrapper.classes('has-value')).toBe(true);
}); });
}); });
it('removes class `has-value` from container element when prop `query` is empty', () => { it('removes class `has-value` from container element when prop `query` is empty', () => {
vm.query = ''; wrapper.setData({ query: '' });
return Vue.nextTick().then(() => { return Vue.nextTick().then(() => {
expect(vm.$el.classList.contains('has-value')).toBe(false); expect(wrapper.classes('has-value')).toBe(false);
}); });
}); });
it('renders search input element', () => { it('renders search input element', () => {
const inputEl = vm.$el.querySelector('input.dropdown-input-field'); const inputEl = wrapper.find('input.dropdown-input-field');
expect(inputEl).not.toBeNull(); expect(inputEl.exists()).toBe(true);
expect(inputEl.getAttribute('placeholder')).toBe('Search'); expect(inputEl.attributes('placeholder')).toBe('Search');
}); });
it('renders search input icons', () => { it('renders search input icons', () => {
expect(vm.$el.querySelector('i.fa.fa-search.dropdown-input-search')).not.toBeNull(); expect(wrapper.find('i.fa.fa-search.dropdown-input-search').exists()).toBe(true);
expect(vm.$el.querySelector('i.fa.fa-times.dropdown-input-clear')).not.toBeNull(); expect(wrapper.find('i.fa.fa-times.dropdown-input-clear').exists()).toBe(true);
}); });
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import IssueCardWeight from 'ee/boards/components/issue_card_weight.vue'; import IssueCardWeight from 'ee/boards/components/issue_card_weight.vue';
import mountComponent from 'helpers/vue_mount_component_helper';
describe('IssueCardWeight component', () => { function mountIssueCardWeight(propsData) {
let vm; return shallowMount(IssueCardWeight, {
let Component; propsData,
beforeAll(() => {
Component = Vue.extend(IssueCardWeight);
}); });
}
describe('IssueCardWeight', () => {
let wrapper;
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
});
describe('weight text', () => {
it('shows 0 when weight is 0', () => {
wrapper = mountIssueCardWeight({
weight: 0,
}); });
it('renders weight', () => { expect(wrapper.find('.board-card-info-text').text()).toContain(0);
vm = mountComponent(Component, { });
it('shows 5 when weight is 5', () => {
wrapper = mountIssueCardWeight({
weight: 5, weight: 5,
}); });
expect(vm.$el.querySelector('.board-card-info-text').innerText).toContain('5'); expect(wrapper.find('.board-card-info-text').text()).toContain('5');
});
}); });
it('renders a link when no tag is specified', () => { it('renders a link when no tag is specified', () => {
vm = mountComponent(Component, { wrapper = mountIssueCardWeight({
weight: 2, weight: 2,
}); });
expect(vm.$el.querySelector('a.board-card-info')).toBeDefined(); expect(wrapper.find('span.board-card-info').exists()).toBe(false);
expect(wrapper.find('a.board-card-info').exists()).toBe(true);
}); });
it('renders the tag when it is explicitly specified', () => { it('renders the tag when it is explicitly specified', () => {
vm = mountComponent(Component, { wrapper = mountIssueCardWeight({
weight: 2, weight: 2,
tagName: 'span', tagName: 'span',
}); });
expect(vm.$el.querySelector('span.board-card-info')).toBeDefined(); expect(wrapper.find('span.board-card-info').exists()).toBe(true);
expect(vm.$el.querySelector('a.board-card-info')).toBeNull(); expect(wrapper.find('a.board-card-info').exists()).toBe(false);
});
describe('with weight=0', () => {
beforeEach(() => {
vm = mountComponent(Component, {
weight: 0,
});
});
afterEach(() => {
vm.$destroy();
});
it('renders weight', () => {
expect(vm.$el.querySelector('.board-card-info-text')).toBeDefined();
expect(vm.$el.querySelector('.board-card-info-text').innerText).toContain(0);
});
}); });
}); });
import Vue from 'vue'; import { GlLink } from '@gitlab/ui';
import mountComponent from 'helpers/vue_mount_component_helper'; import { shallowMount } from '@vue/test-utils';
import IssueCardInnerScopedLabel from '~/boards/components/issue_card_inner_scoped_label.vue'; import IssueCardInnerScopedLabel from '~/boards/components/issue_card_inner_scoped_label.vue';
describe('IssueCardInnerScopedLabel Component', () => { describe('IssueCardInnerScopedLabel Component', () => {
let vm; let wrapper;
const Component = Vue.extend(IssueCardInnerScopedLabel);
const props = { beforeEach(() => {
wrapper = shallowMount(IssueCardInnerScopedLabel, {
propsData: {
label: { title: 'Foo::Bar', description: 'Some Random Description' }, label: { title: 'Foo::Bar', description: 'Some Random Description' },
labelStyle: { background: 'white', color: 'black' }, labelStyle: { background: 'white', color: 'black' },
scopedLabelsDocumentationLink: '/docs-link', scopedLabelsDocumentationLink: '/docs-link',
}; },
const createComponent = () => mountComponent(Component, { ...props }); });
beforeEach(() => {
vm = createComponent();
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
it('should render label title', () => { it('should render label title', () => {
expect(vm.$el.querySelector('.color-label').textContent.trim()).toEqual('Foo::Bar'); expect(wrapper.find('.color-label').text()).toBe('Foo::Bar');
}); });
it('should render question mark symbol', () => { it('should render question mark symbol', () => {
expect(vm.$el.querySelector('.fa-question-circle')).not.toBeNull(); expect(wrapper.find('.fa-question-circle').exists()).toBe(true);
}); });
it('should render label style provided', () => { it('should render label style provided', () => {
const node = vm.$el.querySelector('.color-label'); const label = wrapper.find('.color-label');
expect(node.style.background).toEqual(props.labelStyle.background); expect(label.attributes('style')).toContain('background: white;');
expect(node.style.color).toEqual(props.labelStyle.color); expect(label.attributes('style')).toContain('color: black;');
}); });
it('should render the docs link', () => { it('should render the docs link', () => {
expect(vm.$el.querySelector('a.scoped-label').href).toContain( expect(wrapper.find(GlLink).attributes('href')).toBe('/docs-link');
props.scopedLabelsDocumentationLink,
);
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import dateFormat from 'dateformat'; import dateFormat from 'dateformat';
import IssueDueDate from '~/boards/components/issue_due_date.vue'; import IssueDueDate from '~/boards/components/issue_due_date.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (dueDate = new Date(), closed = false) =>
shallowMount(IssueDueDate, {
propsData: {
closed,
date: dateFormat(dueDate, 'yyyy-mm-dd', true),
},
});
const findTime = wrapper => wrapper.find('time');
describe('Issue Due Date component', () => { describe('Issue Due Date component', () => {
let vm; let wrapper;
let date; let date;
const Component = Vue.extend(IssueDueDate);
const createComponent = (dueDate = new Date(), closed = false) =>
mountComponent(Component, { closed, date: dateFormat(dueDate, 'yyyy-mm-dd', true) });
beforeEach(() => { beforeEach(() => {
date = new Date(); date = new Date();
vm = createComponent();
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
it('should render "Today" if the due date is today', () => { it('should render "Today" if the due date is today', () => {
const timeContainer = vm.$el.querySelector('time'); wrapper = createComponent();
expect(timeContainer.textContent.trim()).toEqual('Today'); expect(findTime(wrapper).text()).toBe('Today');
}); });
it('should render "Yesterday" if the due date is yesterday', () => { it('should render "Yesterday" if the due date is yesterday', () => {
date.setDate(date.getDate() - 1); date.setDate(date.getDate() - 1);
vm = createComponent(date); wrapper = createComponent(date);
expect(vm.$el.querySelector('time').textContent.trim()).toEqual('Yesterday'); expect(findTime(wrapper).text()).toBe('Yesterday');
}); });
it('should render "Tomorrow" if the due date is one day from now', () => { it('should render "Tomorrow" if the due date is one day from now', () => {
date.setDate(date.getDate() + 1); date.setDate(date.getDate() + 1);
vm = createComponent(date); wrapper = createComponent(date);
expect(vm.$el.querySelector('time').textContent.trim()).toEqual('Tomorrow'); expect(findTime(wrapper).text()).toBe('Tomorrow');
}); });
it('should render day of the week if due date is one week away', () => { it('should render day of the week if due date is one week away', () => {
date.setDate(date.getDate() + 5); date.setDate(date.getDate() + 5);
vm = createComponent(date); wrapper = createComponent(date);
expect(vm.$el.querySelector('time').textContent.trim()).toEqual(dateFormat(date, 'dddd')); expect(findTime(wrapper).text()).toBe(dateFormat(date, 'dddd'));
}); });
it('should render month and day for other dates', () => { it('should render month and day for other dates', () => {
date.setDate(date.getDate() + 17); date.setDate(date.getDate() + 17);
vm = createComponent(date); wrapper = createComponent(date);
const today = new Date(); const today = new Date();
const isDueInCurrentYear = today.getFullYear() === date.getFullYear(); const isDueInCurrentYear = today.getFullYear() === date.getFullYear();
const format = isDueInCurrentYear ? 'mmm d' : 'mmm d, yyyy'; const format = isDueInCurrentYear ? 'mmm d' : 'mmm d, yyyy';
expect(vm.$el.querySelector('time').textContent.trim()).toEqual(dateFormat(date, format)); expect(findTime(wrapper).text()).toBe(dateFormat(date, format));
}); });
it('should contain the correct `.text-danger` css class for overdue issue that is open', () => { it('should contain the correct `.text-danger` css class for overdue issue that is open', () => {
date.setDate(date.getDate() - 17); date.setDate(date.getDate() - 17);
vm = createComponent(date); wrapper = createComponent(date);
expect(vm.$el.querySelector('time').classList.contains('text-danger')).toEqual(true); expect(findTime(wrapper).classes('text-danger')).toBe(true);
}); });
it('should not contain the `.text-danger` css class for overdue issue that is closed', () => { it('should not contain the `.text-danger` css class for overdue issue that is closed', () => {
date.setDate(date.getDate() - 17); date.setDate(date.getDate() - 17);
vm = createComponent(date, true); const closed = true;
wrapper = createComponent(date, closed);
expect(vm.$el.querySelector('time').classList.contains('text-danger')).toEqual(false); expect(findTime(wrapper).classes('text-danger')).toBe(false);
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment