diff options
Diffstat (limited to 'spec/javascripts')
-rw-r--r-- | spec/javascripts/issue_show/components/app_spec.js | 21 | ||||
-rw-r--r-- | spec/javascripts/issue_show/components/fields/project_move_spec.js | 38 | ||||
-rw-r--r-- | spec/javascripts/issue_show/components/form_spec.js | 2 | ||||
-rw-r--r-- | spec/javascripts/sidebar/mock_data.js | 41 | ||||
-rw-r--r-- | spec/javascripts/sidebar/sidebar_mediator_spec.js | 40 | ||||
-rw-r--r-- | spec/javascripts/sidebar/sidebar_move_issue_spec.js | 142 | ||||
-rw-r--r-- | spec/javascripts/sidebar/sidebar_service_spec.js | 28 | ||||
-rw-r--r-- | spec/javascripts/sidebar/sidebar_store_spec.js | 14 |
8 files changed, 262 insertions, 64 deletions
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 3af26e2f28f..39065814bc2 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -34,7 +34,6 @@ describe('Issuable output', () => { propsData: { canUpdate: true, canDestroy: true, - canMove: true, endpoint: '/gitlab-org/gitlab-shell/issues/9/realtime_changes', issuableRef: '#1', initialTitleHtml: '', @@ -43,7 +42,6 @@ describe('Issuable output', () => { initialDescriptionText: '', markdownPreviewPath: '/', markdownDocsPath: '/', - projectsAutocompletePath: '/', isConfidential: false, projectNamespace: '/', projectPath: '/', @@ -226,7 +224,7 @@ describe('Issuable output', () => { }); }); - it('redirects if issue is moved', (done) => { + it('redirects if returned web_url has changed', (done) => { spyOn(gl.utils, 'visitUrl'); spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { resolve({ @@ -250,23 +248,6 @@ describe('Issuable output', () => { }); }); - it('does not update issuable if project move confirm is false', (done) => { - spyOn(window, 'confirm').and.returnValue(false); - spyOn(vm.service, 'updateIssuable'); - - vm.store.formState.move_to_project_id = 1; - - vm.updateIssuable(); - - setTimeout(() => { - expect( - vm.service.updateIssuable, - ).not.toHaveBeenCalled(); - - 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 deleted file mode 100644 index 8b6ed6a03a9..00000000000 --- a/spec/javascripts/issue_show/components/fields/project_move_spec.js +++ /dev/null @@ -1,38 +0,0 @@ -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, - projectsAutocompletePath: '/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); - }); -}); diff --git a/spec/javascripts/issue_show/components/form_spec.js b/spec/javascripts/issue_show/components/form_spec.js index d8af5287431..6e89528a3ea 100644 --- a/spec/javascripts/issue_show/components/form_spec.js +++ b/spec/javascripts/issue_show/components/form_spec.js @@ -12,7 +12,6 @@ describe('Inline edit form component', () => { vm = new Component({ propsData: { canDestroy: true, - canMove: true, formState: { title: 'b', description: 'a', @@ -20,7 +19,6 @@ describe('Inline edit form component', () => { }, markdownPreviewPath: '/', markdownDocsPath: '/', - projectsAutocompletePath: '/', projectPath: '/', projectNamespace: '/', }, diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js index 9fc8667ecc9..e2b6bcabc98 100644 --- a/spec/javascripts/sidebar/mock_data.js +++ b/spec/javascripts/sidebar/mock_data.js @@ -66,17 +66,57 @@ const sidebarMockData = { }, labels: [], }, + '/autocomplete/projects?project_id=15': [ + { + 'id': 0, + 'name_with_namespace': 'No project', + }, { + 'id': 20, + 'name_with_namespace': 'foo / bar', + }, + ], }, 'PUT': { '/gitlab-org/gitlab-shell/issues/5.json': { data: {}, }, }, + 'POST': { + '/gitlab-org/gitlab-shell/issues/5/move': { + id: 123, + iid: 5, + author_id: 1, + description: 'some description', + lock_version: 5, + milestone_id: null, + state: 'opened', + title: 'some title', + updated_by_id: 1, + created_at: '2017-06-27T19:54:42.437Z', + updated_at: '2017-08-18T03:39:49.222Z', + deleted_at: null, + time_estimate: 0, + total_time_spent: 0, + human_time_estimate: null, + human_total_time_spent: null, + branch_name: null, + confidential: false, + assignees: [], + due_date: null, + moved_to_id: null, + project_id: 7, + milestone: null, + labels: [], + web_url: '/root/some-project/issues/5', + }, + }, }; export default { mediator: { endpoint: '/gitlab-org/gitlab-shell/issues/5.json', + moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move', + projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15', editable: true, currentUser: { id: 1, @@ -85,6 +125,7 @@ export default { avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', }, rootPath: '/', + fullPath: '/gitlab-org/gitlab-shell', }, time: { time_estimate: 3600, diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js index e246f41ee82..3aa8ca5db0d 100644 --- a/spec/javascripts/sidebar/sidebar_mediator_spec.js +++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js @@ -30,7 +30,7 @@ describe('Sidebar mediator', () => { expect(resp.status).toEqual(200); done(); }) - .catch(() => {}); + .catch(done.fail); }); it('fetches the data', () => { @@ -38,4 +38,42 @@ describe('Sidebar mediator', () => { this.mediator.fetch(); expect(this.mediator.service.get).toHaveBeenCalled(); }); + + it('sets moveToProjectId', () => { + const projectId = 7; + spyOn(this.mediator.store, 'setMoveToProjectId').and.callThrough(); + + this.mediator.setMoveToProjectId(projectId); + + expect(this.mediator.store.setMoveToProjectId).toHaveBeenCalledWith(projectId); + }); + + it('fetches autocomplete projects', (done) => { + const searchTerm = 'foo'; + spyOn(this.mediator.service, 'getProjectsAutocomplete').and.callThrough(); + spyOn(this.mediator.store, 'setAutocompleteProjects').and.callThrough(); + + this.mediator.fetchAutocompleteProjects(searchTerm) + .then(() => { + expect(this.mediator.service.getProjectsAutocomplete).toHaveBeenCalledWith(searchTerm); + expect(this.mediator.store.setAutocompleteProjects).toHaveBeenCalled(); + done(); + }) + .catch(done.fail); + }); + + it('moves issue', (done) => { + const moveToProjectId = 7; + this.mediator.store.setMoveToProjectId(moveToProjectId); + spyOn(this.mediator.service, 'moveIssue').and.callThrough(); + spyOn(gl.utils, 'visitUrl'); + + this.mediator.moveIssue() + .then(() => { + expect(this.mediator.service.moveIssue).toHaveBeenCalledWith(moveToProjectId); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('/root/some-project/issues/5'); + done(); + }) + .catch(done.fail); + }); }); diff --git a/spec/javascripts/sidebar/sidebar_move_issue_spec.js b/spec/javascripts/sidebar/sidebar_move_issue_spec.js new file mode 100644 index 00000000000..8b0d51bbcc8 --- /dev/null +++ b/spec/javascripts/sidebar/sidebar_move_issue_spec.js @@ -0,0 +1,142 @@ +import Vue from 'vue'; +import SidebarMediator from '~/sidebar/sidebar_mediator'; +import SidebarStore from '~/sidebar/stores/sidebar_store'; +import SidebarService from '~/sidebar/services/sidebar_service'; +import SidebarMoveIssue from '~/sidebar/lib/sidebar_move_issue'; +import Mock from './mock_data'; + +describe('SidebarMoveIssue', () => { + beforeEach(() => { + Vue.http.interceptors.push(Mock.sidebarMockInterceptor); + this.mediator = new SidebarMediator(Mock.mediator); + this.$content = $(` + <div class="dropdown"> + <div class="js-toggle"></div> + <div class="dropdown-content"></div> + <div class="js-confirm-button"></div> + </div> + `); + this.$toggleButton = this.$content.find('.js-toggle'); + this.$confirmButton = this.$content.find('.js-confirm-button'); + + this.sidebarMoveIssue = new SidebarMoveIssue( + this.mediator, + this.$toggleButton, + this.$confirmButton, + ); + this.sidebarMoveIssue.init(); + }); + + afterEach(() => { + SidebarService.singleton = null; + SidebarStore.singleton = null; + SidebarMediator.singleton = null; + + this.sidebarMoveIssue.destroy(); + + Vue.http.interceptors = _.without(Vue.http.interceptors, Mock.sidebarMockInterceptor); + }); + + describe('init', () => { + it('should initialize the dropdown and listeners', () => { + spyOn(this.sidebarMoveIssue, 'initDropdown'); + spyOn(this.sidebarMoveIssue, 'addEventListeners'); + + this.sidebarMoveIssue.init(); + + expect(this.sidebarMoveIssue.initDropdown).toHaveBeenCalled(); + expect(this.sidebarMoveIssue.addEventListeners).toHaveBeenCalled(); + }); + }); + + describe('destroy', () => { + it('should remove the listeners', () => { + spyOn(this.sidebarMoveIssue, 'removeEventListeners'); + + this.sidebarMoveIssue.destroy(); + + expect(this.sidebarMoveIssue.removeEventListeners).toHaveBeenCalled(); + }); + }); + + describe('initDropdown', () => { + it('should initialize the gl_dropdown', () => { + spyOn($.fn, 'glDropdown'); + + this.sidebarMoveIssue.initDropdown(); + + expect($.fn.glDropdown).toHaveBeenCalled(); + }); + }); + + describe('onConfirmClicked', () => { + it('should move the issue with valid project ID', () => { + spyOn(this.mediator, 'moveIssue').and.returnValue(Promise.resolve()); + this.mediator.setMoveToProjectId(7); + + this.sidebarMoveIssue.onConfirmClicked(); + + expect(this.mediator.moveIssue).toHaveBeenCalled(); + expect(this.$confirmButton.attr('disabled')).toBe('disabled'); + expect(this.$confirmButton.hasClass('is-loading')).toBe(true); + }); + + it('should remove loading state from confirm button on failure', (done) => { + spyOn(window, 'Flash'); + spyOn(this.mediator, 'moveIssue').and.returnValue(Promise.reject()); + this.mediator.setMoveToProjectId(7); + + this.sidebarMoveIssue.onConfirmClicked(); + + expect(this.mediator.moveIssue).toHaveBeenCalled(); + // Wait for the move issue request to fail + setTimeout(() => { + expect(window.Flash).toHaveBeenCalled(); + expect(this.$confirmButton.attr('disabled')).toBe(undefined); + expect(this.$confirmButton.hasClass('is-loading')).toBe(false); + done(); + }); + }); + + it('should not move the issue with id=0', () => { + spyOn(this.mediator, 'moveIssue'); + this.mediator.setMoveToProjectId(0); + + this.sidebarMoveIssue.onConfirmClicked(); + + expect(this.mediator.moveIssue).not.toHaveBeenCalled(); + }); + }); + + it('should set moveToProjectId on dropdown item "No project" click', (done) => { + spyOn(this.mediator, 'setMoveToProjectId'); + + // Open the dropdown + this.$toggleButton.dropdown('toggle'); + + // Wait for the autocomplete request to finish + setTimeout(() => { + this.$content.find('.js-move-issue-dropdown-item').eq(0).trigger('click'); + + expect(this.mediator.setMoveToProjectId).toHaveBeenCalledWith(0); + expect(this.$confirmButton.attr('disabled')).toBe('disabled'); + done(); + }, 0); + }); + + it('should set moveToProjectId on dropdown item click', (done) => { + spyOn(this.mediator, 'setMoveToProjectId'); + + // Open the dropdown + this.$toggleButton.dropdown('toggle'); + + // Wait for the autocomplete request to finish + setTimeout(() => { + this.$content.find('.js-move-issue-dropdown-item').eq(1).trigger('click'); + + expect(this.mediator.setMoveToProjectId).toHaveBeenCalledWith(20); + expect(this.$confirmButton.attr('disabled')).toBe(undefined); + done(); + }, 0); + }); +}); diff --git a/spec/javascripts/sidebar/sidebar_service_spec.js b/spec/javascripts/sidebar/sidebar_service_spec.js index 91a4dd669a7..a4bd8ba8d88 100644 --- a/spec/javascripts/sidebar/sidebar_service_spec.js +++ b/spec/javascripts/sidebar/sidebar_service_spec.js @@ -5,7 +5,11 @@ import Mock from './mock_data'; describe('Sidebar service', () => { beforeEach(() => { Vue.http.interceptors.push(Mock.sidebarMockInterceptor); - this.service = new SidebarService('/gitlab-org/gitlab-shell/issues/5.json'); + this.service = new SidebarService({ + endpoint: '/gitlab-org/gitlab-shell/issues/5.json', + moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move', + projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15', + }); }); afterEach(() => { @@ -19,7 +23,7 @@ describe('Sidebar service', () => { expect(resp).toBeDefined(); done(); }) - .catch(() => {}); + .catch(done.fail); }); it('updates the data', (done) => { @@ -28,6 +32,24 @@ describe('Sidebar service', () => { expect(resp).toBeDefined(); done(); }) - .catch(() => {}); + .catch(done.fail); + }); + + it('gets projects for autocomplete', (done) => { + this.service.getProjectsAutocomplete() + .then((resp) => { + expect(resp).toBeDefined(); + done(); + }) + .catch(done.fail); + }); + + it('moves the issue to another project', (done) => { + this.service.moveIssue(123) + .then((resp) => { + expect(resp).toBeDefined(); + done(); + }) + .catch(done.fail); }); }); diff --git a/spec/javascripts/sidebar/sidebar_store_spec.js b/spec/javascripts/sidebar/sidebar_store_spec.js index b3fa156eb64..69eb3839d67 100644 --- a/spec/javascripts/sidebar/sidebar_store_spec.js +++ b/spec/javascripts/sidebar/sidebar_store_spec.js @@ -82,4 +82,18 @@ describe('Sidebar store', () => { expect(this.store.humanTimeEstimate).toEqual(Mock.time.human_time_estimate); expect(this.store.humanTotalTimeSpent).toEqual(Mock.time.human_total_time_spent); }); + + it('set autocomplete projects', () => { + const projects = [{ id: 0 }]; + this.store.setAutocompleteProjects(projects); + + expect(this.store.autocompleteProjects).toEqual(projects); + }); + + it('set move to project ID', () => { + const projectId = 7; + this.store.setMoveToProjectId(projectId); + + expect(this.store.moveToProjectId).toEqual(projectId); + }); }); |