Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-03-24 06:09:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-24 06:09:28 +0300
commitbe2f4c5788975597dd7be1c8a3525549770c1216 (patch)
tree083ed0d7e29e26d479c00e00d9cb89d74ebbb0ef /spec/frontend
parent2711c26beaca6c3a5a3be4b65e01557faf0185b6 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/boards/board_blank_state_spec.js95
-rw-r--r--spec/frontend/boards/board_new_issue_spec.js202
-rw-r--r--spec/frontend/boards/components/board_form_spec.js47
-rw-r--r--spec/frontend/boards/issue_spec.js197
-rw-r--r--spec/frontend/boards/mock_data.js53
5 files changed, 594 insertions, 0 deletions
diff --git a/spec/frontend/boards/board_blank_state_spec.js b/spec/frontend/boards/board_blank_state_spec.js
new file mode 100644
index 00000000000..3ffdda52f58
--- /dev/null
+++ b/spec/frontend/boards/board_blank_state_spec.js
@@ -0,0 +1,95 @@
+import Vue from 'vue';
+import boardsStore from '~/boards/stores/boards_store';
+import BoardBlankState from '~/boards/components/board_blank_state.vue';
+
+describe('Boards blank state', () => {
+ let vm;
+ let fail = false;
+
+ beforeEach(done => {
+ const Comp = Vue.extend(BoardBlankState);
+
+ boardsStore.create();
+
+ jest.spyOn(boardsStore, 'addList').mockImplementation();
+ jest.spyOn(boardsStore, 'removeList').mockImplementation();
+ jest.spyOn(boardsStore, 'generateDefaultLists').mockImplementation(
+ () =>
+ new Promise((resolve, reject) => {
+ if (fail) {
+ reject();
+ } else {
+ resolve({
+ data: [
+ {
+ id: 1,
+ title: 'To Do',
+ label: { id: 1 },
+ },
+ {
+ id: 2,
+ title: 'Doing',
+ label: { id: 2 },
+ },
+ ],
+ });
+ }
+ }),
+ );
+
+ vm = new Comp();
+
+ setImmediate(() => {
+ vm.$mount();
+ done();
+ });
+ });
+
+ it('renders pre-defined labels', () => {
+ expect(vm.$el.querySelectorAll('.board-blank-state-list li').length).toBe(2);
+
+ expect(vm.$el.querySelectorAll('.board-blank-state-list li')[0].textContent.trim()).toEqual(
+ 'To Do',
+ );
+
+ expect(vm.$el.querySelectorAll('.board-blank-state-list li')[1].textContent.trim()).toEqual(
+ 'Doing',
+ );
+ });
+
+ it('clears blank state', done => {
+ vm.$el.querySelector('.btn-default').click();
+
+ setImmediate(() => {
+ expect(boardsStore.welcomeIsHidden()).toBeTruthy();
+
+ done();
+ });
+ });
+
+ it('creates pre-defined labels', done => {
+ vm.$el.querySelector('.btn-success').click();
+
+ setImmediate(() => {
+ expect(boardsStore.addList).toHaveBeenCalledTimes(2);
+ expect(boardsStore.addList).toHaveBeenCalledWith(expect.objectContaining({ title: 'To Do' }));
+
+ expect(boardsStore.addList).toHaveBeenCalledWith(expect.objectContaining({ title: 'Doing' }));
+
+ done();
+ });
+ });
+
+ it('resets the store if request fails', done => {
+ fail = true;
+
+ vm.$el.querySelector('.btn-success').click();
+
+ setImmediate(() => {
+ expect(boardsStore.welcomeIsHidden()).toBeFalsy();
+ expect(boardsStore.removeList).toHaveBeenCalledWith(undefined, 'label');
+
+ done();
+ });
+ });
+});
diff --git a/spec/frontend/boards/board_new_issue_spec.js b/spec/frontend/boards/board_new_issue_spec.js
new file mode 100644
index 00000000000..4eb7f0c131e
--- /dev/null
+++ b/spec/frontend/boards/board_new_issue_spec.js
@@ -0,0 +1,202 @@
+/* global List */
+
+import $ from 'jquery';
+import Vue from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import boardNewIssue from '~/boards/components/board_new_issue.vue';
+import boardsStore from '~/boards/stores/boards_store';
+
+import '~/boards/models/list';
+import { listObj, boardsMockInterceptor } from './mock_data';
+
+describe('Issue boards new issue form', () => {
+ let vm;
+ let list;
+ let mock;
+ let newIssueMock;
+ const jQueryMock = {
+ enable: jest.fn(),
+ };
+ const promiseReturn = {
+ data: {
+ iid: 100,
+ },
+ };
+
+ const submitIssue = () => {
+ const dummySubmitEvent = {
+ preventDefault() {},
+ };
+ vm.$refs.submitButton = vm.$el.querySelector('.btn-success');
+ return vm.submit(dummySubmitEvent);
+ };
+
+ beforeEach(() => {
+ setFixtures('<div class="test-container"></div>');
+
+ const BoardNewIssueComp = Vue.extend(boardNewIssue);
+
+ mock = new MockAdapter(axios);
+ mock.onAny().reply(boardsMockInterceptor);
+
+ boardsStore.create();
+
+ list = new List(listObj);
+
+ newIssueMock = Promise.resolve(promiseReturn);
+ jest.spyOn(list, 'newIssue').mockImplementation(() => newIssueMock);
+
+ vm = new BoardNewIssueComp({
+ propsData: {
+ list,
+ },
+ }).$mount(document.querySelector('.test-container'));
+
+ $.fn.extend(jQueryMock);
+
+ return Vue.nextTick();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ mock.restore();
+ });
+
+ it('calls submit if submit button is clicked', () => {
+ jest.spyOn(vm, 'submit').mockImplementation(e => e.preventDefault());
+ vm.title = 'Testing Title';
+
+ return Vue.nextTick().then(() => {
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(vm.submit.mock.calls.length).toBe(1);
+ });
+ });
+
+ it('disables submit button if title is empty', () => {
+ expect(vm.$el.querySelector('.btn-success').disabled).toBe(true);
+ });
+
+ it('enables submit button if title is not empty', () => {
+ vm.title = 'Testing Title';
+
+ return Vue.nextTick().then(() => {
+ expect(vm.$el.querySelector('.form-control').value).toBe('Testing Title');
+ expect(vm.$el.querySelector('.btn-success').disabled).not.toBe(true);
+ });
+ });
+
+ it('clears title after clicking cancel', () => {
+ vm.$el.querySelector('.btn-default').click();
+
+ return Vue.nextTick().then(() => {
+ expect(vm.title).toBe('');
+ });
+ });
+
+ it('does not create new issue if title is empty', () => {
+ return submitIssue().then(() => {
+ expect(list.newIssue).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('submit success', () => {
+ it('creates new issue', () => {
+ vm.title = 'submit title';
+
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(list.newIssue).toHaveBeenCalled();
+ });
+ });
+
+ it('enables button after submit', () => {
+ vm.title = 'submit issue';
+
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(jQueryMock.enable).toHaveBeenCalled();
+ });
+ });
+
+ it('clears title after submit', () => {
+ vm.title = 'submit issue';
+
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(vm.title).toBe('');
+ });
+ });
+
+ it('sets detail issue after submit', () => {
+ expect(boardsStore.detail.issue.title).toBe(undefined);
+ vm.title = 'submit issue';
+
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(boardsStore.detail.issue.title).toBe('submit issue');
+ });
+ });
+
+ it('sets detail list after submit', () => {
+ vm.title = 'submit issue';
+
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(boardsStore.detail.list.id).toBe(list.id);
+ });
+ });
+
+ it('sets detail weight after submit', () => {
+ boardsStore.weightFeatureAvailable = true;
+ vm.title = 'submit issue';
+
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(boardsStore.detail.list.weight).toBe(list.weight);
+ });
+ });
+
+ it('does not set detail weight after submit', () => {
+ boardsStore.weightFeatureAvailable = false;
+ vm.title = 'submit issue';
+
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(boardsStore.detail.list.weight).toBe(list.weight);
+ });
+ });
+ });
+
+ describe('submit error', () => {
+ beforeEach(() => {
+ newIssueMock = Promise.reject(new Error('My hovercraft is full of eels!'));
+ vm.title = 'error';
+ });
+
+ it('removes issue', () => {
+ const lengthBefore = list.issues.length;
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(list.issues.length).toBe(lengthBefore);
+ });
+ });
+
+ it('shows error', () => {
+ return Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(vm.error).toBe(true);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
new file mode 100644
index 00000000000..ee427bc2154
--- /dev/null
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -0,0 +1,47 @@
+import { mount } from '@vue/test-utils';
+
+import boardsStore from '~/boards/stores/boards_store';
+import boardForm from '~/boards/components/board_form.vue';
+import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
+
+describe('board_form.vue', () => {
+ let wrapper;
+
+ const propsData = {
+ canAdminBoard: false,
+ labelsPath: `${gl.TEST_HOST}/labels/path`,
+ milestonePath: `${gl.TEST_HOST}/milestone/path`,
+ };
+
+ const findModal = () => wrapper.find(DeprecatedModal);
+
+ beforeEach(() => {
+ boardsStore.state.currentPage = 'edit';
+ wrapper = mount(boardForm, { propsData });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('methods', () => {
+ describe('cancel', () => {
+ it('resets currentPage', () => {
+ wrapper.vm.cancel();
+ expect(boardsStore.state.currentPage).toBe('');
+ });
+ });
+ });
+
+ describe('buttons', () => {
+ it('cancel button triggers cancel()', () => {
+ wrapper.setMethods({ cancel: jest.fn() });
+ findModal().vm.$emit('cancel');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.cancel).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/boards/issue_spec.js b/spec/frontend/boards/issue_spec.js
new file mode 100644
index 00000000000..ff72edaa695
--- /dev/null
+++ b/spec/frontend/boards/issue_spec.js
@@ -0,0 +1,197 @@
+/* global ListIssue */
+
+import axios from '~/lib/utils/axios_utils';
+import '~/boards/models/label';
+import '~/boards/models/assignee';
+import '~/boards/models/issue';
+import '~/boards/models/list';
+import boardsStore from '~/boards/stores/boards_store';
+import { setMockEndpoints } from './mock_data';
+
+describe('Issue model', () => {
+ let issue;
+
+ beforeEach(() => {
+ setMockEndpoints();
+ boardsStore.create();
+
+ issue = new ListIssue({
+ title: 'Testing',
+ id: 1,
+ iid: 1,
+ confidential: false,
+ labels: [
+ {
+ id: 1,
+ title: 'test',
+ color: 'red',
+ description: 'testing',
+ },
+ ],
+ assignees: [
+ {
+ id: 1,
+ name: 'name',
+ username: 'username',
+ avatar_url: 'http://avatar_url',
+ },
+ ],
+ });
+ });
+
+ it('has label', () => {
+ expect(issue.labels.length).toBe(1);
+ });
+
+ it('add new label', () => {
+ issue.addLabel({
+ id: 2,
+ title: 'bug',
+ color: 'blue',
+ description: 'bugs!',
+ });
+
+ expect(issue.labels.length).toBe(2);
+ });
+
+ it('does not add label if label id exists', () => {
+ issue.addLabel({
+ id: 1,
+ title: 'test 2',
+ color: 'blue',
+ description: 'testing',
+ });
+
+ expect(issue.labels.length).toBe(1);
+ expect(issue.labels[0].color).toBe('red');
+ });
+
+ it('adds other label with same title', () => {
+ issue.addLabel({
+ id: 2,
+ title: 'test',
+ color: 'blue',
+ description: 'other test',
+ });
+
+ expect(issue.labels.length).toBe(2);
+ });
+
+ it('finds label', () => {
+ const label = issue.findLabel(issue.labels[0]);
+
+ expect(label).toBeDefined();
+ });
+
+ it('removes label', () => {
+ const label = issue.findLabel(issue.labels[0]);
+ issue.removeLabel(label);
+
+ expect(issue.labels.length).toBe(0);
+ });
+
+ it('removes multiple labels', () => {
+ issue.addLabel({
+ id: 2,
+ title: 'bug',
+ color: 'blue',
+ description: 'bugs!',
+ });
+
+ expect(issue.labels.length).toBe(2);
+
+ issue.removeLabels([issue.labels[0], issue.labels[1]]);
+
+ expect(issue.labels.length).toBe(0);
+ });
+
+ it('adds assignee', () => {
+ issue.addAssignee({
+ id: 2,
+ name: 'Bruce Wayne',
+ username: 'batman',
+ avatar_url: 'http://batman',
+ });
+
+ expect(issue.assignees.length).toBe(2);
+ });
+
+ it('finds assignee', () => {
+ const assignee = issue.findAssignee(issue.assignees[0]);
+
+ expect(assignee).toBeDefined();
+ });
+
+ it('removes assignee', () => {
+ const assignee = issue.findAssignee(issue.assignees[0]);
+ issue.removeAssignee(assignee);
+
+ expect(issue.assignees.length).toBe(0);
+ });
+
+ it('removes all assignees', () => {
+ issue.removeAllAssignees();
+
+ expect(issue.assignees.length).toBe(0);
+ });
+
+ it('sets position to infinity if no position is stored', () => {
+ expect(issue.position).toBe(Infinity);
+ });
+
+ it('sets position', () => {
+ const relativePositionIssue = new ListIssue({
+ title: 'Testing',
+ iid: 1,
+ confidential: false,
+ relative_position: 1,
+ labels: [],
+ assignees: [],
+ });
+
+ expect(relativePositionIssue.position).toBe(1);
+ });
+
+ it('updates data', () => {
+ issue.updateData({ subscribed: true });
+
+ expect(issue.subscribed).toBe(true);
+ });
+
+ it('sets fetching state', () => {
+ expect(issue.isFetching.subscriptions).toBe(true);
+
+ issue.setFetchingState('subscriptions', false);
+
+ expect(issue.isFetching.subscriptions).toBe(false);
+ });
+
+ it('sets loading state', () => {
+ issue.setLoadingState('foo', true);
+
+ expect(issue.isLoading.foo).toBe(true);
+ });
+
+ describe('update', () => {
+ it('passes assignee ids when there are assignees', done => {
+ jest.spyOn(axios, 'patch').mockImplementation((url, data) => {
+ expect(data.issue.assignee_ids).toEqual([1]);
+ done();
+ return Promise.resolve();
+ });
+
+ issue.update('url');
+ });
+
+ it('passes assignee ids of [0] when there are no assignees', done => {
+ jest.spyOn(axios, 'patch').mockImplementation((url, data) => {
+ expect(data.issue.assignee_ids).toEqual([0]);
+ done();
+ return Promise.resolve();
+ });
+
+ issue.removeAllAssignees();
+ issue.update('url');
+ });
+ });
+});
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 05f73e0d8dc..fa4154676a2 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -1,3 +1,5 @@
+import boardsStore from '~/boards/stores/boards_store';
+
export const boardObj = {
id: 1,
name: 'test',
@@ -89,3 +91,54 @@ export const mockMilestone = {
start_date: '2018-01-01',
due_date: '2019-12-31',
};
+
+export const BoardsMockData = {
+ GET: {
+ '/test/-/boards/1/lists/300/issues?id=300&page=1': {
+ issues: [
+ {
+ title: 'Testing',
+ id: 1,
+ iid: 1,
+ confidential: false,
+ labels: [],
+ assignees: [],
+ },
+ ],
+ },
+ '/test/issue-boards/-/milestones.json': [
+ {
+ id: 1,
+ title: 'test',
+ },
+ ],
+ },
+ POST: {
+ '/test/-/boards/1/lists': listObj,
+ },
+ PUT: {
+ '/test/issue-boards/-/board/1/lists{/id}': {},
+ },
+ DELETE: {
+ '/test/issue-boards/-/board/1/lists{/id}': {},
+ },
+};
+
+export const boardsMockInterceptor = config => {
+ const body = BoardsMockData[config.method.toUpperCase()][config.url];
+ return [200, body];
+};
+
+export const setMockEndpoints = (opts = {}) => {
+ const boardsEndpoint = opts.boardsEndpoint || '/test/issue-boards/-/boards.json';
+ const listsEndpoint = opts.listsEndpoint || '/test/-/boards/1/lists';
+ const bulkUpdatePath = opts.bulkUpdatePath || '';
+ const boardId = opts.boardId || '1';
+
+ boardsStore.setEndpoints({
+ boardsEndpoint,
+ listsEndpoint,
+ bulkUpdatePath,
+ boardId,
+ });
+};