diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2018-05-07 12:24:30 +0300 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2018-05-07 12:24:30 +0300 |
commit | eaeeac2ff42232f139a74d629d6dcf39c1819ee2 (patch) | |
tree | 51f73287ea8144a2253476b7aa0140a4bcc76d85 /spec/javascripts | |
parent | 9f7a6742466931f219cb83ff63e6debcec5db221 (diff) | |
parent | 398ee68457fd5bdcac14b5298f5c3f35b008d808 (diff) |
Merge branch '44846-improve-web-ide-left-panel-and-modes' into 'master'
Resolve "Improve Web IDE left panel and modes"
Closes #44846
See merge request gitlab-org/gitlab-ce!18581
Diffstat (limited to 'spec/javascripts')
25 files changed, 633 insertions, 507 deletions
diff --git a/spec/javascripts/ide/components/activity_bar_spec.js b/spec/javascripts/ide/components/activity_bar_spec.js new file mode 100644 index 00000000000..946c7e8e9c8 --- /dev/null +++ b/spec/javascripts/ide/components/activity_bar_spec.js @@ -0,0 +1,92 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import { activityBarViews } from '~/ide/constants'; +import ActivityBar from '~/ide/components/activity_bar.vue'; +import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; +import { resetStore } from '../helpers'; + +describe('IDE activity bar', () => { + const Component = Vue.extend(ActivityBar); + let vm; + + beforeEach(() => { + Vue.set(store.state.projects, 'abcproject', { + web_url: 'testing', + }); + Vue.set(store.state, 'currentProjectId', 'abcproject'); + + vm = createComponentWithStore(Component, store); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + describe('goBackUrl', () => { + it('renders the Go Back link with the referrer when present', () => { + const fakeReferrer = '/example/README.md'; + spyOnProperty(document, 'referrer').and.returnValue(fakeReferrer); + + vm.$mount(); + + expect(vm.goBackUrl).toEqual(fakeReferrer); + }); + + it('renders the Go Back link with the project url when referrer is not present', () => { + const fakeReferrer = ''; + spyOnProperty(document, 'referrer').and.returnValue(fakeReferrer); + + vm.$mount(); + + expect(vm.goBackUrl).toEqual('testing'); + }); + }); + + describe('updateActivityBarView', () => { + beforeEach(() => { + spyOn(vm, 'updateActivityBarView'); + + vm.$mount(); + }); + + it('calls updateActivityBarView with edit value on click', () => { + vm.$el.querySelector('.js-ide-edit-mode').click(); + + expect(vm.updateActivityBarView).toHaveBeenCalledWith(activityBarViews.edit); + }); + + it('calls updateActivityBarView with commit value on click', () => { + vm.$el.querySelector('.js-ide-commit-mode').click(); + + expect(vm.updateActivityBarView).toHaveBeenCalledWith(activityBarViews.commit); + }); + + it('calls updateActivityBarView with review value on click', () => { + vm.$el.querySelector('.js-ide-review-mode').click(); + + expect(vm.updateActivityBarView).toHaveBeenCalledWith(activityBarViews.review); + }); + }); + + describe('active item', () => { + beforeEach(() => { + vm.$mount(); + }); + + it('sets edit item active', () => { + expect(vm.$el.querySelector('.js-ide-edit-mode').classList).toContain('active'); + }); + + it('sets commit item active', done => { + vm.$store.state.currentActivityView = activityBarViews.commit; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.js-ide-commit-mode').classList).toContain('active'); + + done(); + }); + }); + }); +}); diff --git a/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js b/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js index 53275b78da5..16d0b354a30 100644 --- a/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js @@ -10,10 +10,9 @@ describe('IDE commit panel empty state', () => { beforeEach(() => { const Component = Vue.extend(emptyState); - vm = createComponentWithStore(Component, store, { - noChangesStateSvgPath: 'no-changes', - committedStateSvgPath: 'committed-state', - }); + Vue.set(store.state, 'noChangesStateSvgPath', 'no-changes'); + + vm = createComponentWithStore(Component, store); vm.$mount(); }); @@ -27,37 +26,4 @@ describe('IDE commit panel empty state', () => { it('renders no changes text when last commit message is empty', () => { expect(vm.$el.textContent).toContain('No changes'); }); - - describe('toggle button', () => { - it('calls store action', () => { - spyOn(vm, 'toggleRightPanelCollapsed'); - - vm.$el.querySelector('.multi-file-commit-panel-collapse-btn').click(); - - expect(vm.toggleRightPanelCollapsed).toHaveBeenCalled(); - }); - - it('renders collapsed class', done => { - vm.$el.querySelector('.multi-file-commit-panel-collapse-btn').click(); - - Vue.nextTick(() => { - expect(vm.$el.querySelector('.is-collapsed')).not.toBeNull(); - - done(); - }); - }); - }); - - describe('collapsed state', () => { - beforeEach(done => { - vm.$store.state.rightPanelCollapsed = true; - - Vue.nextTick(done); - }); - - it('does not render text & svg', () => { - expect(vm.$el.querySelector('img')).toBeNull(); - expect(vm.$el.textContent).not.toContain('No changes'); - }); - }); }); diff --git a/spec/javascripts/ide/components/commit_sidebar/form_spec.js b/spec/javascripts/ide/components/commit_sidebar/form_spec.js new file mode 100644 index 00000000000..ce7c134bc97 --- /dev/null +++ b/spec/javascripts/ide/components/commit_sidebar/form_spec.js @@ -0,0 +1,146 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import CommitForm from '~/ide/components/commit_sidebar/form.vue'; +import { activityBarViews } from '~/ide/constants'; +import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; +import { resetStore } from '../../helpers'; + +describe('IDE commit form', () => { + const Component = Vue.extend(CommitForm); + let vm; + + beforeEach(() => { + spyOnProperty(window, 'innerHeight').and.returnValue(800); + + store.state.changedFiles.push('test'); + + vm = createComponentWithStore(Component, store).$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('enables button when has changes', () => { + expect(vm.$el.querySelector('[disabled]')).toBe(null); + }); + + describe('compact', () => { + it('renders commit button in compact mode', () => { + expect(vm.$el.querySelector('.btn-primary')).not.toBeNull(); + expect(vm.$el.querySelector('.btn-primary').textContent).toContain('Commit'); + }); + + it('does not render form', () => { + expect(vm.$el.querySelector('form')).toBeNull(); + }); + + it('renders overview text', done => { + vm.$store.state.stagedFiles.push('test'); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('p').textContent).toContain('1 unstaged and 1 staged changes'); + done(); + }); + }); + + it('shows form when clicking commit button', done => { + vm.$el.querySelector('.btn-primary').click(); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('form')).not.toBeNull(); + + done(); + }); + }); + + it('toggles activity bar vie when clicking commit button', done => { + vm.$el.querySelector('.btn-primary').click(); + + vm.$nextTick(() => { + expect(store.state.currentActivityView).toBe(activityBarViews.commit); + + done(); + }); + }); + }); + + describe('full', () => { + beforeEach(done => { + vm.isCompact = false; + + vm.$nextTick(done); + }); + + it('updates commitMessage in store on input', done => { + const textarea = vm.$el.querySelector('textarea'); + + textarea.value = 'testing commit message'; + + textarea.dispatchEvent(new Event('input')); + + getSetTimeoutPromise() + .then(() => { + expect(vm.$store.state.commit.commitMessage).toBe('testing commit message'); + }) + .then(done) + .catch(done.fail); + }); + + it('updating currentActivityView not to commit view sets compact mode', done => { + store.state.currentActivityView = 'a'; + + vm.$nextTick(() => { + expect(vm.isCompact).toBe(true); + + done(); + }); + }); + + describe('discard draft button', () => { + it('hidden when commitMessage is empty', () => { + expect(vm.$el.querySelector('.btn-default').textContent).toContain('Collapse'); + }); + + it('resets commitMessage when clicking discard button', done => { + vm.$store.state.commit.commitMessage = 'testing commit message'; + + getSetTimeoutPromise() + .then(() => { + vm.$el.querySelector('.btn-default').click(); + }) + .then(Vue.nextTick) + .then(() => { + expect(vm.$store.state.commit.commitMessage).not.toBe('testing commit message'); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('when submitting', () => { + beforeEach(() => { + spyOn(vm, 'commitChanges'); + vm.$store.state.stagedFiles.push('test'); + }); + + it('calls commitChanges', done => { + vm.$store.state.commit.commitMessage = 'testing commit message'; + + getSetTimeoutPromise() + .then(() => { + vm.$el.querySelector('.btn-success').click(); + }) + .then(Vue.nextTick) + .then(() => { + expect(vm.commitChanges).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + }); + }); +}); diff --git a/spec/javascripts/ide/components/commit_sidebar/list_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_spec.js index 62fc3f90ad1..54625ef90f8 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_spec.js @@ -49,45 +49,4 @@ describe('Multi-file editor commit sidebar list', () => { expect(vm.$el.textContent).toContain('No changes'); }); }); - - describe('collapsed', () => { - beforeEach(done => { - vm.$store.state.rightPanelCollapsed = true; - - Vue.nextTick(done); - }); - - it('hides list', () => { - expect(vm.$el.querySelector('.list-unstyled')).toBeNull(); - expect(vm.$el.querySelector('.help-block')).toBeNull(); - }); - }); - - describe('with toggle', () => { - beforeEach(done => { - spyOn(vm, 'toggleRightPanelCollapsed'); - - vm.showToggle = true; - - Vue.nextTick(done); - }); - - it('calls setPanelCollapsedStatus when clickin toggle', () => { - vm.$el.querySelector('.multi-file-commit-panel-collapse-btn').click(); - - expect(vm.toggleRightPanelCollapsed).toHaveBeenCalled(); - }); - }); - - describe('action button', () => { - beforeEach(() => { - spyOn(vm, 'stageAllChanges'); - }); - - it('calls store action when clicked', () => { - vm.$el.querySelector('.ide-staged-action-btn').click(); - - expect(vm.stageAllChanges).toHaveBeenCalled(); - }); - }); }); diff --git a/spec/javascripts/ide/components/ide_context_bar_spec.js b/spec/javascripts/ide/components/ide_context_bar_spec.js deleted file mode 100644 index e17b051f137..00000000000 --- a/spec/javascripts/ide/components/ide_context_bar_spec.js +++ /dev/null @@ -1,37 +0,0 @@ -import Vue from 'vue'; -import store from '~/ide/stores'; -import ideContextBar from '~/ide/components/ide_context_bar.vue'; -import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; - -describe('Multi-file editor right context bar', () => { - let vm; - - beforeEach(() => { - const Component = Vue.extend(ideContextBar); - - vm = createComponentWithStore(Component, store, { - noChangesStateSvgPath: 'svg', - committedStateSvgPath: 'svg', - }); - - vm.$store.state.rightPanelCollapsed = false; - - vm.$mount(); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('collapsed', () => { - beforeEach(done => { - vm.$store.state.rightPanelCollapsed = true; - - Vue.nextTick(done); - }); - - it('adds collapsed class', () => { - expect(vm.$el.querySelector('.is-collapsed')).not.toBeNull(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_external_links_spec.js b/spec/javascripts/ide/components/ide_external_links_spec.js deleted file mode 100644 index 9f6cb459f3b..00000000000 --- a/spec/javascripts/ide/components/ide_external_links_spec.js +++ /dev/null @@ -1,43 +0,0 @@ -import Vue from 'vue'; -import ideExternalLinks from '~/ide/components/ide_external_links.vue'; -import createComponent from 'spec/helpers/vue_mount_component_helper'; - -describe('ide external links component', () => { - let vm; - let fakeReferrer; - let Component; - - const fakeProjectUrl = '/project/'; - - beforeEach(() => { - Component = Vue.extend(ideExternalLinks); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('goBackUrl', () => { - it('renders the Go Back link with the referrer when present', () => { - fakeReferrer = '/example/README.md'; - spyOnProperty(document, 'referrer').and.returnValue(fakeReferrer); - - vm = createComponent(Component, { - projectUrl: fakeProjectUrl, - }).$mount(); - - expect(vm.goBackUrl).toEqual(fakeReferrer); - }); - - it('renders the Go Back link with the project url when referrer is not present', () => { - fakeReferrer = ''; - spyOnProperty(document, 'referrer').and.returnValue(fakeReferrer); - - vm = createComponent(Component, { - projectUrl: fakeProjectUrl, - }).$mount(); - - expect(vm.goBackUrl).toEqual(fakeProjectUrl); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_project_tree_spec.js b/spec/javascripts/ide/components/ide_project_tree_spec.js deleted file mode 100644 index 657682cb39c..00000000000 --- a/spec/javascripts/ide/components/ide_project_tree_spec.js +++ /dev/null @@ -1,39 +0,0 @@ -import Vue from 'vue'; -import ProjectTree from '~/ide/components/ide_project_tree.vue'; -import createComponent from 'spec/helpers/vue_mount_component_helper'; - -describe('IDE project tree', () => { - const Component = Vue.extend(ProjectTree); - let vm; - - beforeEach(() => { - vm = createComponent(Component, { - project: { - id: 1, - name: 'test', - web_url: gl.TEST_HOST, - avatar_url: '', - branches: [], - }, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders identicon when projct has no avatar', () => { - expect(vm.$el.querySelector('.identicon')).not.toBeNull(); - }); - - it('renders avatar image if project has avatar', done => { - vm.project.avatar_url = gl.TEST_HOST; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.identicon')).toBeNull(); - expect(vm.$el.querySelector('img.avatar')).not.toBeNull(); - - done(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_repo_tree_spec.js b/spec/javascripts/ide/components/ide_repo_tree_spec.js deleted file mode 100644 index e0fbc90ca61..00000000000 --- a/spec/javascripts/ide/components/ide_repo_tree_spec.js +++ /dev/null @@ -1,43 +0,0 @@ -import Vue from 'vue'; -import ideRepoTree from '~/ide/components/ide_repo_tree.vue'; -import createComponent from '../../helpers/vue_mount_component_helper'; -import { file } from '../helpers'; - -describe('IdeRepoTree', () => { - let vm; - let tree; - - beforeEach(() => { - const IdeRepoTree = Vue.extend(ideRepoTree); - - tree = { - tree: [file()], - loading: false, - }; - - vm = createComponent(IdeRepoTree, { - tree, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders a sidebar', () => { - expect(vm.$el.querySelector('.loading-file')).toBeNull(); - expect(vm.$el.querySelector('.file')).not.toBeNull(); - }); - - it('renders 3 loading files if tree is loading', done => { - tree.loading = true; - - vm.$nextTick(() => { - expect( - vm.$el.querySelectorAll('.multi-file-loading-container').length, - ).toEqual(3); - - done(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_review_spec.js b/spec/javascripts/ide/components/ide_review_spec.js new file mode 100644 index 00000000000..b9ee22b7c1a --- /dev/null +++ b/spec/javascripts/ide/components/ide_review_spec.js @@ -0,0 +1,69 @@ +import Vue from 'vue'; +import IdeReview from '~/ide/components/ide_review.vue'; +import store from '~/ide/stores'; +import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; +import { trimText } from '../../helpers/vue_component_helper'; +import { resetStore, file } from '../helpers'; +import { projectData } from '../mock_data'; + +describe('IDE review mode', () => { + const Component = Vue.extend(IdeReview); + let vm; + + beforeEach(() => { + store.state.currentProjectId = 'abcproject'; + store.state.currentBranchId = 'master'; + store.state.projects.abcproject = Object.assign({}, projectData); + Vue.set(store.state.trees, 'abcproject/master', { + tree: [file('fileName')], + loading: false, + }); + + vm = createComponentWithStore(Component, store).$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders list of files', () => { + expect(vm.$el.textContent).toContain('fileName'); + }); + + describe('merge request', () => { + beforeEach(done => { + store.state.currentMergeRequestId = '1'; + store.state.projects.abcproject.mergeRequests['1'] = { + iid: 123, + web_url: 'testing123', + }; + + vm.$nextTick(done); + }); + + it('renders edit dropdown', () => { + expect(vm.$el.querySelector('.btn')).not.toBe(null); + }); + + it('renders merge request link & IID', () => { + const link = vm.$el.querySelector('.ide-review-sub-header'); + + expect(link.querySelector('a').getAttribute('href')).toBe('testing123'); + expect(trimText(link.textContent)).toBe('Merge request (!123)'); + }); + + it('changes text to latest changes when viewer is not mrdiff', done => { + store.state.viewer = 'diff'; + + vm.$nextTick(() => { + expect(trimText(vm.$el.querySelector('.ide-review-sub-header').textContent)).toBe( + 'Latest changes', + ); + + done(); + }); + }); + }); +}); diff --git a/spec/javascripts/ide/components/ide_side_bar_spec.js b/spec/javascripts/ide/components/ide_side_bar_spec.js index 699dae1ce2f..20ee20bc1d7 100644 --- a/spec/javascripts/ide/components/ide_side_bar_spec.js +++ b/spec/javascripts/ide/components/ide_side_bar_spec.js @@ -1,8 +1,10 @@ import Vue from 'vue'; import store from '~/ide/stores'; import ideSidebar from '~/ide/components/ide_side_bar.vue'; +import { activityBarViews } from '~/ide/constants'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { resetStore } from '../helpers'; +import { projectData } from '../mock_data'; describe('IdeSidebar', () => { let vm; @@ -10,6 +12,9 @@ describe('IdeSidebar', () => { beforeEach(() => { const Component = Vue.extend(ideSidebar); + store.state.currentProjectId = 'abcproject'; + store.state.projects.abcproject = projectData; + vm = createComponentWithStore(Component, store).$mount(); }); @@ -20,23 +25,33 @@ describe('IdeSidebar', () => { }); it('renders a sidebar', () => { - expect( - vm.$el.querySelector('.multi-file-commit-panel-inner'), - ).not.toBeNull(); + expect(vm.$el.querySelector('.multi-file-commit-panel-inner')).not.toBeNull(); }); it('renders loading icon component', done => { vm.$store.state.loading = true; vm.$nextTick(() => { - expect( - vm.$el.querySelector('.multi-file-loading-container'), - ).not.toBeNull(); - expect( - vm.$el.querySelectorAll('.multi-file-loading-container').length, - ).toBe(3); + expect(vm.$el.querySelector('.multi-file-loading-container')).not.toBeNull(); + expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toBe(3); done(); }); }); + + describe('activityBarComponent', () => { + it('renders tree component', () => { + expect(vm.$el.querySelector('.ide-file-list')).not.toBeNull(); + }); + + it('renders commit component', done => { + vm.$store.state.currentActivityView = activityBarViews.commit; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.multi-file-commit-panel-section')).not.toBeNull(); + + done(); + }); + }); + }); }); diff --git a/spec/javascripts/ide/components/ide_spec.js b/spec/javascripts/ide/components/ide_spec.js index 7bfcfc90572..6f580e1f7af 100644 --- a/spec/javascripts/ide/components/ide_spec.js +++ b/spec/javascripts/ide/components/ide_spec.js @@ -4,6 +4,7 @@ import store from '~/ide/stores'; import ide from '~/ide/components/ide.vue'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { file, resetStore } from '../helpers'; +import { projectData } from '../mock_data'; describe('ide component', () => { let vm; @@ -11,6 +12,10 @@ describe('ide component', () => { beforeEach(() => { const Component = Vue.extend(ide); + store.state.currentProjectId = 'abcproject'; + store.state.currentBranchId = 'master'; + store.state.projects.abcproject = Object.assign({}, projectData); + vm = createComponentWithStore(Component, store, { emptyStateSvgPath: 'svg', noChangesStateSvgPath: 'svg', @@ -24,11 +29,11 @@ describe('ide component', () => { resetStore(vm.$store); }); - it('does not render panel right when no files open', () => { + it('does not render right right when no files open', () => { expect(vm.$el.querySelector('.panel-right')).toBeNull(); }); - it('renders panel right when files are open', done => { + it('renders right panel when files are open', done => { vm.$store.state.trees['abcproject/mybranch'] = { tree: [file()], }; diff --git a/spec/javascripts/ide/components/ide_tree_list_spec.js b/spec/javascripts/ide/components/ide_tree_list_spec.js new file mode 100644 index 00000000000..4ecbdb8a55e --- /dev/null +++ b/spec/javascripts/ide/components/ide_tree_list_spec.js @@ -0,0 +1,54 @@ +import Vue from 'vue'; +import IdeTreeList from '~/ide/components/ide_tree_list.vue'; +import store from '~/ide/stores'; +import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; +import { resetStore, file } from '../helpers'; +import { projectData } from '../mock_data'; + +describe('IDE tree list', () => { + const Component = Vue.extend(IdeTreeList); + let vm; + + beforeEach(() => { + store.state.currentProjectId = 'abcproject'; + store.state.currentBranchId = 'master'; + store.state.projects.abcproject = Object.assign({}, projectData); + Vue.set(store.state.trees, 'abcproject/master', { + tree: [file('fileName')], + loading: false, + }); + + vm = createComponentWithStore(Component, store, { + viewerType: 'edit', + }); + + spyOn(vm, 'updateViewer').and.callThrough(); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('updates viewer on mount', () => { + expect(vm.updateViewer).toHaveBeenCalledWith('edit'); + }); + + it('renders loading indicator', done => { + store.state.trees['abcproject/master'].loading = true; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.multi-file-loading-container')).not.toBeNull(); + expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toBe(3); + + done(); + }); + }); + + it('renders list of files', () => { + expect(vm.$el.textContent).toContain('fileName'); + }); +}); diff --git a/spec/javascripts/ide/components/ide_tree_spec.js b/spec/javascripts/ide/components/ide_tree_spec.js new file mode 100644 index 00000000000..97a0a2432f1 --- /dev/null +++ b/spec/javascripts/ide/components/ide_tree_spec.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import IdeTree from '~/ide/components/ide_tree.vue'; +import store from '~/ide/stores'; +import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; +import { resetStore, file } from '../helpers'; +import { projectData } from '../mock_data'; + +describe('IdeRepoTree', () => { + let vm; + + beforeEach(() => { + const IdeRepoTree = Vue.extend(IdeTree); + + store.state.currentProjectId = 'abcproject'; + store.state.currentBranchId = 'master'; + store.state.projects.abcproject = Object.assign({}, projectData); + Vue.set(store.state.trees, 'abcproject/master', { + tree: [file('fileName')], + loading: false, + }); + + vm = createComponentWithStore(IdeRepoTree, store).$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders list of files', () => { + expect(vm.$el.textContent).toContain('fileName'); + }); +}); diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js index 768f6e99bf1..5e3e00a180b 100644 --- a/spec/javascripts/ide/components/repo_commit_section_spec.js +++ b/spec/javascripts/ide/components/repo_commit_section_spec.js @@ -1,9 +1,9 @@ import Vue from 'vue'; import store from '~/ide/stores'; import service from '~/ide/services'; +import router from '~/ide/ide_router'; import repoCommitSection from '~/ide/components/repo_commit_section.vue'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; import { file, resetStore } from '../helpers'; describe('RepoCommitSection', () => { @@ -12,10 +12,10 @@ describe('RepoCommitSection', () => { function createComponent() { const Component = Vue.extend(repoCommitSection); - vm = createComponentWithStore(Component, store, { - noChangesStateSvgPath: 'svg', - committedStateSvgPath: 'commitsvg', - }); + store.state.noChangesStateSvgPath = 'svg'; + store.state.committedStateSvgPath = 'commitsvg'; + + vm = createComponentWithStore(Component, store); vm.$store.state.currentProjectId = 'abcproject'; vm.$store.state.currentBranchId = 'master'; @@ -60,6 +60,8 @@ describe('RepoCommitSection', () => { } beforeEach(done => { + spyOn(router, 'push'); + vm = createComponent(); spyOn(service, 'getTreeData').and.returnValue( @@ -93,61 +95,49 @@ describe('RepoCommitSection', () => { resetStore(vm.$store); const Component = Vue.extend(repoCommitSection); - vm = createComponentWithStore(Component, store, { - noChangesStateSvgPath: 'nochangessvg', - committedStateSvgPath: 'svg', - }).$mount(); + store.state.noChangesStateSvgPath = 'nochangessvg'; + store.state.committedStateSvgPath = 'svg'; - expect( - vm.$el.querySelector('.js-empty-state').textContent.trim(), - ).toContain('No changes'); - expect( - vm.$el.querySelector('.js-empty-state img').getAttribute('src'), - ).toBe('nochangessvg'); + vm = createComponentWithStore(Component, store).$mount(); + + expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toContain('No changes'); + expect(vm.$el.querySelector('.js-empty-state img').getAttribute('src')).toBe('nochangessvg'); }); }); it('renders a commit section', () => { - const changedFileElements = [ - ...vm.$el.querySelectorAll('.multi-file-commit-list li'), - ]; - const submitCommit = vm.$el.querySelector('form .btn'); - const allFiles = vm.$store.state.changedFiles.concat( - vm.$store.state.stagedFiles, - ); + const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list li')]; + const allFiles = vm.$store.state.changedFiles.concat(vm.$store.state.stagedFiles); - expect(vm.$el.querySelector('.multi-file-commit-form')).not.toBeNull(); expect(changedFileElements.length).toEqual(4); changedFileElements.forEach((changedFile, i) => { expect(changedFile.textContent.trim()).toContain(allFiles[i].path); }); - - expect(submitCommit.disabled).toBeTruthy(); - expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeNull(); }); it('adds changed files into staged files', done => { - vm.$el.querySelector('.ide-staged-action-btn').click(); - - Vue.nextTick(() => { - expect( - vm.$el.querySelector('.ide-commit-list-container').textContent, - ).toContain('No changes'); - - done(); - }); + vm.$el.querySelector('.multi-file-discard-btn .btn').click(); + vm + .$nextTick() + .then(() => vm.$el.querySelector('.multi-file-discard-btn .btn').click()) + .then(vm.$nextTick) + .then(() => { + expect(vm.$el.querySelector('.ide-commit-list-container').textContent).toContain( + 'No changes', + ); + }) + .then(done) + .catch(done.fail); }); it('stages a single file', done => { vm.$el.querySelector('.multi-file-discard-btn .btn').click(); Vue.nextTick(() => { - expect( - vm.$el - .querySelector('.ide-commit-list-container') - .querySelectorAll('li').length, - ).toBe(1); + expect(vm.$el.querySelector('.ide-commit-list-container').querySelectorAll('li').length).toBe( + 1, + ); done(); }); @@ -157,26 +147,10 @@ describe('RepoCommitSection', () => { vm.$el.querySelectorAll('.multi-file-discard-btn .btn')[1].click(); Vue.nextTick(() => { - expect( - vm.$el.querySelector('.ide-commit-list-container').textContent, - ).not.toContain('file1'); - expect( - vm.$el - .querySelector('.ide-commit-list-container') - .querySelectorAll('li').length, - ).toBe(1); - - done(); - }); - }); - - it('removes all staged files', done => { - vm.$el.querySelectorAll('.ide-staged-action-btn')[1].click(); - - Vue.nextTick(() => { - expect( - vm.$el.querySelectorAll('.ide-commit-list-container')[1].textContent, - ).toContain('No changes'); + expect(vm.$el.querySelector('.ide-commit-list-container').textContent).not.toContain('file1'); + expect(vm.$el.querySelector('.ide-commit-list-container').querySelectorAll('li').length).toBe( + 1, + ); done(); }); @@ -190,75 +164,17 @@ describe('RepoCommitSection', () => { Vue.nextTick(() => { expect( - vm.$el - .querySelectorAll('.ide-commit-list-container')[1] - .querySelectorAll('li').length, + vm.$el.querySelectorAll('.ide-commit-list-container')[1].querySelectorAll('li').length, ).toBe(1); done(); }); }); - it('updates commitMessage in store on input', done => { - const textarea = vm.$el.querySelector('textarea'); - - textarea.value = 'testing commit message'; - - textarea.dispatchEvent(new Event('input')); - - getSetTimeoutPromise() - .then(() => { - expect(vm.$store.state.commit.commitMessage).toBe( - 'testing commit message', - ); - }) - .then(done) - .catch(done.fail); - }); - - describe('discard draft button', () => { - it('hidden when commitMessage is empty', () => { - expect( - vm.$el.querySelector('.multi-file-commit-form .btn-default'), - ).toBeNull(); - }); - - it('resets commitMessage when clicking discard button', done => { - vm.$store.state.commit.commitMessage = 'testing commit message'; - - getSetTimeoutPromise() - .then(() => { - vm.$el.querySelector('.multi-file-commit-form .btn-default').click(); - }) - .then(Vue.nextTick) - .then(() => { - expect(vm.$store.state.commit.commitMessage).not.toBe( - 'testing commit message', - ); - }) - .then(done) - .catch(done.fail); - }); - }); - - describe('when submitting', () => { - beforeEach(() => { - spyOn(vm, 'commitChanges'); - }); - - it('calls commitChanges', done => { - vm.$store.state.commit.commitMessage = 'testing commit message'; - - getSetTimeoutPromise() - .then(() => { - vm.$el.querySelector('.multi-file-commit-form .btn-success').click(); - }) - .then(Vue.nextTick) - .then(() => { - expect(vm.commitChanges).toHaveBeenCalled(); - }) - .then(done) - .catch(done.fail); + describe('mounted', () => { + it('opens last opened file', () => { + expect(store.state.openFiles.length).toBe(1); + expect(store.state.openFiles[0].pending).toBe(true); }); }); }); diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js index b06a6c62a1c..360b6d4dc15 100644 --- a/spec/javascripts/ide/components/repo_editor_spec.js +++ b/spec/javascripts/ide/components/repo_editor_spec.js @@ -5,6 +5,7 @@ import store from '~/ide/stores'; import repoEditor from '~/ide/components/repo_editor.vue'; import monacoLoader from '~/ide/monaco_loader'; import Editor from '~/ide/lib/editor'; +import { activityBarViews } from '~/ide/constants'; import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import setTimeoutPromise from '../../helpers/set_timeout_promise_helper'; import { file, resetStore } from '../helpers'; @@ -295,4 +296,30 @@ describe('RepoEditor', () => { }); }); }); + + describe('show tabs', () => { + it('shows tabs in edit mode', () => { + expect(vm.$el.querySelector('.nav-links')).not.toBe(null); + }); + + it('hides tabs in review mode', done => { + vm.$store.state.currentActivityView = activityBarViews.review; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.nav-links')).toBe(null); + + done(); + }); + }); + + it('hides tabs in commit mode', done => { + vm.$store.state.currentActivityView = activityBarViews.commit; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.nav-links')).toBe(null); + + done(); + }); + }); + }); }); diff --git a/spec/javascripts/ide/components/repo_file_spec.js b/spec/javascripts/ide/components/repo_file_spec.js index 28ff06e1f80..156233653ab 100644 --- a/spec/javascripts/ide/components/repo_file_spec.js +++ b/spec/javascripts/ide/components/repo_file_spec.js @@ -73,6 +73,43 @@ describe('RepoFile', () => { expect(treeChangesEl).not.toBeNull(); expect(treeChangesEl.textContent).toContain('1'); }); + + it('renders action dropdown', done => { + createComponent({ + file: { + ...file('t4'), + type: 'tree', + branchId: 'master', + projectId: 'project', + }, + level: 0, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.ide-new-btn')).not.toBeNull(); + + done(); + }); + }); + + it('disables action dropdown', done => { + createComponent({ + file: { + ...file('t4'), + type: 'tree', + branchId: 'master', + projectId: 'project', + }, + level: 0, + disableActionDropdown: true, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.ide-new-btn')).toBeNull(); + + done(); + }); + }); }); describe('locked file', () => { diff --git a/spec/javascripts/ide/components/repo_tabs_spec.js b/spec/javascripts/ide/components/repo_tabs_spec.js index cb785ba2cd3..583f71e6121 100644 --- a/spec/javascripts/ide/components/repo_tabs_spec.js +++ b/spec/javascripts/ide/components/repo_tabs_spec.js @@ -26,60 +26,10 @@ describe('RepoTabs', () => { const tabs = [...vm.$el.querySelectorAll('.multi-file-tab')]; expect(tabs.length).toEqual(2); - expect(tabs[0].classList.contains('active')).toEqual(true); - expect(tabs[1].classList.contains('active')).toEqual(false); + expect(tabs[0].parentNode.classList.contains('active')).toEqual(true); + expect(tabs[1].parentNode.classList.contains('active')).toEqual(false); done(); }); }); - - describe('updated', () => { - it('sets showShadow as true when scroll width is larger than width', done => { - const el = document.createElement('div'); - el.innerHTML = '<div id="test-app"></div>'; - document.body.appendChild(el); - - const style = document.createElement('style'); - style.innerText = ` - .multi-file-tabs { - width: 100px; - } - - .multi-file-tabs .list-unstyled { - display: flex; - overflow-x: auto; - } - `; - document.head.appendChild(style); - - vm = createComponent( - RepoTabs, - { - files: [], - viewer: 'editor', - hasChanges: false, - activeFile: file('activeFile'), - hasMergeRequest: false, - }, - '#test-app', - ); - - vm - .$nextTick() - .then(() => { - expect(vm.showShadow).toEqual(false); - - vm.files = openedFiles; - }) - .then(vm.$nextTick) - .then(() => { - expect(vm.showShadow).toEqual(true); - - style.remove(); - el.remove(); - }) - .then(done) - .catch(done.fail); - }); - }); }); diff --git a/spec/javascripts/ide/lib/editor_spec.js b/spec/javascripts/ide/lib/editor_spec.js index 530bdfa2759..b88a12264ca 100644 --- a/spec/javascripts/ide/lib/editor_spec.js +++ b/spec/javascripts/ide/lib/editor_spec.js @@ -74,10 +74,10 @@ describe('Multi-file editor library', () => { scrollBeyondLastLine: false, quickSuggestions: false, occurrencesHighlight: false, - renderLineHighlight: 'none', - hideCursorInOverviewRuler: true, wordWrap: 'on', renderSideBySide: true, + renderLineHighlight: 'all', + hideCursorInOverviewRuler: false, }); }); }); diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js new file mode 100644 index 00000000000..3c6d75ab5e4 --- /dev/null +++ b/spec/javascripts/ide/mock_data.js @@ -0,0 +1,15 @@ +// eslint-disable-next-line import/prefer-default-export +export const projectData = { + id: 1, + name: 'abcproject', + web_url: '', + avatar_url: '', + path: '', + name_with_namespace: 'namespace/abcproject', + branches: { + master: { + treeId: 'abcproject/master', + }, + }, + mergeRequests: {}, +}; diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js index 3ee11bd2f03..3ef5a859001 100644 --- a/spec/javascripts/ide/stores/actions/file_spec.js +++ b/spec/javascripts/ide/stores/actions/file_spec.js @@ -511,7 +511,10 @@ describe('IDE store file actions', () => { actions.stageChange, 'path', store.state, - [{ type: types.STAGE_CHANGE, payload: 'path' }], + [ + { type: types.STAGE_CHANGE, payload: 'path' }, + { type: types.SET_LAST_COMMIT_MSG, payload: '' }, + ], [], done, ); @@ -524,7 +527,10 @@ describe('IDE store file actions', () => { actions.unstageChange, 'path', store.state, - [{ type: types.UNSTAGE_CHANGE, payload: 'path' }], + [ + { type: types.UNSTAGE_CHANGE, payload: 'path' }, + { type: types.SET_LAST_COMMIT_MSG, payload: '' }, + ], [], done, ); @@ -589,20 +595,6 @@ describe('IDE store file actions', () => { .then(done) .catch(done.fail); }); - - it('returns false when passed in file is active & viewer is diff', done => { - f.active = true; - store.state.openFiles.push(f); - store.state.viewer = 'diff'; - - store - .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) - .then(added => { - expect(added).toBe(false); - }) - .then(done) - .catch(done.fail); - }); }); describe('removePendingTab', () => { diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js index a64af5b941b..062c3497623 100644 --- a/spec/javascripts/ide/stores/actions_spec.js +++ b/spec/javascripts/ide/stores/actions_spec.js @@ -2,6 +2,9 @@ import actions, { stageAllChanges, unstageAllChanges, toggleFileFinder, + setCurrentBranchId, + setEmptyStateSvgs, + updateActivityBarView, updateTempFlagForEntry, } from '~/ide/stores/actions'; import store from '~/ide/stores'; @@ -306,6 +309,7 @@ describe('Multi-file store actions', () => { null, store.state, [ + { type: types.SET_LAST_COMMIT_MSG, payload: '' }, { type: types.STAGE_CHANGE, payload: store.state.changedFiles[0].path }, { type: types.STAGE_CHANGE, payload: store.state.changedFiles[1].path }, ], @@ -345,6 +349,32 @@ describe('Multi-file store actions', () => { }); }); + describe('updateActivityBarView', () => { + it('commits UPDATE_ACTIVITY_BAR_VIEW', done => { + testAction( + updateActivityBarView, + 'test', + {}, + [{ type: 'UPDATE_ACTIVITY_BAR_VIEW', payload: 'test' }], + [], + done, + ); + }); + }); + + describe('setEmptyStateSvgs', () => { + it('commits setEmptyStateSvgs', done => { + testAction( + setEmptyStateSvgs, + 'svg', + {}, + [{ type: 'SET_EMPTY_STATE_SVGS', payload: 'svg' }], + [], + done, + ); + }); + }); + describe('updateTempFlagForEntry', () => { it('commits UPDATE_TEMP_FLAG', done => { const f = { @@ -388,6 +418,19 @@ describe('Multi-file store actions', () => { }); }); + describe('setCurrentBranchId', () => { + it('commits setCurrentBranchId', done => { + testAction( + setCurrentBranchId, + 'branchId', + {}, + [{ type: 'SET_CURRENT_BRANCH', payload: 'branchId' }], + [], + done, + ); + }); + }); + describe('toggleFileFinder', () => { it('commits TOGGLE_FILE_FINDER', done => { testAction( diff --git a/spec/javascripts/ide/stores/getters_spec.js b/spec/javascripts/ide/stores/getters_spec.js index bd834443730..67a848e8edd 100644 --- a/spec/javascripts/ide/stores/getters_spec.js +++ b/spec/javascripts/ide/stores/getters_spec.js @@ -37,12 +37,6 @@ describe('IDE store getters', () => { expect(modifiedFiles.length).toBe(1); expect(modifiedFiles[0].name).toBe('changed'); }); - - it('returns angle left when collapsed', () => { - localState.rightPanelCollapsed = true; - - expect(getters.collapseButtonIcon(localState)).toBe('angle-double-left'); - }); }); describe('currentMergeRequest', () => { diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js index b2b4b85ca42..a2869ff378b 100644 --- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js @@ -289,21 +289,6 @@ describe('IDE commit module actions', () => { .then(done) .catch(done.fail); }); - - it('pushes route to new branch if commitAction is new branch', done => { - store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH; - - store - .dispatch('commit/updateFilesAfterCommit', { - data, - branch, - }) - .then(() => { - expect(router.push).toHaveBeenCalledWith(`/project/abcproject/blob/master/${f.path}`); - }) - .then(done) - .catch(done.fail); - }); }); describe('commitChanges', () => { @@ -391,21 +376,6 @@ describe('IDE commit module actions', () => { .catch(done.fail); }); - it('pushes router to new route', done => { - store - .dispatch('commit/commitChanges') - .then(() => { - expect(router.push).toHaveBeenCalledWith( - `/project/${store.state.currentProjectId}/blob/${ - store.getters['commit/newBranchName'] - }/changed`, - ); - - done(); - }) - .catch(done.fail); - }); - it('sets last Commit Msg', done => { store .dispatch('commit/commitChanges') diff --git a/spec/javascripts/ide/stores/mutations/file_spec.js b/spec/javascripts/ide/stores/mutations/file_spec.js index 6fba934810d..e83961fcedc 100644 --- a/spec/javascripts/ide/stores/mutations/file_spec.js +++ b/spec/javascripts/ide/stores/mutations/file_spec.js @@ -267,41 +267,23 @@ describe('IDE store file mutations', () => { it('adds file into openFiles as pending', () => { mutations.ADD_PENDING_TAB(localState, { file: localFile }); - expect(localState.openFiles.length).toBe(2); - expect(localState.openFiles[1].pending).toBe(true); - expect(localState.openFiles[1].key).toBe(`pending-${localFile.key}`); - }); - - it('updates open file to pending', () => { - mutations.ADD_PENDING_TAB(localState, { file: localState.openFiles[0] }); - expect(localState.openFiles.length).toBe(1); + expect(localState.openFiles[0].pending).toBe(true); + expect(localState.openFiles[0].key).toBe(`pending-${localFile.key}`); }); - it('updates pending open file to active', () => { - localState.openFiles.push({ - ...localFile, - pending: true, - }); + it('only allows 1 open pending file', () => { + const newFile = file('test'); + localState.entries[newFile.path] = newFile; mutations.ADD_PENDING_TAB(localState, { file: localFile }); - expect(localState.openFiles[1].pending).toBe(true); - expect(localState.openFiles[1].active).toBe(true); - }); - - it('sets all openFiles to not active', () => { - mutations.ADD_PENDING_TAB(localState, { file: localFile }); + expect(localState.openFiles.length).toBe(1); - expect(localState.openFiles.length).toBe(2); + mutations.ADD_PENDING_TAB(localState, { file: file('test') }); - localState.openFiles.forEach(f => { - if (f.pending) { - expect(f.active).toBe(true); - } else { - expect(f.active).toBe(false); - } - }); + expect(localState.openFiles.length).toBe(1); + expect(localState.openFiles[0].name).toBe('test'); }); }); diff --git a/spec/javascripts/ide/stores/mutations_spec.js b/spec/javascripts/ide/stores/mutations_spec.js index 61efb6372c9..972713c5ad2 100644 --- a/spec/javascripts/ide/stores/mutations_spec.js +++ b/spec/javascripts/ide/stores/mutations_spec.js @@ -87,6 +87,28 @@ describe('Multi-file store mutations', () => { }); }); + describe('UPDATE_ACTIVITY_BAR_VIEW', () => { + it('updates currentActivityBar', () => { + mutations.UPDATE_ACTIVITY_BAR_VIEW(localState, 'test'); + + expect(localState.currentActivityView).toBe('test'); + }); + }); + + describe('SET_EMPTY_STATE_SVGS', () => { + it('updates empty state SVGs', () => { + mutations.SET_EMPTY_STATE_SVGS(localState, { + emptyStateSvgPath: 'emptyState', + noChangesStateSvgPath: 'noChanges', + committedStateSvgPath: 'commited', + }); + + expect(localState.emptyStateSvgPath).toBe('emptyState'); + expect(localState.noChangesStateSvgPath).toBe('noChanges'); + expect(localState.committedStateSvgPath).toBe('commited'); + }); + }); + describe('UPDATE_TEMP_FLAG', () => { beforeEach(() => { localState.entries.test = { |