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:
-rw-r--r--app/assets/javascripts/issue_show/components/description.vue8
-rw-r--r--app/assets/javascripts/task_list.js9
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/javascripts/issue_show/components/app_spec.js13
-rw-r--r--spec/javascripts/issue_show/components/description_spec.js14
-rw-r--r--spec/javascripts/task_list_spec.js156
6 files changed, 196 insertions, 7 deletions
diff --git a/app/assets/javascripts/issue_show/components/description.vue b/app/assets/javascripts/issue_show/components/description.vue
index 56e873c6ba0..f42787a7147 100644
--- a/app/assets/javascripts/issue_show/components/description.vue
+++ b/app/assets/javascripts/issue_show/components/description.vue
@@ -1,6 +1,6 @@
<script>
import $ from 'jquery';
-import createFlash from '~/flash';
+import { __ } from '~/locale';
import animateMixin from '../mixins/animate';
import TaskList from '../../task_list';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
@@ -91,8 +91,10 @@ export default {
},
taskListUpdateError() {
- createFlash(
- 'Someone edited this issue at the same time you did and we updated the issue description.',
+ window.Flash(
+ __(
+ 'Someone edited this issue at the same time you did and we updated the issue description.',
+ ),
);
this.$emit('taskListUpdateFailed');
diff --git a/app/assets/javascripts/task_list.js b/app/assets/javascripts/task_list.js
index c3932db7be2..161c44fa156 100644
--- a/app/assets/javascripts/task_list.js
+++ b/app/assets/javascripts/task_list.js
@@ -9,8 +9,9 @@ export default class TaskList {
this.dataType = options.dataType;
this.fieldName = options.fieldName;
this.lockVersion = options.lockVersion;
- this.onSuccess = options.onSuccess || (() => {});
this.taskListContainerSelector = `${this.selector} .js-task-list-container`;
+ this.updateHandler = this.update.bind(this);
+ this.onSuccess = options.onSuccess || (() => {});
this.onError =
options.onError ||
function showFlash(e) {
@@ -27,10 +28,10 @@ export default class TaskList {
}
init() {
- // Prevent duplicate event bindings
- this.disable();
+ this.disable(); // Prevent duplicate event bindings
+
$(this.taskListContainerSelector).taskList('enable');
- $(document).on('tasklist:changed', this.taskListContainerSelector, this.update.bind(this));
+ $(document).on('tasklist:changed', this.taskListContainerSelector, this.updateHandler);
}
getTaskListTarget(e = {}) {
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 5b794ae587b..0f50d797c69 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -6527,6 +6527,9 @@ msgstr ""
msgid "Snippets"
msgstr ""
+msgid "Someone edited this issue at the same time you did and we updated the issue description."
+msgstr ""
+
msgid "Something went wrong on our end"
msgstr ""
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js
index c3f624aebd3..028a36d3496 100644
--- a/spec/javascripts/issue_show/components/app_spec.js
+++ b/spec/javascripts/issue_show/components/app_spec.js
@@ -469,5 +469,18 @@ describe('Issuable output', () => {
.then(done)
.catch(done.fail);
});
+
+ it('should show error message if store update fails', done => {
+ spyOn(vm.service, 'getData').and.returnValue(Promise.reject());
+ spyOn(window, 'Flash');
+ vm.issuableType = 'merge request';
+
+ vm.updateStoreState()
+ .then(() => {
+ expect(window.Flash).toHaveBeenCalledWith(`Error updating ${vm.issuableType}`);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
});
});
diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js
index 52148f4c66b..b6833079e6e 100644
--- a/spec/javascripts/issue_show/components/description_spec.js
+++ b/spec/javascripts/issue_show/components/description_spec.js
@@ -187,4 +187,18 @@ describe('Description component', () => {
it('sets data-update-url', () => {
expect(vm.$el.querySelector('textarea').dataset.updateUrl).toEqual(gl.TEST_HOST);
});
+
+ describe('taskListUpdateError', () => {
+ it('should create flash notification and emit an event to parent', () => {
+ const msg =
+ 'Someone edited this issue at the same time you did and we updated the issue description.';
+ spyOn(window, 'Flash');
+ spyOn(vm, '$emit');
+
+ vm.taskListUpdateError();
+
+ expect(window.Flash).toHaveBeenCalledWith(msg);
+ expect(vm.$emit).toHaveBeenCalledWith('taskListUpdateFailed');
+ });
+ });
});
diff --git a/spec/javascripts/task_list_spec.js b/spec/javascripts/task_list_spec.js
new file mode 100644
index 00000000000..00f8b2d6d77
--- /dev/null
+++ b/spec/javascripts/task_list_spec.js
@@ -0,0 +1,156 @@
+import $ from 'jquery';
+import TaskList from '~/task_list';
+import axios from '~/lib/utils/axios_utils';
+
+describe('TaskList', () => {
+ let taskList;
+ let currentTarget;
+ const taskListOptions = {
+ selector: '.task-list',
+ dataType: 'issue',
+ fieldName: 'description',
+ lockVersion: 2,
+ };
+ const createTaskList = () => new TaskList(taskListOptions);
+
+ beforeEach(() => {
+ setFixtures(`
+ <div class="task-list">
+ <div class="js-task-list-container"></div>
+ </div>
+ `);
+
+ currentTarget = $('<div></div>');
+ taskList = createTaskList();
+ });
+
+ it('should call init when the class constructed', () => {
+ spyOn(TaskList.prototype, 'init').and.callThrough();
+ spyOn(TaskList.prototype, 'disable');
+ spyOn($.prototype, 'taskList');
+ spyOn($.prototype, 'on');
+
+ taskList = createTaskList();
+ const $taskListEl = $(taskList.taskListContainerSelector);
+
+ expect(taskList.init).toHaveBeenCalled();
+ expect(taskList.disable).toHaveBeenCalled();
+ expect($taskListEl.taskList).toHaveBeenCalledWith('enable');
+ expect($(document).on).toHaveBeenCalledWith(
+ 'tasklist:changed',
+ taskList.taskListContainerSelector,
+ taskList.updateHandler,
+ );
+ });
+
+ describe('getTaskListTarget', () => {
+ it('should return currentTarget from event object if exists', () => {
+ const $target = taskList.getTaskListTarget({ currentTarget });
+
+ expect($target).toEqual(currentTarget);
+ });
+
+ // it('should return element of the taskListContainerSelector', () => {
+ // const $target = taskList.getTaskListTarget();
+
+ // expect($target).toEqual($(taskList.taskListContainerSelector));
+ // });
+ });
+
+ describe('disableTaskListItems', () => {
+ it('should call taskList method with disable param', () => {
+ spyOn($.prototype, 'taskList');
+
+ taskList.disableTaskListItems({ currentTarget });
+
+ expect(currentTarget.taskList).toHaveBeenCalledWith('disable');
+ });
+ });
+
+ describe('enableTaskListItems', () => {
+ it('should call taskList method with enable param', () => {
+ spyOn($.prototype, 'taskList');
+
+ taskList.enableTaskListItems({ currentTarget });
+
+ expect(currentTarget.taskList).toHaveBeenCalledWith('enable');
+ });
+ });
+
+ describe('disable', () => {
+ it('should disable task list items and off document event', () => {
+ spyOn(taskList, 'disableTaskListItems');
+ spyOn($.prototype, 'off');
+
+ taskList.disable();
+
+ expect(taskList.disableTaskListItems).toHaveBeenCalled();
+ expect($(document).off).toHaveBeenCalledWith(
+ 'tasklist:changed',
+ taskList.taskListContainerSelector,
+ );
+ });
+ });
+
+ describe('update', () => {
+ it('should disable task list items and make a patch request then enable them again', done => {
+ const response = { data: { lock_version: 3 } };
+ spyOn(taskList, 'enableTaskListItems');
+ spyOn(taskList, 'disableTaskListItems');
+ spyOn(taskList, 'onSuccess');
+ spyOn(axios, 'patch').and.returnValue(Promise.resolve(response));
+
+ const value = 'hello world';
+ const endpoint = '/foo';
+ const target = $(`<input data-update-url="${endpoint}" value="${value}" />`);
+ const detail = {
+ index: 2,
+ checked: true,
+ lineNumber: 8,
+ lineSource: '- [ ] check item',
+ };
+ const event = { target, detail };
+ const patchData = {
+ [taskListOptions.dataType]: {
+ [taskListOptions.fieldName]: value,
+ lock_version: taskListOptions.lockVersion,
+ update_task: {
+ index: detail.index,
+ checked: detail.checked,
+ line_number: detail.lineNumber,
+ line_source: detail.lineSource,
+ },
+ },
+ };
+
+ taskList
+ .update(event)
+ .then(() => {
+ expect(taskList.disableTaskListItems).toHaveBeenCalledWith(event);
+ expect(axios.patch).toHaveBeenCalledWith(endpoint, patchData);
+ expect(taskList.enableTaskListItems).toHaveBeenCalledWith(event);
+ expect(taskList.onSuccess).toHaveBeenCalledWith(response.data);
+ expect(taskList.lockVersion).toEqual(response.data.lock_version);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ it('should handle request error and enable task list items', done => {
+ const response = { data: { error: 1 } };
+ spyOn(taskList, 'enableTaskListItems');
+ spyOn(taskList, 'onError');
+ spyOn(axios, 'patch').and.returnValue(Promise.reject({ response })); // eslint-disable-line prefer-promise-reject-errors
+
+ const event = { detail: {} };
+ taskList
+ .update(event)
+ .then(() => {
+ expect(taskList.enableTaskListItems).toHaveBeenCalledWith(event);
+ expect(taskList.onError).toHaveBeenCalledWith(response.data);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+});