Commit 27d240d8 authored by Phil Hughes's avatar Phil Hughes

Merge branch '27258-board-spec-to-jest-and-vtu' into 'master'

Refactor leftover boards test to Jest

See merge request gitlab-org/gitlab!28317
parents 3785ca00 7e2bd5ec
import Sortablejs from 'sortablejs';
export default Sortablejs;
export const Sortable = Sortablejs;
export class MultiDrag {}
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
/* global ListAssignee */ /* global ListAssignee */
/* global ListLabel */ /* global ListLabel */
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import waitForPromises from 'helpers/wait_for_promises';
import eventHub from '~/boards/eventhub'; import eventHub from '~/boards/eventhub';
import '~/boards/models/label'; import '~/boards/models/label';
...@@ -13,22 +15,41 @@ import '~/boards/models/list'; ...@@ -13,22 +15,41 @@ import '~/boards/models/list';
import store from '~/boards/stores'; import store from '~/boards/stores';
import boardsStore from '~/boards/stores/boards_store'; import boardsStore from '~/boards/stores/boards_store';
import boardCard from '~/boards/components/board_card.vue'; import boardCard from '~/boards/components/board_card.vue';
import issueCardInner from '~/boards/components/issue_card_inner.vue';
import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import { listObj, boardsMockInterceptor, setMockEndpoints } from './mock_data'; import { listObj, boardsMockInterceptor, setMockEndpoints } from './mock_data';
describe('Board card', () => { describe('Board card', () => {
let vm; let wrapper;
let mock; let mock;
let list;
const findIssueCardInner = () => wrapper.find(issueCardInner);
const findUserAvatarLink = () => wrapper.find(userAvatarLink);
// this particular mount component needs to be used after the root beforeEach because it depends on list being initialized
const mountComponent = propsData => {
wrapper = shallowMount(boardCard, {
stubs: {
issueCardInner,
},
store,
propsData: {
list,
issue: list.issues[0],
issueLinkBase: '/',
disabled: false,
index: 0,
rootPath: '/',
...propsData,
},
});
};
beforeEach(done => { const setupData = () => {
mock = new MockAdapter(axios); list = new List(listObj);
mock.onAny().reply(boardsMockInterceptor);
setMockEndpoints();
boardsStore.create(); boardsStore.create();
boardsStore.detail.issue = {}; boardsStore.detail.issue = {};
const BoardCardComp = Vue.extend(boardCard);
const list = new List(listObj);
const label1 = new ListLabel({ const label1 = new ListLabel({
id: 3, id: 3,
title: 'testing 123', title: 'testing 123',
...@@ -36,178 +57,155 @@ describe('Board card', () => { ...@@ -36,178 +57,155 @@ describe('Board card', () => {
text_color: 'white', text_color: 'white',
description: 'test', description: 'test',
}); });
return waitForPromises().then(() => {
setTimeout(() => {
list.issues[0].labels.push(label1); list.issues[0].labels.push(label1);
});
};
vm = new BoardCardComp({ beforeEach(() => {
store, mock = new MockAdapter(axios);
propsData: { mock.onAny().reply(boardsMockInterceptor);
list, setMockEndpoints();
issue: list.issues[0], return setupData();
issueLinkBase: '/',
disabled: false,
index: 0,
rootPath: '/',
},
}).$mount();
done();
}, 0);
}); });
afterEach(() => { afterEach(() => {
wrapper.destroy();
wrapper = null;
list = null;
mock.restore(); mock.restore();
}); });
it('returns false when detailIssue is empty', () => { it('when details issue is empty does not show the element', () => {
expect(vm.issueDetailVisible).toBe(false); mountComponent();
expect(wrapper.classes()).not.toContain('is-active');
}); });
it('returns true when detailIssue is equal to card issue', () => { it('when detailIssue is equal to card issue shows the element', () => {
boardsStore.detail.issue = vm.issue; [boardsStore.detail.issue] = list.issues;
mountComponent();
expect(vm.issueDetailVisible).toBe(true); expect(wrapper.classes()).toContain('is-active');
}); });
it("returns false when multiSelect doesn't contain issue", () => { it('when multiSelect does not contain issue removes multi select class', () => {
expect(vm.multiSelectVisible).toBe(false); mountComponent();
expect(wrapper.classes()).not.toContain('multi-select');
}); });
it('returns true when multiSelect contains issue', () => { it('when multiSelect contain issue add multi select class', () => {
boardsStore.multiSelect.list = [vm.issue]; boardsStore.multiSelect.list = [list.issues[0]];
mountComponent();
expect(vm.multiSelectVisible).toBe(true); expect(wrapper.classes()).toContain('multi-select');
}); });
it('adds user-can-drag class if not disabled', () => { it('adds user-can-drag class if not disabled', () => {
expect(vm.$el.classList.contains('user-can-drag')).toBe(true); mountComponent();
expect(wrapper.classes()).toContain('user-can-drag');
}); });
it('does not add user-can-drag class disabled', done => { it('does not add user-can-drag class disabled', () => {
vm.disabled = true; mountComponent({ disabled: true });
setTimeout(() => { expect(wrapper.classes()).not.toContain('user-can-drag');
expect(vm.$el.classList.contains('user-can-drag')).toBe(false);
done();
}, 0);
}); });
it('does not add disabled class', () => { it('does not add disabled class', () => {
expect(vm.$el.classList.contains('is-disabled')).toBe(false); mountComponent();
expect(wrapper.classes()).not.toContain('is-disabled');
}); });
it('adds disabled class is disabled is true', done => { it('adds disabled class is disabled is true', () => {
vm.disabled = true; mountComponent({ disabled: true });
setTimeout(() => { expect(wrapper.classes()).toContain('is-disabled');
expect(vm.$el.classList.contains('is-disabled')).toBe(true);
done();
}, 0);
}); });
describe('mouse events', () => { describe('mouse events', () => {
const triggerEvent = (eventName, el = vm.$el) => {
const event = document.createEvent('MouseEvents');
event.initMouseEvent(
eventName,
true,
true,
window,
1,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null,
);
el.dispatchEvent(event);
};
it('sets showDetail to true on mousedown', () => { it('sets showDetail to true on mousedown', () => {
triggerEvent('mousedown'); mountComponent();
wrapper.trigger('mousedown');
expect(vm.showDetail).toBe(true); return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.showDetail).toBe(true);
});
}); });
it('sets showDetail to false on mousemove', () => { it('sets showDetail to false on mousemove', () => {
triggerEvent('mousedown'); mountComponent();
wrapper.trigger('mousedown');
expect(vm.showDetail).toBe(true); return wrapper.vm
.$nextTick()
triggerEvent('mousemove'); .then(() => {
expect(wrapper.vm.showDetail).toBe(true);
expect(vm.showDetail).toBe(false); wrapper.trigger('mousemove');
return wrapper.vm.$nextTick();
})
.then(() => {
expect(wrapper.vm.showDetail).toBe(false);
});
}); });
it('does not set detail issue if showDetail is false', () => { it('does not set detail issue if showDetail is false', () => {
mountComponent();
expect(boardsStore.detail.issue).toEqual({}); expect(boardsStore.detail.issue).toEqual({});
}); });
it('does not set detail issue if link is clicked', () => { it('does not set detail issue if link is clicked', () => {
triggerEvent('mouseup', vm.$el.querySelector('a')); mountComponent();
findIssueCardInner()
.find('a')
.trigger('mouseup');
expect(boardsStore.detail.issue).toEqual({}); expect(boardsStore.detail.issue).toEqual({});
}); });
it('does not set detail issue if img is clicked', done => { it('does not set detail issue if img is clicked', () => {
vm.issue.assignees = [ mountComponent({
new ListAssignee({ issue: {
id: 1, ...list.issues[0],
name: 'testing 123', assignees: [
username: 'test', new ListAssignee({
avatar: 'test_image', id: 1,
}), name: 'testing 123',
]; username: 'test',
avatar: 'test_image',
Vue.nextTick(() => { }),
triggerEvent('mouseup', vm.$el.querySelector('img')); ],
},
});
expect(boardsStore.detail.issue).toEqual({}); findUserAvatarLink().trigger('mouseup');
done(); expect(boardsStore.detail.issue).toEqual({});
});
}); });
it('does not set detail issue if showDetail is false after mouseup', () => { it('does not set detail issue if showDetail is false after mouseup', () => {
triggerEvent('mouseup'); mountComponent();
wrapper.trigger('mouseup');
expect(boardsStore.detail.issue).toEqual({}); expect(boardsStore.detail.issue).toEqual({});
}); });
it('sets detail issue to card issue on mouse up', () => { it('sets detail issue to card issue on mouse up', () => {
spyOn(eventHub, '$emit'); jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
triggerEvent('mousedown');
triggerEvent('mouseup');
expect(eventHub.$emit).toHaveBeenCalledWith('newDetailIssue', vm.issue, undefined); mountComponent();
expect(boardsStore.detail.list).toEqual(vm.list);
});
it('adds active class if detail issue is set', done => { wrapper.trigger('mousedown');
vm.detailIssue.issue = vm.issue; wrapper.trigger('mouseup');
Vue.nextTick() expect(eventHub.$emit).toHaveBeenCalledWith('newDetailIssue', wrapper.vm.issue, undefined);
.then(() => { expect(boardsStore.detail.list).toEqual(wrapper.vm.list);
expect(vm.$el.classList.contains('is-active')).toBe(true);
})
.then(done)
.catch(done.fail);
}); });
it('resets detail issue to empty if already set', () => { it('resets detail issue to empty if already set', () => {
spyOn(eventHub, '$emit'); jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
[boardsStore.detail.issue] = list.issues;
boardsStore.detail.issue = vm.issue; mountComponent();
triggerEvent('mousedown'); wrapper.trigger('mousedown');
triggerEvent('mouseup'); wrapper.trigger('mouseup');
expect(eventHub.$emit).toHaveBeenCalledWith('clearDetailIssue', undefined); expect(eventHub.$emit).toHaveBeenCalledWith('clearDetailIssue', undefined);
}); });
......
...@@ -9,7 +9,9 @@ import '~/boards/models/label'; ...@@ -9,7 +9,9 @@ import '~/boards/models/label';
import '~/boards/models/assignee'; import '~/boards/models/assignee';
import '~/boards/models/issue'; import '~/boards/models/issue';
import '~/boards/models/list'; import '~/boards/models/list';
import { ListType } from '~/boards/constants';
import boardsStore from '~/boards/stores/boards_store'; import boardsStore from '~/boards/stores/boards_store';
import waitForPromises from 'helpers/wait_for_promises';
import { listObj, listObjDuplicate, boardsMockInterceptor } from './mock_data'; import { listObj, listObjDuplicate, boardsMockInterceptor } from './mock_data';
describe('List model', () => { describe('List model', () => {
...@@ -20,22 +22,35 @@ describe('List model', () => { ...@@ -20,22 +22,35 @@ describe('List model', () => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
mock.onAny().reply(boardsMockInterceptor); mock.onAny().reply(boardsMockInterceptor);
boardsStore.create(); boardsStore.create();
boardsStore.setEndpoints({
listsEndpoint: '/test/-/boards/1/lists',
});
list = new List(listObj); list = new List(listObj);
return waitForPromises();
}); });
afterEach(() => { afterEach(() => {
mock.restore(); mock.restore();
}); });
it('gets issues when created', done => { describe('list type', () => {
setTimeout(() => { const notExpandableList = ['blank'];
expect(list.issues.length).toBe(1);
done(); const table = Object.keys(ListType).map(k => {
}, 0); const value = ListType[k];
return [value, !notExpandableList.includes(value)];
});
it.each(table)(`when list_type is %s boards isExpandable is %p`, (type, result) => {
expect(new List({ id: 1, list_type: type }).isExpandable).toBe(result);
});
}); });
it('saves list and returns ID', done => { it('gets issues when created', () => {
expect(list.issues.length).toBe(1);
});
it('saves list and returns ID', () => {
list = new List({ list = new List({
title: 'test', title: 'test',
label: { label: {
...@@ -45,50 +60,40 @@ describe('List model', () => { ...@@ -45,50 +60,40 @@ describe('List model', () => {
text_color: 'white', text_color: 'white',
}, },
}); });
list.save(); return list.save().then(() => {
setTimeout(() => {
expect(list.id).toBe(listObj.id); expect(list.id).toBe(listObj.id);
expect(list.type).toBe('label'); expect(list.type).toBe('label');
expect(list.position).toBe(0); expect(list.position).toBe(0);
expect(list.label.color).toBe('red'); expect(list.label.color).toBe('red');
expect(list.label.textColor).toBe('white'); expect(list.label.textColor).toBe('white');
done(); });
}, 0);
}); });
it('destroys the list', done => { it('destroys the list', () => {
boardsStore.addList(listObj); boardsStore.addList(listObj);
list = boardsStore.findList('id', listObj.id); list = boardsStore.findList('id', listObj.id);
expect(boardsStore.state.lists.length).toBe(1); expect(boardsStore.state.lists.length).toBe(1);
list.destroy(); list.destroy();
setTimeout(() => { return waitForPromises().then(() => {
expect(boardsStore.state.lists.length).toBe(0); expect(boardsStore.state.lists.length).toBe(0);
done(); });
}, 0);
}); });
it('gets issue from list', done => { it('gets issue from list', () => {
setTimeout(() => { const issue = list.findIssue(1);
const issue = list.findIssue(1);
expect(issue).toBeDefined(); expect(issue).toBeDefined();
done();
}, 0);
}); });
it('removes issue', done => { it('removes issue', () => {
setTimeout(() => { const issue = list.findIssue(1);
const issue = list.findIssue(1);
expect(list.issues.length).toBe(1); expect(list.issues.length).toBe(1);
list.removeIssue(issue); list.removeIssue(issue);
expect(list.issues.length).toBe(0); expect(list.issues.length).toBe(0);
done();
}, 0);
}); });
it('sends service request to update issue label', () => { it('sends service request to update issue label', () => {
...@@ -105,7 +110,7 @@ describe('List model', () => { ...@@ -105,7 +110,7 @@ describe('List model', () => {
list.issues.push(issue); list.issues.push(issue);
listDup.issues.push(issue); listDup.issues.push(issue);
spyOn(boardsStore, 'moveIssue').and.callThrough(); jest.spyOn(boardsStore, 'moveIssue');
listDup.updateIssueLabel(issue, list); listDup.updateIssueLabel(issue, list);
...@@ -120,7 +125,8 @@ describe('List model', () => { ...@@ -120,7 +125,8 @@ describe('List model', () => {
describe('page number', () => { describe('page number', () => {
beforeEach(() => { beforeEach(() => {
spyOn(list, 'getIssues'); jest.spyOn(list, 'getIssues').mockImplementation(() => {});
list.issues = [];
}); });
it('increase page number if current issue count is more than the page size', () => { it('increase page number if current issue count is more than the page size', () => {
...@@ -167,7 +173,7 @@ describe('List model', () => { ...@@ -167,7 +173,7 @@ describe('List model', () => {
describe('newIssue', () => { describe('newIssue', () => {
beforeEach(() => { beforeEach(() => {
spyOn(boardsStore, 'newIssue').and.returnValue( jest.spyOn(boardsStore, 'newIssue').mockReturnValue(
Promise.resolve({ Promise.resolve({
data: { data: {
id: 42, id: 42,
...@@ -178,6 +184,7 @@ describe('List model', () => { ...@@ -178,6 +184,7 @@ describe('List model', () => {
}, },
}), }),
); );
list.issues = [];
}); });
it('adds new issue to top of list', done => { it('adds new issue to top of list', done => {
......
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