diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index cd569eb3045..b6eacf839b9 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -130,6 +130,10 @@ export default { required: false, default: true, }, + lockVersion: { + type: Number, + required: true, + }, }, data() { const store = new Store({ @@ -141,6 +145,7 @@ export default { updatedByName: this.updatedByName, updatedByPath: this.updatedByPath, taskStatus: this.initialTaskStatus, + lock_version: this.lockVersion, }); return { @@ -214,6 +219,7 @@ export default { this.store.setFormState({ title: this.state.titleText, description: this.state.descriptionText, + lock_version: this.state.lock_version, lockedWarningVisible: false, updateLoading: false, }); diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js index 32044d6da25..2b3903def6b 100644 --- a/app/assets/javascripts/issue_show/stores/index.js +++ b/app/assets/javascripts/issue_show/stores/index.js @@ -6,6 +6,7 @@ export default class Store { description: '', lockedWarningVisible: false, updateLoading: false, + lock_version: 0, }; } @@ -22,6 +23,7 @@ export default class Store { this.state.updatedAt = data.updated_at; this.state.updatedByName = data.updated_by_name; this.state.updatedByPath = data.updated_by_path; + this.state.lock_version = data.lock_version; } stateShouldUpdate(data) { diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 03e3a72a82f..af319e5ebfe 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -190,6 +190,7 @@ describe IssuablesHelper do markdownDocsPath: '/help/user/markdown', markdownVersion: CacheMarkdownField::CACHE_COMMONMARK_VERSION, issuableTemplates: [], + lockVersion: issue.lock_version, projectPath: @project.path, projectNamespace: @project.namespace.path, initialTitleHtml: issue.title, diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 2bd1b3996dc..9b2b6b670c3 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -43,6 +43,7 @@ describe('Issuable output', () => { initialTitleText: '', initialDescriptionHtml: 'test', initialDescriptionText: 'test', + lockVersion: 1, markdownPreviewPath: '/', markdownDocsPath: '/', projectNamespace: '/', @@ -78,6 +79,7 @@ describe('Issuable output', () => { expect(formatText(editedText.innerText)).toMatch(/Edited[\s\S]+?by Some User/); expect(editedText.querySelector('.author-link').href).toMatch(/\/some_user$/); expect(editedText.querySelector('time')).toBeTruthy(); + expect(vm.state.lock_version).toEqual(1); }) .then(() => { vm.poll.makeRequest(); @@ -95,6 +97,7 @@ describe('Issuable output', () => { expect(editedText.querySelector('.author-link').href).toMatch(/\/other_user$/); expect(editedText.querySelector('time')).toBeTruthy(); + expect(vm.state.lock_version).toEqual(2); }) .then(done) .catch(done.fail); @@ -255,15 +258,10 @@ describe('Issuable output', () => { describe('error when updating', () => { beforeEach(() => { spyOn(window, 'Flash').and.callThrough(); - spyOn(vm.service, 'updateIssuable').and.callFake( - () => - new Promise((resolve, reject) => { - reject(); - }), - ); }); it('closes form on error', done => { + spyOn(vm.service, 'updateIssuable').and.callFake(() => Promise.resolve()); vm.updateIssuable(); setTimeout(() => { @@ -276,6 +274,7 @@ describe('Issuable output', () => { }); it('returns the correct error message for issuableType', done => { + spyOn(vm.service, 'updateIssuable').and.callFake(() => Promise.reject()); vm.issuableType = 'merge request'; Vue.nextTick(() => { @@ -290,6 +289,20 @@ describe('Issuable output', () => { }); }); }); + + it('shows error mesage from backend if exists', done => { + const msg = 'Custom error message from backend'; + spyOn(vm.service, 'updateIssuable').and.callFake(() => + Promise.reject({ response: { data: { errors: msg } } }), // eslint-disable-line prefer-promise-reject-errors + ); + + vm.updateIssuable(); + setTimeout(() => { + expect(window.Flash).toHaveBeenCalledWith(msg); + + done(); + }); + }); }); }); @@ -420,6 +433,7 @@ describe('Issuable output', () => { .then(vm.$nextTick) .then(() => { expect(vm.formState.lockedWarningVisible).toEqual(true); + expect(vm.formState.lock_version).toEqual(1); expect(vm.$el.querySelector('.alert')).not.toBeNull(); }) .then(done) diff --git a/spec/javascripts/issue_show/mock_data.js b/spec/javascripts/issue_show/mock_data.js index 74b3efb014b..f4475aadb8b 100644 --- a/spec/javascripts/issue_show/mock_data.js +++ b/spec/javascripts/issue_show/mock_data.js @@ -8,6 +8,7 @@ export default { updated_at: '2015-05-15T12:31:04.428Z', updated_by_name: 'Some User', updated_by_path: '/some_user', + lock_version: 1, }, secondRequest: { title: '

2

', @@ -18,5 +19,6 @@ export default { updated_at: '2016-05-15T12:31:04.428Z', updated_by_name: 'Other User', updated_by_path: '/other_user', + lock_version: 2, }, };