From f80d2ab3c603fd8dd90b2ca3ed1fa92202916b00 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 15 May 2017 13:51:25 +0100 Subject: [PATCH 1/8] Added specs for description field [ci skip] --- .../components/fields/description_spec.js | 34 +++++ .../components/markdown/field_spec.js | 121 ++++++++++++++++++ .../components/markdown/header_spec.js | 67 ++++++++++ 3 files changed, 222 insertions(+) create mode 100644 spec/javascripts/issue_show/components/fields/description_spec.js create mode 100644 spec/javascripts/vue_shared/components/markdown/field_spec.js create mode 100644 spec/javascripts/vue_shared/components/markdown/header_spec.js diff --git a/spec/javascripts/issue_show/components/fields/description_spec.js b/spec/javascripts/issue_show/components/fields/description_spec.js new file mode 100644 index 00000000000..d13362ef8e6 --- /dev/null +++ b/spec/javascripts/issue_show/components/fields/description_spec.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Store from '~/issue_show/stores'; +import descriptionField from '~/issue_show/components/fields/description.vue'; + +describe('Description field component', () => { + let vm; + let store; + + beforeEach((done) => { + const Component = Vue.extend(descriptionField); + store = new Store({ + titleHtml: '', + descriptionHtml: '', + issuableRef: '', + }); + store.formState.description = 'test'; + + vm = new Component({ + propsData: { + markdownPreviewUrl: '/', + markdownDocs: '/', + store, + }, + }).$mount(); + + Vue.nextTick(done); + }); + + it('renders markdown field with description', () => { + expect( + vm.$el.querySelector('.md-area textarea').value, + ).toBe('test'); + }); +}); diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js new file mode 100644 index 00000000000..4bbaff561fc --- /dev/null +++ b/spec/javascripts/vue_shared/components/markdown/field_spec.js @@ -0,0 +1,121 @@ +import Vue from 'vue'; +import fieldComponent from '~/vue_shared/components/markdown/field.vue'; + +describe('Markdown field component', () => { + let vm; + + beforeEach(() => { + vm = new Vue({ + render(createElement) { + return createElement( + fieldComponent, + { + props: { + markdownPreviewUrl: '/preview', + markdownDocs: '/docs', + }, + }, + [ + createElement('textarea', { + slot: 'textarea', + }), + ], + ); + }, + }); + }); + + it('creates a new instance of GL form', (done) => { + spyOn(gl, 'GLForm'); + vm.$mount(); + + Vue.nextTick(() => { + expect( + gl.GLForm, + ).toHaveBeenCalled(); + + done(); + }); + }); + + describe('mounted', () => { + beforeEach((done) => { + vm.$mount(); + + Vue.nextTick(done); + }); + + it('renders textarea inside backdrop', () => { + expect( + vm.$el.querySelector('.zen-backdrop textarea'), + ).not.toBeNull(); + }); + + describe('markdown preview', () => { + let previewLink; + + beforeEach(() => { + spyOn(Vue.http, 'post').and.callFake(() => new Promise((resolve) => { + resolve({ + json() { + return { + body: '

markdown preview

', + }; + }, + }); + })); + + previewLink = vm.$el.querySelector('.nav-links li:nth-child(2) a'); + }); + + it('sets preview link as active', (done) => { + previewLink.click(); + + Vue.nextTick(() => { + expect( + previewLink.parentNode.classList.contains('active'), + ).toBeTruthy(); + + done(); + }); + }); + + it('shows preview loading text', (done) => { + previewLink.click(); + + Vue.nextTick(() => { + expect( + vm.$el.querySelector('.md-preview').textContent.trim(), + ).toContain('Loading...'); + + done(); + }); + }); + + it('renders markdown preview', (done) => { + previewLink.click(); + + setTimeout(() => { + expect( + vm.$el.querySelector('.md-preview').innerHTML, + ).toContain('

markdown preview

'); + + done(); + }); + }); + + it('renders GFM with jQuery', (done) => { + spyOn($.fn, 'renderGFM'); + previewLink.click(); + + setTimeout(() => { + expect( + $.fn.renderGFM, + ).toHaveBeenCalled(); + + done(); + }); + }); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/markdown/header_spec.js b/spec/javascripts/vue_shared/components/markdown/header_spec.js new file mode 100644 index 00000000000..7110ff36937 --- /dev/null +++ b/spec/javascripts/vue_shared/components/markdown/header_spec.js @@ -0,0 +1,67 @@ +import Vue from 'vue'; +import headerComponent from '~/vue_shared/components/markdown/header.vue'; + +describe('Markdown field header component', () => { + let vm; + + beforeEach((done) => { + const Component = Vue.extend(headerComponent); + + vm = new Component({ + propsData: { + previewMarkdown: false, + }, + }).$mount(); + + Vue.nextTick(done); + }); + + it('renders markdown buttons', () => { + expect( + vm.$el.querySelectorAll('.js-md').length, + ).toBe(7); + }); + + it('renders `write` link as active when previewMarkdown is false', () => { + expect( + vm.$el.querySelector('li:nth-child(1)').classList.contains('active'), + ).toBeTruthy(); + }); + + it('renders `preview` link as active when previewMarkdown is true', (done) => { + vm.previewMarkdown = true; + + Vue.nextTick(() => { + expect( + vm.$el.querySelector('li:nth-child(2)').classList.contains('active'), + ).toBeTruthy(); + + done(); + }); + }); + + it('emits toggle markdown event when clicking preview', () => { + spyOn(vm, '$emit'); + + vm.$el.querySelector('li:nth-child(2) a').click(); + + expect( + vm.$emit, + ).toHaveBeenCalledWith('toggle-markdown'); + }); + + it('blurs preview link after click', (done) => { + const link = vm.$el.querySelector('li:nth-child(2) a'); + spyOn(HTMLElement.prototype, 'blur'); + + link.click(); + + setTimeout(() => { + expect( + link.blur, + ).toHaveBeenCalled(); + + done(); + }); + }); +}); From 907dd68e0a18e995dc5772c9bc8117aa150edc25 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 17 May 2017 13:01:24 +0100 Subject: [PATCH 2/8] Added move to project in issue inline edit form [ci skip] --- .../javascripts/issue_show/components/app.vue | 20 ++++- .../components/fields/project_move.vue | 84 +++++++++++++++++++ .../issue_show/components/form.vue | 14 ++++ app/assets/javascripts/issue_show/index.js | 6 ++ .../javascripts/issue_show/services/index.js | 2 +- .../javascripts/issue_show/stores/index.js | 1 + app/controllers/projects/issues_controller.rb | 5 +- app/serializers/issue_entity.rb | 6 ++ app/views/projects/issues/show.html.haml | 2 + .../issue_show/components/app_spec.js | 45 +++++++++- .../components/fields/project_move_spec.js | 38 +++++++++ 11 files changed, 215 insertions(+), 8 deletions(-) create mode 100644 app/assets/javascripts/issue_show/components/fields/project_move.vue create mode 100644 spec/javascripts/issue_show/components/fields/project_move_spec.js diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index eb594cfb60b..9d5e69585f1 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -15,6 +15,10 @@ export default { required: true, type: String, }, + canMove: { + required: true, + type: Boolean, + }, canUpdate: { required: true, type: Boolean, @@ -49,6 +53,10 @@ export default { type: String, required: true, }, + projectsAutocompleteUrl: { + type: String, + required: true, + }, }, data() { const store = new Store({ @@ -79,6 +87,7 @@ export default { this.store.formState = { title: this.state.titleText, description: this.state.descriptionText, + move_to_project_id: 0, }; }, closeForm() { @@ -86,7 +95,12 @@ export default { }, updateIssuable() { this.service.updateIssuable(this.store.formState) - .then(() => { + .then(res => res.json()) + .then((data) => { + if (location.pathname !== data.path) { + gl.utils.visitUrl(data.path); + } + eventHub.$emit('close.form'); }) .catch(() => { @@ -153,9 +167,11 @@ export default { + :markdown-preview-url="markdownPreviewUrl" + :projects-autocomplete-url="projectsAutocompleteUrl" />
+ import tooltipMixin from '../../../vue_shared/mixins/tooltip'; + + export default { + mixins: [ + tooltipMixin, + ], + props: { + formState: { + type: Object, + required: true, + }, + projectsAutocompleteUrl: { + type: String, + required: true, + }, + }, + mounted() { + const $moveDropdown = $(this.$refs['move-dropdown']); + + $moveDropdown.select2({ + ajax: { + url: this.projectsAutocompleteUrl, + quietMillis: 125, + data(term, page, context) { + return { + search: term, + offset_id: context, + }; + }, + results(data) { + const more = data.length >= 50; + const context = data[data.length - 1] ? data[data.length - 1].id : null; + + return { + results: data, + more, + context, + }; + }, + }, + formatResult(project) { + return project.name_with_namespace; + }, + formatSelection(project) { + return project.name_with_namespace; + }, + }) + .on('change', (e) => { + this.formState.move_to_project_id = parseInt(e.target.value, 10); + }); + }, + beforeDestroy() { + $(this.$refs['move-dropdown']).select2('destroy'); + }, + }; + + + diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue index 7732a1c194a..4cfc95e9888 100644 --- a/app/assets/javascripts/issue_show/components/form.vue +++ b/app/assets/javascripts/issue_show/components/form.vue @@ -2,9 +2,14 @@ import titleField from './fields/title.vue'; import descriptionField from './fields/description.vue'; import editActions from './edit_actions.vue'; + import projectMove from './fields/project_move.vue'; export default { props: { + canMove: { + type: Boolean, + required: true, + }, canDestroy: { type: Boolean, required: true, @@ -21,11 +26,16 @@ type: String, required: true, }, + projectsAutocompleteUrl: { + type: String, + required: true, + }, }, components: { titleField, descriptionField, editActions, + projectMove, }, }; @@ -38,6 +48,10 @@ :form-state="formState" :markdown-preview-url="markdownPreviewUrl" :markdown-docs="markdownDocs" /> + diff --git a/app/assets/javascripts/issue_show/index.js b/app/assets/javascripts/issue_show/index.js index d13e24a468b..666d144f958 100644 --- a/app/assets/javascripts/issue_show/index.js +++ b/app/assets/javascripts/issue_show/index.js @@ -23,15 +23,18 @@ document.addEventListener('DOMContentLoaded', () => { const { canUpdate, canDestroy, + canMove, endpoint, issuableRef, markdownPreviewUrl, markdownDocs, + projectsAutocompleteUrl, } = issuableElement.dataset; return { canUpdate: gl.utils.convertPermissionToBoolean(canUpdate), canDestroy: gl.utils.convertPermissionToBoolean(canDestroy), + canMove: gl.utils.convertPermissionToBoolean(canMove), endpoint, issuableRef, initialTitle: issuableTitleElement.innerHTML, @@ -39,6 +42,7 @@ document.addEventListener('DOMContentLoaded', () => { initialDescriptionText: issuableDescriptionTextarea ? issuableDescriptionTextarea.textContent : '', markdownPreviewUrl, markdownDocs, + projectsAutocompleteUrl, }; }, render(createElement) { @@ -46,6 +50,7 @@ document.addEventListener('DOMContentLoaded', () => { props: { canUpdate: this.canUpdate, canDestroy: this.canDestroy, + canMove: this.canMove, endpoint: this.endpoint, issuableRef: this.issuableRef, initialTitle: this.initialTitle, @@ -53,6 +58,7 @@ document.addEventListener('DOMContentLoaded', () => { initialDescriptionText: this.initialDescriptionText, markdownPreviewUrl: this.markdownPreviewUrl, markdownDocs: this.markdownDocs, + projectsAutocompleteUrl: this.projectsAutocompleteUrl, }, }); }, diff --git a/app/assets/javascripts/issue_show/services/index.js b/app/assets/javascripts/issue_show/services/index.js index 0ceff34cf8b..6f0fd0b1768 100644 --- a/app/assets/javascripts/issue_show/services/index.js +++ b/app/assets/javascripts/issue_show/services/index.js @@ -7,7 +7,7 @@ export default class Service { constructor(endpoint) { this.endpoint = endpoint; - this.resource = Vue.resource(this.endpoint, {}, { + this.resource = Vue.resource(`${this.endpoint}.json`, {}, { realtimeChanges: { method: 'GET', url: `${this.endpoint}/realtime_changes`, diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js index 3232875000d..5717f0a8e74 100644 --- a/app/assets/javascripts/issue_show/stores/index.js +++ b/app/assets/javascripts/issue_show/stores/index.js @@ -15,6 +15,7 @@ export default class Store { this.formState = { title: '', description: '', + move_to_project_id: 0, }; } diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 46438e68d54..9d28a7ed85a 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -148,10 +148,7 @@ class Projects::IssuesController < Projects::ApplicationController format.json do if @issue.valid? - render json: @issue.to_json(methods: [:task_status, :task_status_short], - include: { milestone: {}, - assignees: { only: [:id, :name, :username], methods: [:avatar_url] }, - labels: { methods: :text_color } }) + render json: IssueSerializer.new.represent(@issue) else render json: { errors: @issue.errors.full_messages }, status: :unprocessable_entity end diff --git a/app/serializers/issue_entity.rb b/app/serializers/issue_entity.rb index bc4f68710b2..6bc8d0f70c3 100644 --- a/app/serializers/issue_entity.rb +++ b/app/serializers/issue_entity.rb @@ -1,4 +1,6 @@ class IssueEntity < IssuableEntity + include RequestAwareEntity + expose :branch_name expose :confidential expose :assignees, using: API::Entities::UserBasic @@ -7,4 +9,8 @@ class IssueEntity < IssuableEntity expose :project_id expose :milestone, using: API::Entities::Milestone expose :labels, using: LabelEntity + + expose :path do |issue| + namespace_project_issue_path(issue.project.namespace, issue.project, issue) + end end diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 2b095648dcf..a35de038f2f 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -54,9 +54,11 @@ #js-issuable-app{ "data" => { "endpoint" => namespace_project_issue_path(@project.namespace, @project, @issue), "can-update" => can?(current_user, :update_issue, @issue).to_s, "can-destroy" => can?(current_user, :destroy_issue, @issue).to_s, + "can-move" => @issue.can_move?(current_user).to_s, "issuable-ref" => @issue.to_reference, "markdown-preview-url" => preview_markdown_path(@project), "markdown-docs" => help_page_path('user/markdown'), + "projects-autocomplete-url" => autocomplete_projects_path(project_id: @project.id), } } %h2.title= markdown_field(@issue, :title) - if @issue.description.present? diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 22b0a0f7046..700910c241a 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -29,12 +29,15 @@ describe('Issuable output', () => { propsData: { canUpdate: true, canDestroy: true, + canMove: true, endpoint: '/gitlab-org/gitlab-shell/issues/9/realtime_changes', issuableRef: '#1', initialTitle: '', initialDescriptionHtml: '', initialDescriptionText: '', - showForm: false, + markdownPreviewUrl: '/', + markdownDocs: '/', + projectsAutocompleteUrl: '/', }, }).$mount(); }); @@ -108,6 +111,46 @@ describe('Issuable output', () => { }); }); + it('does not redirect if issue has not moved', (done) => { + spyOn(gl.utils, 'visitUrl'); + spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { + resolve(); + })); + + vm.updateIssuable(); + + setTimeout(() => { + expect( + gl.utils.visitUrl, + ).not.toHaveBeenCalled(); + + done(); + }); + }); + + it('redirects if issue is moved', (done) => { + spyOn(gl.utils, 'visitUrl'); + spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { + resolve({ + json() { + return { + path: '/testing-issue-move', + }; + }, + }); + })); + + vm.updateIssuable(); + + setTimeout(() => { + expect( + gl.utils.visitUrl, + ).toHaveBeenCalledWith('/testing-issue-move'); + + done(); + }); + }); + it('closes form on error', (done) => { spyOn(window, 'Flash').and.callThrough(); spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve, reject) => { diff --git a/spec/javascripts/issue_show/components/fields/project_move_spec.js b/spec/javascripts/issue_show/components/fields/project_move_spec.js new file mode 100644 index 00000000000..86d35c33ff4 --- /dev/null +++ b/spec/javascripts/issue_show/components/fields/project_move_spec.js @@ -0,0 +1,38 @@ +import Vue from 'vue'; +import projectMove from '~/issue_show/components/fields/project_move.vue'; + +describe('Project move field component', () => { + let vm; + let formState; + + beforeEach((done) => { + const Component = Vue.extend(projectMove); + + formState = { + move_to_project_id: 0, + }; + + vm = new Component({ + propsData: { + formState, + projectsAutocompleteUrl: '/autocomplete', + }, + }).$mount(); + + Vue.nextTick(done); + }); + + it('mounts select2 element', () => { + expect( + vm.$el.querySelector('.select2-container'), + ).not.toBeNull(); + }); + + it('updates formState on change', () => { + $(vm.$refs['move-dropdown']).val(2).trigger('change'); + + expect( + formState.move_to_project_id, + ).toBe(2); + }); +}); From 292780272e41740102eca2630a681887d137e67e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 17 May 2017 14:35:02 +0100 Subject: [PATCH 3/8] Focus the description field in the inline form when mounted [ci skip] --- .../components/fields/description.vue | 5 ++- .../components/fields/description_spec.js | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 spec/javascripts/issue_show/components/fields/description_spec.js diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue index b4c31811a0b..35b1ea6ff2b 100644 --- a/app/assets/javascripts/issue_show/components/fields/description.vue +++ b/app/assets/javascripts/issue_show/components/fields/description.vue @@ -20,6 +20,9 @@ components: { markdownField, }, + mounted() { + this.$refs.textarea.focus(); + }, }; @@ -39,7 +42,7 @@ data-supports-slash-commands="false" aria-label="Description" v-model="formState.description" - ref="textatea" + ref="textarea" slot="textarea"> diff --git a/spec/javascripts/issue_show/components/fields/description_spec.js b/spec/javascripts/issue_show/components/fields/description_spec.js new file mode 100644 index 00000000000..6ea52feb84f --- /dev/null +++ b/spec/javascripts/issue_show/components/fields/description_spec.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import descriptionField from '~/issue_show/components/fields/description.vue'; + +describe('Description field component', () => { + let vm; + + beforeEach((done) => { + const Component = Vue.extend(descriptionField); + + // Needs an el in the DOM to be able to text the element is focused + const el = document.createElement('div'); + + document.body.appendChild(el); + + vm = new Component({ + el, + propsData: { + formState: { + description: '', + }, + markdownDocs: '/', + markdownPreviewUrl: '/', + }, + }).$mount(); + + Vue.nextTick(done); + }); + + it('focuses field when mounted', () => { + expect( + document.activeElement, + ).toBe(vm.$refs.textarea); + }); +}); From 6c34f5a212c04a5f384999146c1957cf983dcbf3 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 17 May 2017 15:24:39 +0100 Subject: [PATCH 4/8] Added a test with markdown [ci skip] --- .../components/fields/description_spec.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/spec/javascripts/issue_show/components/fields/description_spec.js b/spec/javascripts/issue_show/components/fields/description_spec.js index d13362ef8e6..05e628ca34c 100644 --- a/spec/javascripts/issue_show/components/fields/description_spec.js +++ b/spec/javascripts/issue_show/components/fields/description_spec.js @@ -19,7 +19,7 @@ describe('Description field component', () => { propsData: { markdownPreviewUrl: '/', markdownDocs: '/', - store, + formState: store.formState, }, }).$mount(); @@ -31,4 +31,16 @@ describe('Description field component', () => { vm.$el.querySelector('.md-area textarea').value, ).toBe('test'); }); + + it('renders markdown field with a markdown description', (done) => { + store.formState.description = '**test**'; + + Vue.nextTick(() => { + expect( + vm.$el.querySelector('.md-area textarea').value, + ).toBe('**test**'); + + done(); + }); + }); }); From cf0cc9726d26212e79d915339acb06edda726ec3 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 17 May 2017 16:06:17 +0100 Subject: [PATCH 5/8] Stops formState from updating if the form is already open [ci skip] --- .../javascripts/issue_show/components/app.vue | 14 +++++++------ .../issue_show/components/app_spec.js | 21 +++++++++++++++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index 87757b1a35d..47d9a27e99e 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -79,12 +79,14 @@ export default { }, methods: { openForm() { - this.showForm = true; - this.store.formState = { - title: this.state.titleText, - confidential: this.isConfidential, - description: this.state.descriptionText, - }; + if (!this.showForm) { + this.showForm = true; + this.store.formState = { + title: this.state.titleText, + confidential: this.isConfidential, + description: this.state.descriptionText, + }; + } }, closeForm() { this.showForm = false; diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 36cd174d341..646fb455d7c 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -23,7 +23,7 @@ describe('Issuable output', () => { const IssuableDescriptionComponent = Vue.extend(issuableApp); Vue.http.interceptors.push(issueShowInterceptor(issueShowData.initialRequest)); - spyOn(eventHub, '$emit'); + spyOn(eventHub, '$emit').and.callThrough(); vm = new IssuableDescriptionComponent({ propsData: { @@ -34,8 +34,9 @@ describe('Issuable output', () => { initialTitle: '', initialDescriptionHtml: '', initialDescriptionText: '', - showForm: false, isConfidential: false, + markdownPreviewUrl: '/', + markdownDocs: '/', }, }).$mount(); }); @@ -89,6 +90,22 @@ describe('Issuable output', () => { }); }); + it('does not update formState if form is already open', (done) => { + vm.openForm(); + + vm.state.titleText = 'testing 123'; + + vm.openForm(); + + Vue.nextTick(() => { + expect( + vm.store.formState.title, + ).not.toBe('testing 123'); + + done(); + }); + }); + describe('updateIssuable', () => { it('correctly updates issuable data', (done) => { spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { From 9c9a24cee8d961fa33675b857f2ad980e20e0a4b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 18 May 2017 09:12:44 +0100 Subject: [PATCH 6/8] Fixed typo --- .../issue_show/components/fields/description_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/javascripts/issue_show/components/fields/description_spec.js b/spec/javascripts/issue_show/components/fields/description_spec.js index 6ea52feb84f..cdb5c9ab862 100644 --- a/spec/javascripts/issue_show/components/fields/description_spec.js +++ b/spec/javascripts/issue_show/components/fields/description_spec.js @@ -7,7 +7,7 @@ describe('Description field component', () => { beforeEach((done) => { const Component = Vue.extend(descriptionField); - // Needs an el in the DOM to be able to text the element is focused + // Needs an el in the DOM to be able to test the element is focused const el = document.createElement('div'); document.body.appendChild(el); From c225007a7238d8ed18a1b344a2bc354672b25408 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 18 May 2017 15:50:25 +0100 Subject: [PATCH 7/8] Added back a removed test [ci skip] --- .../issue_show/components/app_spec.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 8848ca4e078..e1643f56d5d 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -14,7 +14,7 @@ const issueShowInterceptor = data => (request, next) => { })); }; -fdescribe('Issuable output', () => { +describe('Issuable output', () => { document.body.innerHTML = ''; let vm; @@ -92,6 +92,22 @@ fdescribe('Issuable output', () => { }); }); + it('does not update formState if form is already open', (done) => { + vm.openForm(); + + vm.state.titleText = 'testing 123'; + + vm.openForm(); + + Vue.nextTick(() => { + expect( + vm.store.formState.title, + ).not.toBe('testing 123'); + + done(); + }); + }); + describe('updateIssuable', () => { it('reloads the page if the confidential status has changed', (done) => { spyOn(gl.utils, 'visitUrl'); From 1c463586c4b1aa39f8c55ec7de684faa13aa5d8b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 18 May 2017 22:35:38 +0100 Subject: [PATCH 8/8] Removed un-used CSS Fixed random if statement [ci skip] --- .../javascripts/issue_show/components/app.vue | 5 +++-- .../issue_show/components/fields/project_move.vue | 1 - spec/javascripts/issue_show/components/app_spec.js | 13 +++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index 2a7a7d3900e..c4154745bf8 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -8,6 +8,7 @@ import Store from '../stores'; import titleComponent from './title.vue'; import descriptionComponent from './description.vue'; import formComponent from './form.vue'; +import '../../lib/utils/url_utility'; export default { props: { @@ -106,8 +107,8 @@ export default { .then((data) => { if (location.pathname !== data.path) { gl.utils.visitUrl(data.path); - } if (data.confidential !== this.isConfidential) { - gl.utils.visitUrl(location.href); + } else if (data.confidential !== this.isConfidential) { + gl.utils.visitUrl(location.pathname); } eventHub.$emit('close.form'); diff --git a/app/assets/javascripts/issue_show/components/fields/project_move.vue b/app/assets/javascripts/issue_show/components/fields/project_move.vue index 701c7f0ea9b..f811fb0de24 100644 --- a/app/assets/javascripts/issue_show/components/fields/project_move.vue +++ b/app/assets/javascripts/issue_show/components/fields/project_move.vue @@ -72,7 +72,6 @@
{ json() { return { confidential: true, + path: location.pathname, }; }, }); @@ -126,7 +127,7 @@ describe('Issuable output', () => { setTimeout(() => { expect( gl.utils.visitUrl, - ).toHaveBeenCalledWith(location.href); + ).toHaveBeenCalledWith(location.pathname); done(); }); @@ -154,7 +155,14 @@ describe('Issuable output', () => { it('does not redirect if issue has not moved', (done) => { spyOn(gl.utils, 'visitUrl'); spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { - resolve(); + resolve({ + json() { + return { + path: location.pathname, + confidential: vm.isConfidential, + }; + }, + }); })); vm.updateIssuable(); @@ -175,6 +183,7 @@ describe('Issuable output', () => { json() { return { path: '/testing-issue-move', + confidential: vm.isConfidential, }; }, });