diff options
Diffstat (limited to 'spec/javascripts/repo/components')
16 files changed, 792 insertions, 681 deletions
diff --git a/spec/javascripts/repo/components/new_branch_form_spec.js b/spec/javascripts/repo/components/new_branch_form_spec.js index c9c5ce096fc..9a705a1f0ed 100644 --- a/spec/javascripts/repo/components/new_branch_form_spec.js +++ b/spec/javascripts/repo/components/new_branch_form_spec.js @@ -1,8 +1,8 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import newBranchForm from '~/repo/components/new_branch_form.vue'; -import eventHub from '~/repo/event_hub'; -import RepoStore from '~/repo/stores/repo_store'; -import createComponent from '../../helpers/vue_mount_component_helper'; +import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; +import { resetStore } from '../helpers'; describe('Multi-file editor new branch form', () => { let vm; @@ -10,17 +10,17 @@ describe('Multi-file editor new branch form', () => { beforeEach(() => { const Component = Vue.extend(newBranchForm); - RepoStore.currentBranch = 'master'; + vm = createComponentWithStore(Component, store); - vm = createComponent(Component, { - currentBranch: RepoStore.currentBranch, - }); + vm.$store.state.currentBranch = 'master'; + + vm.$mount(); }); afterEach(() => { vm.$destroy(); - RepoStore.currentBranch = ''; + resetStore(vm.$store); }); describe('template', () => { @@ -48,6 +48,10 @@ describe('Multi-file editor new branch form', () => { }); describe('submitNewBranch', () => { + beforeEach(() => { + spyOn(vm, 'createNewBranch').and.returnValue(Promise.resolve()); + }); + it('sets to loading', () => { vm.submitNewBranch(); @@ -66,57 +70,45 @@ describe('Multi-file editor new branch form', () => { }); }); - it('emits an event with branchName', () => { - spyOn(eventHub, '$emit'); - + it('calls createdNewBranch with branchName', () => { vm.branchName = 'testing'; vm.submitNewBranch(); - expect(eventHub.$emit).toHaveBeenCalledWith('createNewBranch', 'testing'); + expect(vm.createNewBranch).toHaveBeenCalledWith('testing'); }); }); - describe('showErrorMessage', () => { - it('sets loading to false', () => { - vm.loading = true; - - vm.showErrorMessage(); - - expect(vm.loading).toBeFalsy(); - }); - - it('creates flash element', () => { - vm.showErrorMessage('error message'); - - expect(vm.$el.querySelector('.flash-alert')).not.toBeNull(); - expect(vm.$el.querySelector('.flash-alert').textContent.trim()).toBe('error message'); + describe('submitNewBranch with error', () => { + beforeEach(() => { + spyOn(vm, 'createNewBranch').and.returnValue(Promise.reject({ + json: () => Promise.resolve({ + message: 'error message', + }), + })); }); - }); - describe('createdNewBranch', () => { - it('set loading to false', () => { + it('sets loading to false', (done) => { vm.loading = true; - vm.createdNewBranch(); - - expect(vm.loading).toBeFalsy(); - }); - - it('resets branch name', () => { - vm.branchName = 'testing'; + vm.submitNewBranch(); - vm.createdNewBranch(); + setTimeout(() => { + expect(vm.loading).toBeFalsy(); - expect(vm.branchName).toBe(''); + done(); + }); }); - it('sets the dropdown toggle text', () => { - vm.dropdownText = document.createElement('span'); + it('creates flash element', (done) => { + vm.submitNewBranch(); - vm.createdNewBranch('branch name'); + setTimeout(() => { + expect(vm.$el.querySelector('.flash-alert')).not.toBeNull(); + expect(vm.$el.querySelector('.flash-alert').textContent.trim()).toBe('error message'); - expect(vm.dropdownText.textContent).toBe('branch name'); + done(); + }); }); }); }); diff --git a/spec/javascripts/repo/components/new_dropdown/index_spec.js b/spec/javascripts/repo/components/new_dropdown/index_spec.js new file mode 100644 index 00000000000..93b10fc1fee --- /dev/null +++ b/spec/javascripts/repo/components/new_dropdown/index_spec.js @@ -0,0 +1,71 @@ +import Vue from 'vue'; +import store from '~/repo/stores'; +import newDropdown from '~/repo/components/new_dropdown/index.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { resetStore } from '../../helpers'; + +describe('new dropdown component', () => { + let vm; + + beforeEach(() => { + const component = Vue.extend(newDropdown); + + vm = createComponentWithStore(component, store); + + vm.$store.state.path = ''; + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders new file and new directory links', () => { + expect(vm.$el.querySelectorAll('a')[0].textContent.trim()).toBe('New file'); + expect(vm.$el.querySelectorAll('a')[1].textContent.trim()).toBe('New directory'); + }); + + describe('createNewItem', () => { + it('sets modalType to blob when new file is clicked', () => { + vm.$el.querySelectorAll('a')[0].click(); + + expect(vm.modalType).toBe('blob'); + }); + + it('sets modalType to tree when new directory is clicked', () => { + vm.$el.querySelectorAll('a')[1].click(); + + expect(vm.modalType).toBe('tree'); + }); + + it('opens modal when link is clicked', (done) => { + vm.$el.querySelectorAll('a')[0].click(); + + Vue.nextTick(() => { + expect(vm.$el.querySelector('.modal')).not.toBeNull(); + + done(); + }); + }); + }); + + describe('toggleModalOpen', () => { + it('closes modal after toggling', (done) => { + vm.toggleModalOpen(); + + Vue.nextTick() + .then(() => { + expect(vm.$el.querySelector('.modal')).not.toBeNull(); + }) + .then(vm.toggleModalOpen) + .then(() => { + expect(vm.$el.querySelector('.modal')).toBeNull(); + }) + .then(done) + .catch(done.fail); + }); + }); +}); diff --git a/spec/javascripts/repo/components/new_dropdown/modal_spec.js b/spec/javascripts/repo/components/new_dropdown/modal_spec.js new file mode 100644 index 00000000000..1ff7590ec79 --- /dev/null +++ b/spec/javascripts/repo/components/new_dropdown/modal_spec.js @@ -0,0 +1,198 @@ +import Vue from 'vue'; +import store from '~/repo/stores'; +import modal from '~/repo/components/new_dropdown/modal.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { file, resetStore } from '../../helpers'; + +describe('new file modal component', () => { + const Component = Vue.extend(modal); + let vm; + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + ['tree', 'blob'].forEach((type) => { + describe(type, () => { + beforeEach(() => { + vm = createComponentWithStore(Component, store, { + type, + path: '', + }).$mount(); + + vm.entryName = 'testing'; + }); + + it(`sets modal title as ${type}`, () => { + const title = type === 'tree' ? 'directory' : 'file'; + + expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Create new ${title}`); + }); + + it(`sets button label as ${type}`, () => { + const title = type === 'tree' ? 'directory' : 'file'; + + expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Create ${title}`); + }); + + it(`sets form label as ${type}`, () => { + const title = type === 'tree' ? 'Directory' : 'File'; + + expect(vm.$el.querySelector('.label-light').textContent.trim()).toBe(`${title} name`); + }); + + describe('createEntryInStore', () => { + it('calls createTempEntry', () => { + spyOn(vm, 'createTempEntry'); + + vm.createEntryInStore(); + + expect(vm.createTempEntry).toHaveBeenCalledWith({ + name: 'testing', + type, + }); + }); + + it('sets editMode to true', (done) => { + vm.createEntryInStore(); + + setTimeout(() => { + expect(vm.$store.state.editMode).toBeTruthy(); + + done(); + }); + }); + + it('toggles blob view', (done) => { + vm.createEntryInStore(); + + setTimeout(() => { + expect(vm.$store.state.currentBlobView).toBe('repo-editor'); + + done(); + }); + }); + + it('opens newly created file', (done) => { + vm.createEntryInStore(); + + setTimeout(() => { + expect(vm.$store.state.openFiles.length).toBe(1); + expect(vm.$store.state.openFiles[0].name).toBe(type === 'blob' ? 'testing' : '.gitkeep'); + + done(); + }); + }); + + it(`creates ${type} in the current stores path`, (done) => { + vm.$store.state.path = 'app'; + + vm.createEntryInStore(); + + setTimeout(() => { + expect(vm.$store.state.tree[0].path).toBe('app/testing'); + expect(vm.$store.state.tree[0].name).toBe('testing'); + + if (type === 'tree') { + expect(vm.$store.state.tree[0].tree.length).toBe(1); + } + + done(); + }); + }); + + if (type === 'blob') { + it('creates new file', (done) => { + vm.createEntryInStore(); + + setTimeout(() => { + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe('testing'); + expect(vm.$store.state.tree[0].type).toBe('blob'); + expect(vm.$store.state.tree[0].tempFile).toBeTruthy(); + + done(); + }); + }); + + it('does not create temp file when file already exists', (done) => { + vm.$store.state.tree.push(file('testing', '1', type)); + + vm.createEntryInStore(); + + setTimeout(() => { + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe('testing'); + expect(vm.$store.state.tree[0].type).toBe('blob'); + expect(vm.$store.state.tree[0].tempFile).toBeFalsy(); + + done(); + }); + }); + } else { + it('creates new tree', () => { + vm.createEntryInStore(); + + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe('testing'); + expect(vm.$store.state.tree[0].type).toBe('tree'); + expect(vm.$store.state.tree[0].tempFile).toBeTruthy(); + expect(vm.$store.state.tree[0].tree.length).toBe(1); + expect(vm.$store.state.tree[0].tree[0].name).toBe('.gitkeep'); + }); + + it('creates multiple trees when entryName has slashes', () => { + vm.entryName = 'app/test'; + vm.createEntryInStore(); + + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe('app'); + expect(vm.$store.state.tree[0].tree[0].name).toBe('test'); + expect(vm.$store.state.tree[0].tree[0].tree[0].name).toBe('.gitkeep'); + }); + + it('creates tree in existing tree', () => { + vm.$store.state.tree.push(file('app', '1', 'tree')); + + vm.entryName = 'app/test'; + vm.createEntryInStore(); + + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe('app'); + expect(vm.$store.state.tree[0].tempFile).toBeFalsy(); + expect(vm.$store.state.tree[0].tree[0].tempFile).toBeTruthy(); + expect(vm.$store.state.tree[0].tree[0].name).toBe('test'); + expect(vm.$store.state.tree[0].tree[0].tree[0].name).toBe('.gitkeep'); + }); + + it('does not create new tree when already exists', () => { + vm.$store.state.tree.push(file('app', '1', 'tree')); + + vm.entryName = 'app'; + vm.createEntryInStore(); + + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe('app'); + expect(vm.$store.state.tree[0].tempFile).toBeFalsy(); + expect(vm.$store.state.tree[0].tree.length).toBe(0); + }); + } + }); + }); + }); + + it('focuses field on mount', () => { + document.body.innerHTML += '<div class="js-test"></div>'; + + vm = createComponentWithStore(Component, store, { + type: 'tree', + path: '', + }).$mount('.js-test'); + + expect(document.activeElement).toBe(vm.$refs.fieldName); + + vm.$el.remove(); + }); +}); diff --git a/spec/javascripts/repo/components/new_dropdown/upload_spec.js b/spec/javascripts/repo/components/new_dropdown/upload_spec.js new file mode 100644 index 00000000000..bf7893029b1 --- /dev/null +++ b/spec/javascripts/repo/components/new_dropdown/upload_spec.js @@ -0,0 +1,103 @@ +import Vue from 'vue'; +import upload from '~/repo/components/new_dropdown/upload.vue'; +import store from '~/repo/stores'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { resetStore } from '../../helpers'; + +describe('new dropdown upload', () => { + let vm; + + beforeEach(() => { + const Component = Vue.extend(upload); + + vm = createComponentWithStore(Component, store, { + path: '', + }); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + describe('readFile', () => { + beforeEach(() => { + spyOn(FileReader.prototype, 'readAsText'); + spyOn(FileReader.prototype, 'readAsDataURL'); + }); + + it('calls readAsText for text files', () => { + const file = { + type: 'text/html', + }; + + vm.readFile(file); + + expect(FileReader.prototype.readAsText).toHaveBeenCalledWith(file); + }); + + it('calls readAsDataURL for non-text files', () => { + const file = { + type: 'images/png', + }; + + vm.readFile(file); + + expect(FileReader.prototype.readAsDataURL).toHaveBeenCalledWith(file); + }); + }); + + describe('createFile', () => { + const target = { + result: 'content', + }; + const binaryTarget = { + result: 'base64,base64content', + }; + const file = { + name: 'file', + }; + + it('creates new file', (done) => { + vm.createFile(target, file, true); + + vm.$nextTick(() => { + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe(file.name); + expect(vm.$store.state.tree[0].content).toBe(target.result); + + done(); + }); + }); + + it('creates new file in path', (done) => { + vm.$store.state.path = 'testing'; + vm.createFile(target, file, true); + + vm.$nextTick(() => { + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe(file.name); + expect(vm.$store.state.tree[0].content).toBe(target.result); + expect(vm.$store.state.tree[0].path).toBe(`testing/${file.name}`); + + done(); + }); + }); + + it('splits content on base64 if binary', (done) => { + vm.createFile(binaryTarget, file, false); + + vm.$nextTick(() => { + expect(vm.$store.state.tree.length).toBe(1); + expect(vm.$store.state.tree[0].name).toBe(file.name); + expect(vm.$store.state.tree[0].content).toBe(binaryTarget.result.split('base64,')[1]); + expect(vm.$store.state.tree[0].base64).toBe(true); + + done(); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_commit_section_spec.js b/spec/javascripts/repo/components/repo_commit_section_spec.js index e09d593f04c..0f991e1b727 100644 --- a/spec/javascripts/repo/components/repo_commit_section_spec.js +++ b/spec/javascripts/repo/components/repo_commit_section_spec.js @@ -1,56 +1,43 @@ import Vue from 'vue'; +import store from '~/repo/stores'; +import service from '~/repo/services'; import repoCommitSection from '~/repo/components/repo_commit_section.vue'; -import RepoStore from '~/repo/stores/repo_store'; -import RepoService from '~/repo/services/repo_service'; import getSetTimeoutPromise from '../../helpers/set_timeout_promise_helper'; +import { file, resetStore } from '../helpers'; describe('RepoCommitSection', () => { - const branch = 'master'; - const projectUrl = 'projectUrl'; - let changedFiles; - let openedFiles; + let vm; - RepoStore.projectUrl = projectUrl; - - function createComponent(el) { + function createComponent() { const RepoCommitSection = Vue.extend(repoCommitSection); - return new RepoCommitSection().$mount(el); + const comp = new RepoCommitSection({ + store, + }).$mount(); + + comp.$store.state.currentBranch = 'master'; + comp.$store.state.openFiles = [file(), file()]; + comp.$store.state.openFiles.forEach(f => Object.assign(f, { + changed: true, + content: 'testing', + })); + + return comp.$mount(); } beforeEach(() => { - // Create a copy for each test because these can get modified directly - changedFiles = [{ - id: 0, - changed: true, - url: `/namespace/${projectUrl}/blob/${branch}/dir/file0.ext`, - path: 'dir/file0.ext', - newContent: 'a', - }, { - id: 1, - changed: true, - url: `/namespace/${projectUrl}/blob/${branch}/dir/file1.ext`, - path: 'dir/file1.ext', - newContent: 'b', - }]; - openedFiles = changedFiles.concat([{ - id: 2, - url: `/namespace/${projectUrl}/blob/${branch}/dir/file2.ext`, - path: 'dir/file2.ext', - changed: false, - }]); + vm = createComponent(); }); - it('renders a commit section', () => { - RepoStore.isCommitable = true; - RepoStore.currentBranch = branch; - RepoStore.targetBranch = branch; - RepoStore.openedFiles = openedFiles; + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); - const vm = createComponent(); + it('renders a commit section', () => { const changedFileElements = [...vm.$el.querySelectorAll('.changed-files > li')]; - const commitMessage = vm.$el.querySelector('#commit-message'); - const submitCommit = vm.$refs.submitCommit; + const submitCommit = vm.$el.querySelector('.btn'); const targetBranch = vm.$el.querySelector('.target-branch'); expect(vm.$el.querySelector(':scope > form')).toBeTruthy(); @@ -58,160 +45,70 @@ describe('RepoCommitSection', () => { expect(changedFileElements.length).toEqual(2); changedFileElements.forEach((changedFile, i) => { - expect(changedFile.textContent.trim()).toEqual(changedFiles[i].path); + expect(changedFile.textContent.trim()).toEqual(vm.$store.getters.changedFiles[i].path); }); - expect(commitMessage.tagName).toEqual('TEXTAREA'); - expect(commitMessage.name).toEqual('commit-message'); - expect(submitCommit.type).toEqual('submit'); expect(submitCommit.disabled).toBeTruthy(); expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeFalsy(); expect(vm.$el.querySelector('.commit-summary').textContent.trim()).toEqual('Commit 2 files'); expect(targetBranch.querySelector(':scope > label').textContent.trim()).toEqual('Target branch'); - expect(targetBranch.querySelector('.help-block').textContent.trim()).toEqual(branch); - }); - - it('does not render if not isCommitable', () => { - RepoStore.isCommitable = false; - RepoStore.openedFiles = [{ - id: 0, - changed: true, - }]; - - const vm = createComponent(); - - expect(vm.$el.innerHTML).toBeFalsy(); - }); - - it('does not render if no changedFiles', () => { - RepoStore.isCommitable = true; - RepoStore.openedFiles = []; - - const vm = createComponent(); - - expect(vm.$el.innerHTML).toBeFalsy(); + expect(targetBranch.querySelector('.help-block').textContent.trim()).toEqual('master'); }); describe('when submitting', () => { - let el; - let vm; - const projectId = 'projectId'; - const commitMessage = 'commitMessage'; - - beforeEach((done) => { - RepoStore.isCommitable = true; - RepoStore.currentBranch = branch; - RepoStore.targetBranch = branch; - RepoStore.openedFiles = openedFiles; - RepoStore.projectId = projectId; - - // We need to append to body to get form `submit` events working - // Otherwise we run into, "Form submission canceled because the form is not connected" - // See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm - el = document.createElement('div'); - document.body.appendChild(el); - - vm = createComponent(el); - vm.commitMessage = commitMessage; - - spyOn(vm, 'tryCommit').and.callThrough(); - spyOn(vm, 'redirectToNewMr').and.stub(); - spyOn(vm, 'redirectToBranch').and.stub(); - spyOn(RepoService, 'commitFiles').and.returnValue(Promise.resolve()); - spyOn(RepoService, 'getBranch').and.returnValue(Promise.resolve({ - commit: { - id: 1, - short_id: 1, - }, - })); - - // Wait for the vm data to be in place - Vue.nextTick(() => { - done(); - }); - }); + let changedFiles; - afterEach(() => { - vm.$destroy(); - el.remove(); - RepoStore.openedFiles = []; - }); + beforeEach(() => { + vm.commitMessage = 'testing'; + changedFiles = JSON.parse(JSON.stringify(vm.$store.getters.changedFiles)); - it('shows commit message', () => { - const commitMessageEl = vm.$el.querySelector('#commit-message'); - expect(commitMessageEl.value).toBe(commitMessage); + spyOn(service, 'commit').and.returnValue(Promise.resolve({ + short_id: '1', + stats: {}, + })); }); it('allows you to submit', () => { - const submitCommit = vm.$refs.submitCommit; - expect(submitCommit.disabled).toBeFalsy(); + expect(vm.$el.querySelector('.btn').disabled).toBeTruthy(); }); - it('shows commit submit and summary if commitMessage and spinner if submitCommitsLoading', (done) => { - const submitCommit = vm.$refs.submitCommit; - submitCommit.click(); + it('submits commit', (done) => { + vm.makeCommit(); // Wait for the branch check to finish getSetTimeoutPromise() .then(() => Vue.nextTick()) .then(() => { - expect(vm.tryCommit).toHaveBeenCalled(); - expect(submitCommit.querySelector('.js-commit-loading-icon')).toBeTruthy(); - expect(vm.redirectToBranch).toHaveBeenCalled(); - - const args = RepoService.commitFiles.calls.allArgs()[0]; - const { commit_message, actions, branch: payloadBranch } = args[0]; + const args = service.commit.calls.allArgs()[0]; + const { commit_message, actions, branch: payloadBranch } = args[1]; - expect(commit_message).toBe(commitMessage); + expect(commit_message).toBe('testing'); expect(actions.length).toEqual(2); - expect(payloadBranch).toEqual(branch); + expect(payloadBranch).toEqual('master'); expect(actions[0].action).toEqual('update'); expect(actions[1].action).toEqual('update'); - expect(actions[0].content).toEqual(openedFiles[0].newContent); - expect(actions[1].content).toEqual(openedFiles[1].newContent); - expect(actions[0].file_path).toEqual(openedFiles[0].path); - expect(actions[1].file_path).toEqual(openedFiles[1].path); + expect(actions[0].content).toEqual(changedFiles[0].content); + expect(actions[1].content).toEqual(changedFiles[1].content); + expect(actions[0].file_path).toEqual(changedFiles[0].path); + expect(actions[1].file_path).toEqual(changedFiles[1].path); }) .then(done) .catch(done.fail); }); it('redirects to MR creation page if start new MR checkbox checked', (done) => { + spyOn(gl.utils, 'visitUrl'); vm.startNewMR = true; - Vue.nextTick() - .then(() => { - const submitCommit = vm.$refs.submitCommit; - submitCommit.click(); - }) - // Wait for the branch check to finish - .then(() => getSetTimeoutPromise()) + vm.makeCommit(); + + getSetTimeoutPromise() + .then(() => Vue.nextTick()) .then(() => { - expect(vm.redirectToNewMr).toHaveBeenCalled(); + expect(gl.utils.visitUrl).toHaveBeenCalled(); }) .then(done) .catch(done.fail); }); }); - - describe('methods', () => { - describe('resetCommitState', () => { - it('should reset store vars and scroll to top', () => { - const vm = { - submitCommitsLoading: true, - changedFiles: new Array(10), - openedFiles: new Array(3), - commitMessage: 'commitMessage', - editMode: true, - }; - - repoCommitSection.methods.resetCommitState.call(vm); - - expect(vm.submitCommitsLoading).toEqual(false); - expect(vm.changedFiles).toEqual([]); - expect(vm.commitMessage).toEqual(''); - expect(vm.editMode).toEqual(false); - }); - }); - }); }); diff --git a/spec/javascripts/repo/components/repo_edit_button_spec.js b/spec/javascripts/repo/components/repo_edit_button_spec.js index dff2fac191d..44018464b35 100644 --- a/spec/javascripts/repo/components/repo_edit_button_spec.js +++ b/spec/javascripts/repo/components/repo_edit_button_spec.js @@ -1,45 +1,83 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import repoEditButton from '~/repo/components/repo_edit_button.vue'; -import RepoStore from '~/repo/stores/repo_store'; +import { file, resetStore } from '../helpers'; describe('RepoEditButton', () => { - function createComponent() { + let vm; + + beforeEach(() => { + const f = file(); const RepoEditButton = Vue.extend(repoEditButton); - return new RepoEditButton().$mount(); - } + vm = new RepoEditButton({ + store, + }); + + f.active = true; + vm.$store.dispatch('setInitialData', { + canCommit: true, + onTopOfBranch: true, + }); + vm.$store.state.openFiles.push(f); + }); afterEach(() => { - RepoStore.openedFiles = []; + vm.$destroy(); + + resetStore(vm.$store); }); - it('renders an edit button that toggles the view state', (done) => { - RepoStore.isCommitable = true; - RepoStore.changedFiles = []; - RepoStore.binary = false; - RepoStore.openedFiles = [{}, {}]; + it('renders an edit button', () => { + vm.$mount(); + + expect(vm.$el.querySelector('.btn')).not.toBeNull(); + expect(vm.$el.querySelector('.btn').textContent.trim()).toBe('Edit'); + }); - const vm = createComponent(); + it('renders edit button with cancel text', () => { + vm.$store.state.editMode = true; - expect(vm.$el.tagName).toEqual('BUTTON'); - expect(vm.$el.textContent).toMatch('Edit'); + vm.$mount(); - spyOn(vm, 'editCancelClicked').and.callThrough(); + expect(vm.$el.querySelector('.btn')).not.toBeNull(); + expect(vm.$el.querySelector('.btn').textContent.trim()).toBe('Cancel edit'); + }); - vm.$el.click(); + it('toggles edit mode on click', (done) => { + vm.$mount(); + + vm.$el.querySelector('.btn').click(); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.btn').textContent.trim()).toBe('Cancel edit'); - Vue.nextTick(() => { - expect(vm.editCancelClicked).toHaveBeenCalled(); - expect(vm.$el.textContent).toMatch('Cancel edit'); done(); }); }); - it('does not render if not isCommitable', () => { - RepoStore.isCommitable = false; + describe('discardPopupOpen', () => { + beforeEach(() => { + vm.$store.state.discardPopupOpen = true; + vm.$store.state.editMode = true; + vm.$store.state.openFiles[0].changed = true; + + vm.$mount(); + }); + + it('renders popup', () => { + expect(vm.$el.querySelector('.modal')).not.toBeNull(); + }); + + it('removes all changed files', (done) => { + vm.$el.querySelector('.btn-warning').click(); - const vm = createComponent(); + vm.$nextTick(() => { + expect(vm.$store.getters.changedFiles.length).toBe(0); + expect(vm.$el.querySelector('.modal')).toBeNull(); - expect(vm.$el.innerHTML).toBeUndefined(); + done(); + }); + }); }); }); diff --git a/spec/javascripts/repo/components/repo_editor_spec.js b/spec/javascripts/repo/components/repo_editor_spec.js index a25a600b3be..82f914b7c9d 100644 --- a/spec/javascripts/repo/components/repo_editor_spec.js +++ b/spec/javascripts/repo/components/repo_editor_spec.js @@ -1,52 +1,46 @@ import Vue from 'vue'; -import RepoStore from '~/repo/stores/repo_store'; +import store from '~/repo/stores'; import repoEditor from '~/repo/components/repo_editor.vue'; +import { file, resetStore } from '../helpers'; describe('RepoEditor', () => { + let vm; + beforeEach(() => { + const f = file(); const RepoEditor = Vue.extend(repoEditor); - this.vm = new RepoEditor().$mount(); + vm = new RepoEditor({ + store, + }); + + f.active = true; + f.tempFile = true; + vm.$store.state.openFiles.push(f); + vm.monaco = true; + + vm.$mount(); }); afterEach(() => { - RepoStore.openedFiles = []; + vm.$destroy(); + + resetStore(vm.$store); }); it('renders an ide container', (done) => { - this.vm.openedFiles = ['idiidid']; - this.vm.binary = false; - Vue.nextTick(() => { - expect(this.vm.shouldHideEditor).toBe(false); - expect(this.vm.$el.id).toEqual('ide'); - expect(this.vm.$el.tagName).toBe('DIV'); + expect(vm.shouldHideEditor).toBeFalsy(); done(); }); }); - describe('when there are no open files', () => { - it('does not render the ide', (done) => { - this.vm.openedFiles = []; - - Vue.nextTick(() => { - expect(this.vm.shouldHideEditor).toBe(true); - expect(this.vm.$el.tagName).not.toBeDefined(); - done(); - }); - }); - }); - describe('when open file is binary and not raw', () => { it('does not render the IDE', (done) => { - this.vm.binary = true; - this.vm.activeFile = { - raw: false, - }; + vm.$store.getters.activeFile.binary = true; Vue.nextTick(() => { - expect(this.vm.shouldHideEditor).toBe(true); - expect(this.vm.$el.tagName).not.toBeDefined(); + expect(vm.shouldHideEditor).toBeTruthy(); done(); }); }); diff --git a/spec/javascripts/repo/components/repo_file_buttons_spec.js b/spec/javascripts/repo/components/repo_file_buttons_spec.js index 701c260224f..d6e255e4810 100644 --- a/spec/javascripts/repo/components/repo_file_buttons_spec.js +++ b/spec/javascripts/repo/components/repo_file_buttons_spec.js @@ -1,79 +1,49 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import repoFileButtons from '~/repo/components/repo_file_buttons.vue'; -import RepoStore from '~/repo/stores/repo_store'; +import { file, resetStore } from '../helpers'; describe('RepoFileButtons', () => { + const activeFile = file(); + let vm; + function createComponent() { const RepoFileButtons = Vue.extend(repoFileButtons); - return new RepoFileButtons().$mount(); + activeFile.rawPath = 'test'; + activeFile.blamePath = 'test'; + activeFile.commitsPath = 'test'; + activeFile.active = true; + store.state.openFiles.push(activeFile); + + return new RepoFileButtons({ + store, + }).$mount(); } afterEach(() => { - RepoStore.openedFiles = []; - }); - - it('renders Raw, Blame, History, Permalink and Preview toggle', () => { - const activeFile = { - extension: 'md', - url: 'url', - raw_path: 'raw_path', - blame_path: 'blame_path', - commits_path: 'commits_path', - permalink: 'permalink', - }; - const activeFileLabel = 'activeFileLabel'; - RepoStore.openedFiles = new Array(1); - RepoStore.activeFile = activeFile; - RepoStore.activeFileLabel = activeFileLabel; - RepoStore.editMode = true; - RepoStore.binary = false; - - const vm = createComponent(); - const raw = vm.$el.querySelector('.raw'); - const blame = vm.$el.querySelector('.blame'); - const history = vm.$el.querySelector('.history'); + vm.$destroy(); - expect(vm.$el.id).toEqual('repo-file-buttons'); - expect(raw.href).toMatch(`/${activeFile.raw_path}`); - expect(raw.textContent.trim()).toEqual('Raw'); - expect(blame.href).toMatch(`/${activeFile.blame_path}`); - expect(blame.textContent.trim()).toEqual('Blame'); - expect(history.href).toMatch(`/${activeFile.commits_path}`); - expect(history.textContent.trim()).toEqual('History'); - expect(vm.$el.querySelector('.permalink').textContent.trim()).toEqual('Permalink'); - expect(vm.$el.querySelector('.preview').textContent.trim()).toEqual(activeFileLabel); + resetStore(vm.$store); }); - it('triggers rawPreviewToggle on preview click', () => { - const activeFile = { - extension: 'md', - url: 'url', - }; - RepoStore.openedFiles = new Array(1); - RepoStore.activeFile = activeFile; - RepoStore.editMode = true; - - const vm = createComponent(); - const preview = vm.$el.querySelector('.preview'); - - spyOn(vm, 'rawPreviewToggle'); - - preview.click(); - - expect(vm.rawPreviewToggle).toHaveBeenCalled(); - }); + it('renders Raw, Blame, History, Permalink and Preview toggle', (done) => { + vm = createComponent(); - it('does not render preview toggle if not canPreview', () => { - const activeFile = { - extension: 'abcd', - url: 'url', - }; - RepoStore.openedFiles = new Array(1); - RepoStore.activeFile = activeFile; + vm.$nextTick(() => { + const raw = vm.$el.querySelector('.raw'); + const blame = vm.$el.querySelector('.blame'); + const history = vm.$el.querySelector('.history'); - const vm = createComponent(); + expect(raw.href).toMatch(`/${activeFile.rawPath}`); + expect(raw.textContent.trim()).toEqual('Raw'); + expect(blame.href).toMatch(`/${activeFile.blamePath}`); + expect(blame.textContent.trim()).toEqual('Blame'); + expect(history.href).toMatch(`/${activeFile.commitsPath}`); + expect(history.textContent.trim()).toEqual('History'); + expect(vm.$el.querySelector('.permalink').textContent.trim()).toEqual('Permalink'); - expect(vm.$el.querySelector('.preview')).toBeFalsy(); + done(); + }); }); }); diff --git a/spec/javascripts/repo/components/repo_file_spec.js b/spec/javascripts/repo/components/repo_file_spec.js index 107f6797f8a..c45f8a18d1f 100644 --- a/spec/javascripts/repo/components/repo_file_spec.js +++ b/spec/javascripts/repo/components/repo_file_spec.js @@ -1,31 +1,29 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import repoFile from '~/repo/components/repo_file.vue'; -import RepoStore from '~/repo/stores/repo_store'; -import eventHub from '~/repo/event_hub'; -import { file } from '../mock_data'; +import { file, resetStore } from '../helpers'; describe('RepoFile', () => { const updated = 'updated'; - const otherFile = { - html: '<p class="file-content">html</p>', - pageTitle: 'otherpageTitle', - }; + let vm; function createComponent(propsData) { const RepoFile = Vue.extend(repoFile); return new RepoFile({ + store, propsData, }).$mount(); } - beforeEach(() => { - RepoStore.openedFiles = []; + afterEach(() => { + resetStore(vm.$store); }); it('renders link, icon, name and last commit details', () => { const RepoFile = Vue.extend(repoFile); - const vm = new RepoFile({ + vm = new RepoFile({ + store, propsData: { file: file(), }, @@ -46,23 +44,17 @@ describe('RepoFile', () => { }); it('does render if hasFiles is true and is loading tree', () => { - const vm = createComponent({ + vm = createComponent({ file: file(), }); expect(vm.$el.querySelector('.fa-spin.fa-spinner')).toBeFalsy(); }); - it('sets the document title correctly', () => { - RepoStore.setActiveFiles(otherFile); - - expect(document.title.trim()).toEqual(otherFile.pageTitle); - }); - it('renders a spinner if the file is loading', () => { const f = file(); f.loading = true; - const vm = createComponent({ + vm = createComponent({ file: f, }); @@ -70,32 +62,34 @@ describe('RepoFile', () => { expect(vm.$el.querySelector('.fa-spin.fa-spinner').style.marginLeft).toEqual(`${vm.file.level * 16}px`); }); - it('does not render commit message and datetime if mini', () => { - RepoStore.openedFiles.push(file()); - - const vm = createComponent({ + it('does not render commit message and datetime if mini', (done) => { + vm = createComponent({ file: file(), }); + vm.$store.state.openFiles.push(vm.file); - expect(vm.$el.querySelector('.commit-message')).toBeFalsy(); - expect(vm.$el.querySelector('.commit-update')).toBeFalsy(); + vm.$nextTick(() => { + expect(vm.$el.querySelector('.commit-message')).toBeFalsy(); + expect(vm.$el.querySelector('.commit-update')).toBeFalsy(); + + done(); + }); }); - it('fires linkClicked when the link is clicked', () => { - const vm = createComponent({ + it('fires clickedTreeRow when the link is clicked', () => { + vm = createComponent({ file: file(), }); - spyOn(vm, 'linkClicked'); + spyOn(vm, 'clickedTreeRow'); vm.$el.click(); - expect(vm.linkClicked).toHaveBeenCalledWith(vm.file); + expect(vm.clickedTreeRow).toHaveBeenCalledWith(vm.file); }); describe('submodule', () => { let f; - let vm; beforeEach(() => { f = file('submodule name', '123456789'); @@ -118,20 +112,4 @@ describe('RepoFile', () => { expect(vm.$el.querySelector('td').textContent.replace(/\s+/g, ' ')).toContain('submodule name @ 12345678'); }); }); - - describe('methods', () => { - describe('linkClicked', () => { - it('$emits fileNameClicked with file obj', () => { - spyOn(eventHub, '$emit'); - - const vm = createComponent({ - file: file(), - }); - - vm.linkClicked(vm.file); - - expect(eventHub.$emit).toHaveBeenCalledWith('fileNameClicked', vm.file); - }); - }); - }); }); diff --git a/spec/javascripts/repo/components/repo_loading_file_spec.js b/spec/javascripts/repo/components/repo_loading_file_spec.js index e9f95a02028..031f2a9c0b2 100644 --- a/spec/javascripts/repo/components/repo_loading_file_spec.js +++ b/spec/javascripts/repo/components/repo_loading_file_spec.js @@ -1,13 +1,16 @@ import Vue from 'vue'; -import RepoStore from '~/repo/stores/repo_store'; +import store from '~/repo/stores'; import repoLoadingFile from '~/repo/components/repo_loading_file.vue'; +import { resetStore } from '../helpers'; describe('RepoLoadingFile', () => { - function createComponent(propsData) { + let vm; + + function createComponent() { const RepoLoadingFile = Vue.extend(repoLoadingFile); return new RepoLoadingFile({ - propsData, + store, }).$mount(); } @@ -30,33 +33,30 @@ describe('RepoLoadingFile', () => { } afterEach(() => { - RepoStore.openedFiles = []; + vm.$destroy(); + + resetStore(vm.$store); }); it('renders 3 columns of animated LoC', () => { - const vm = createComponent({ - loading: { - tree: true, - }, - hasFiles: false, - }); + vm = createComponent(); const columns = [...vm.$el.querySelectorAll('td')]; expect(columns.length).toEqual(3); assertColumns(columns); }); - it('renders 1 column of animated LoC if isMini', () => { - RepoStore.openedFiles = new Array(1); - const vm = createComponent({ - loading: { - tree: true, - }, - hasFiles: false, - }); - const columns = [...vm.$el.querySelectorAll('td')]; + it('renders 1 column of animated LoC if isMini', (done) => { + vm = createComponent(); + vm.$store.state.openFiles.push('test'); - expect(columns.length).toEqual(1); - assertColumns(columns); + vm.$nextTick(() => { + const columns = [...vm.$el.querySelectorAll('td')]; + + expect(columns.length).toEqual(1); + assertColumns(columns); + + done(); + }); }); }); diff --git a/spec/javascripts/repo/components/repo_prev_directory_spec.js b/spec/javascripts/repo/components/repo_prev_directory_spec.js index 4c064f21084..7f82ae36a64 100644 --- a/spec/javascripts/repo/components/repo_prev_directory_spec.js +++ b/spec/javascripts/repo/components/repo_prev_directory_spec.js @@ -1,47 +1,45 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import repoPrevDirectory from '~/repo/components/repo_prev_directory.vue'; -import eventHub from '~/repo/event_hub'; +import { resetStore } from '../helpers'; describe('RepoPrevDirectory', () => { - function createComponent(propsData) { + let vm; + const parentLink = 'parent'; + function createComponent() { const RepoPrevDirectory = Vue.extend(repoPrevDirectory); - return new RepoPrevDirectory({ - propsData, - }).$mount(); - } - - it('renders a prev dir link', () => { - const prevUrl = 'prevUrl'; - const vm = createComponent({ - prevUrl, + const comp = new RepoPrevDirectory({ + store, }); - const link = vm.$el.querySelector('a'); - spyOn(vm, 'linkClicked'); + comp.$store.state.parentTreeUrl = parentLink; - expect(link.href).toMatch(`/${prevUrl}`); - expect(link.textContent).toEqual('...'); + return comp.$mount(); + } + + beforeEach(() => { + vm = createComponent(); + }); - link.click(); + afterEach(() => { + vm.$destroy(); - expect(vm.linkClicked).toHaveBeenCalledWith(prevUrl); + resetStore(vm.$store); }); - describe('methods', () => { - describe('linkClicked', () => { - it('$emits linkclicked with prevUrl', () => { - const prevUrl = 'prevUrl'; - const vm = createComponent({ - prevUrl, - }); + it('renders a prev dir link', () => { + const link = vm.$el.querySelector('a'); - spyOn(eventHub, '$emit'); + expect(link.href).toMatch(`/${parentLink}`); + expect(link.textContent).toEqual('...'); + }); - vm.linkClicked(prevUrl); + it('clicking row triggers getTreeData', () => { + spyOn(vm, 'getTreeData'); - expect(eventHub.$emit).toHaveBeenCalledWith('goToPreviousDirectoryClicked', prevUrl); - }); - }); + vm.$el.querySelector('td').click(); + + expect(vm.getTreeData).toHaveBeenCalledWith({ endpoint: parentLink }); }); }); diff --git a/spec/javascripts/repo/components/repo_preview_spec.js b/spec/javascripts/repo/components/repo_preview_spec.js index 4920cf02083..8d1a87494cf 100644 --- a/spec/javascripts/repo/components/repo_preview_spec.js +++ b/spec/javascripts/repo/components/repo_preview_spec.js @@ -1,23 +1,37 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import repoPreview from '~/repo/components/repo_preview.vue'; -import RepoStore from '~/repo/stores/repo_store'; +import { file, resetStore } from '../helpers'; describe('RepoPreview', () => { + let vm; + function createComponent() { + const f = file(); const RepoPreview = Vue.extend(repoPreview); - return new RepoPreview().$mount(); + const comp = new RepoPreview({ + store, + }); + + f.active = true; + f.html = 'test'; + + comp.$store.state.openFiles.push(f); + + return comp.$mount(); } - it('renders a div with the activeFile html', () => { - const activeFile = { - html: '<p class="file-content">html</p>', - }; - RepoStore.activeFile = activeFile; + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); - const vm = createComponent(); + it('renders a div with the activeFile html', () => { + vm = createComponent(); expect(vm.$el.tagName).toEqual('DIV'); - expect(vm.$el.innerHTML).toContain(activeFile.html); + expect(vm.$el.innerHTML).toContain('test'); }); }); diff --git a/spec/javascripts/repo/components/repo_sidebar_spec.js b/spec/javascripts/repo/components/repo_sidebar_spec.js index 148f275e03d..7cb4dace491 100644 --- a/spec/javascripts/repo/components/repo_sidebar_spec.js +++ b/spec/javascripts/repo/components/repo_sidebar_spec.js @@ -1,32 +1,31 @@ import Vue from 'vue'; -import Helper from '~/repo/helpers/repo_helper'; -import RepoService from '~/repo/services/repo_service'; -import RepoStore from '~/repo/stores/repo_store'; +import store from '~/repo/stores'; import repoSidebar from '~/repo/components/repo_sidebar.vue'; -import { file } from '../mock_data'; +import { file, resetStore } from '../helpers'; describe('RepoSidebar', () => { let vm; - function createComponent() { + beforeEach(() => { const RepoSidebar = Vue.extend(repoSidebar); - return new RepoSidebar().$mount(); - } + vm = new RepoSidebar({ + store, + }); + + vm.$store.state.isRoot = true; + vm.$store.state.tree.push(file()); + + vm.$mount(); + }); afterEach(() => { vm.$destroy(); - RepoStore.files = []; - RepoStore.openedFiles = []; + resetStore(vm.$store); }); it('renders a sidebar', () => { - RepoStore.files = [file()]; - RepoStore.openedFiles = []; - RepoStore.isRoot = true; - - vm = createComponent(); const thead = vm.$el.querySelector('thead'); const tbody = vm.$el.querySelector('tbody'); @@ -41,139 +40,36 @@ describe('RepoSidebar', () => { expect(tbody.querySelector('.file')).toBeTruthy(); }); - it('does not render a thead, renders repo-file-options and sets sidebar-mini class if isMini', () => { - RepoStore.openedFiles = [{ - id: 0, - }]; - vm = createComponent(); - - expect(vm.$el.classList.contains('sidebar-mini')).toBeTruthy(); - expect(vm.$el.querySelector('thead')).toBeTruthy(); - expect(vm.$el.querySelector('thead .repo-file-options')).toBeTruthy(); - }); - - it('renders 5 loading files if tree is loading and not hasFiles', () => { - RepoStore.loading.tree = true; - RepoStore.files = []; - vm = createComponent(); + it('does not render a thead, renders repo-file-options and sets sidebar-mini class if isMini', (done) => { + vm.$store.state.openFiles.push(vm.$store.state.tree[0]); - expect(vm.$el.querySelectorAll('tbody .loading-file').length).toEqual(5); - }); - - it('renders a prev directory if is not root', () => { - RepoStore.files = [file()]; - RepoStore.isRoot = false; - RepoStore.loading.tree = false; - vm = createComponent(); - - expect(vm.$el.querySelector('tbody .prev-directory')).toBeTruthy(); - }); + Vue.nextTick(() => { + expect(vm.$el.classList.contains('sidebar-mini')).toBeTruthy(); + expect(vm.$el.querySelector('thead')).toBeTruthy(); + expect(vm.$el.querySelector('thead .repo-file-options')).toBeTruthy(); - describe('flattendFiles', () => { - it('returns a flattend array of files', () => { - const f = file(); - f.files.push(file('testing 123')); - const files = [f, file()]; - vm = createComponent(); - vm.files = files; - - expect(vm.flattendFiles.length).toBe(3); - expect(vm.flattendFiles[1].name).toBe('testing 123'); + done(); }); }); - describe('methods', () => { - describe('fileClicked', () => { - it('should fetch data for new file', () => { - spyOn(Helper, 'getContent').and.callThrough(); - RepoStore.files = [file()]; - RepoStore.isRoot = true; - vm = createComponent(); - - vm.fileClicked(RepoStore.files[0]); - - expect(Helper.getContent).toHaveBeenCalledWith(RepoStore.files[0]); - }); - - it('should not fetch data for already opened files', () => { - const f = file(); - spyOn(Helper, 'getFileFromPath').and.returnValue(f); - spyOn(RepoStore, 'setActiveFiles'); - vm = createComponent(); - vm.fileClicked(f); + it('renders 5 loading files if tree is loading', (done) => { + vm.$store.state.tree = []; + vm.$store.state.loading = true; - expect(RepoStore.setActiveFiles).toHaveBeenCalledWith(f); - }); + Vue.nextTick(() => { + expect(vm.$el.querySelectorAll('tbody .loading-file').length).toEqual(5); - it('should hide files in directory if already open', () => { - spyOn(Helper, 'setDirectoryToClosed').and.callThrough(); - const f = file(); - f.opened = true; - f.type = 'tree'; - RepoStore.files = [f]; - vm = createComponent(); - - vm.fileClicked(RepoStore.files[0]); - - expect(Helper.setDirectoryToClosed).toHaveBeenCalledWith(RepoStore.files[0]); - }); - - describe('submodule', () => { - it('opens submodule project URL', () => { - spyOn(gl.utils, 'visitUrl'); - - const f = file(); - f.type = 'submodule'; - - vm = createComponent(); - - vm.fileClicked(f); - - expect(gl.utils.visitUrl).toHaveBeenCalledWith('url'); - }); - }); - }); - - describe('goToPreviousDirectoryClicked', () => { - it('should hide files in directory if already open', () => { - const prevUrl = 'foo/bar'; - vm = createComponent(); - - vm.goToPreviousDirectoryClicked(prevUrl); - - expect(RepoService.url).toEqual(prevUrl); - }); + done(); }); + }); - describe('back button', () => { - beforeEach(() => { - const f = file(); - const file2 = Object.assign({}, file()); - file2.url = 'test'; - RepoStore.files = [f, file2]; - RepoStore.openedFiles = []; - RepoStore.isRoot = true; - - vm = createComponent(); - }); - - it('render previous file when using back button', () => { - spyOn(Helper, 'getContent').and.callThrough(); - - vm.fileClicked(RepoStore.files[1]); - expect(Helper.getContent).toHaveBeenCalledWith(RepoStore.files[1]); - - history.pushState({ - key: Math.random(), - }, '', RepoStore.files[1].url); - const popEvent = document.createEvent('Event'); - popEvent.initEvent('popstate', true, true); - window.dispatchEvent(popEvent); + it('renders a prev directory if is not root', (done) => { + vm.$store.state.isRoot = false; - expect(Helper.getContent.calls.mostRecent().args[0].url).toContain(RepoStore.files[1].url); + Vue.nextTick(() => { + expect(vm.$el.querySelector('tbody .prev-directory')).toBeTruthy(); - window.history.pushState({}, null, '/'); - }); + done(); }); }); }); diff --git a/spec/javascripts/repo/components/repo_spec.js b/spec/javascripts/repo/components/repo_spec.js index 3558a155728..b32d2c13af8 100644 --- a/spec/javascripts/repo/components/repo_spec.js +++ b/spec/javascripts/repo/components/repo_spec.js @@ -1,9 +1,8 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import repo from '~/repo/components/repo.vue'; -import RepoStore from '~/repo/stores/repo_store'; -import Service from '~/repo/services/repo_service'; -import eventHub from '~/repo/event_hub'; -import createComponent from '../../helpers/vue_mount_component_helper'; +import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; +import { file, resetStore } from '../helpers'; describe('repo component', () => { let vm; @@ -11,86 +10,26 @@ describe('repo component', () => { beforeEach(() => { const Component = Vue.extend(repo); - RepoStore.currentBranch = 'master'; - - vm = createComponent(Component); + vm = createComponentWithStore(Component, store).$mount(); }); afterEach(() => { vm.$destroy(); - RepoStore.currentBranch = ''; + resetStore(vm.$store); }); - describe('createNewBranch', () => { - beforeEach(() => { - spyOn(history, 'pushState'); - }); - - describe('success', () => { - beforeEach(() => { - spyOn(Service, 'createBranch').and.returnValue(Promise.resolve({ - data: { - name: 'test', - }, - })); - }); - - it('calls createBranch with branchName', () => { - eventHub.$emit('createNewBranch', 'test'); - - expect(Service.createBranch).toHaveBeenCalledWith({ - branch: 'test', - ref: RepoStore.currentBranch, - }); - }); - - it('pushes new history state', (done) => { - RepoStore.currentBranch = 'master'; - - spyOn(vm, 'getCurrentLocation').and.returnValue('http://test.com/master'); - - eventHub.$emit('createNewBranch', 'test'); - - setTimeout(() => { - expect(history.pushState).toHaveBeenCalledWith(jasmine.anything(), '', 'http://test.com/test'); - done(); - }); - }); - - it('updates stores currentBranch', (done) => { - eventHub.$emit('createNewBranch', 'test'); - - setTimeout(() => { - expect(RepoStore.currentBranch).toBe('test'); - - done(); - }); - }); - }); - - describe('failure', () => { - beforeEach(() => { - spyOn(Service, 'createBranch').and.returnValue(Promise.reject({ - response: { - data: { - message: 'test', - }, - }, - })); - }); - - it('emits createNewBranchError event', (done) => { - spyOn(eventHub, '$emit').and.callThrough(); + it('does not render panel right when no files open', () => { + expect(vm.$el.querySelector('.panel-right')).toBeNull(); + }); - eventHub.$emit('createNewBranch', 'test'); + it('renders panel right when files are open', (done) => { + vm.$store.state.tree.push(file()); - setTimeout(() => { - expect(eventHub.$emit).toHaveBeenCalledWith('createNewBranchError', 'test'); + Vue.nextTick(() => { + expect(vm.$el.querySelector('.panel-right')).toBeNull(); - done(); - }); - }); + done(); }); }); }); diff --git a/spec/javascripts/repo/components/repo_tab_spec.js b/spec/javascripts/repo/components/repo_tab_spec.js index 37e297437f0..df0ca55aafc 100644 --- a/spec/javascripts/repo/components/repo_tab_spec.js +++ b/spec/javascripts/repo/components/repo_tab_spec.js @@ -1,47 +1,64 @@ import Vue from 'vue'; +import store from '~/repo/stores'; import repoTab from '~/repo/components/repo_tab.vue'; -import RepoStore from '~/repo/stores/repo_store'; +import { file, resetStore } from '../helpers'; describe('RepoTab', () => { + let vm; + function createComponent(propsData) { const RepoTab = Vue.extend(repoTab); return new RepoTab({ + store, propsData, }).$mount(); } + afterEach(() => { + resetStore(vm.$store); + }); + it('renders a close link and a name link', () => { - const tab = { - url: 'url', - name: 'name', - }; - const vm = createComponent({ - tab, + vm = createComponent({ + tab: file(), }); + vm.$store.state.openFiles.push(vm.tab); const close = vm.$el.querySelector('.close-btn'); - const name = vm.$el.querySelector(`a[title="${tab.url}"]`); - - spyOn(vm, 'closeTab'); - spyOn(vm, 'tabClicked'); + const name = vm.$el.querySelector(`a[title="${vm.tab.url}"]`); expect(close.querySelector('.fa-times')).toBeTruthy(); - expect(name.textContent.trim()).toEqual(tab.name); + expect(name.textContent.trim()).toEqual(vm.tab.name); + }); - close.click(); - name.click(); + it('calls setFileActive when clicking tab', () => { + vm = createComponent({ + tab: file(), + }); + + spyOn(vm, 'setFileActive'); + + vm.$el.click(); - expect(vm.closeTab).toHaveBeenCalledWith(tab); - expect(vm.tabClicked).toHaveBeenCalledWith(tab); + expect(vm.setFileActive).toHaveBeenCalledWith(vm.tab); + }); + + it('calls closeFile when clicking close button', () => { + vm = createComponent({ + tab: file(), + }); + + spyOn(vm, 'closeFile'); + + vm.$el.querySelector('.close-btn').click(); + + expect(vm.closeFile).toHaveBeenCalledWith({ file: vm.tab }); }); it('renders an fa-circle icon if tab is changed', () => { - const tab = { - url: 'url', - name: 'name', - changed: true, - }; - const vm = createComponent({ + const tab = file(); + tab.changed = true; + vm = createComponent({ tab, }); @@ -50,38 +67,41 @@ describe('RepoTab', () => { describe('methods', () => { describe('closeTab', () => { - it('returns undefined and does not $emit if file is changed', () => { - const tab = { - url: 'url', - name: 'name', - changed: true, - }; - const vm = createComponent({ + it('does not close tab if is changed', (done) => { + const tab = file(); + tab.changed = true; + tab.opened = true; + vm = createComponent({ tab, }); - - spyOn(RepoStore, 'removeFromOpenedFiles'); + vm.$store.state.openFiles.push(tab); + vm.$store.dispatch('setFileActive', tab); vm.$el.querySelector('.close-btn').click(); - expect(RepoStore.removeFromOpenedFiles).not.toHaveBeenCalled(); + vm.$nextTick(() => { + expect(tab.opened).toBeTruthy(); + + done(); + }); }); - it('$emits tabclosed event with file obj', () => { - const tab = { - url: 'url', - name: 'name', - changed: false, - }; - const vm = createComponent({ + it('closes tab when clicking close btn', (done) => { + const tab = file('lose'); + tab.opened = true; + vm = createComponent({ tab, }); - - spyOn(RepoStore, 'removeFromOpenedFiles'); + vm.$store.state.openFiles.push(tab); + vm.$store.dispatch('setFileActive', tab); vm.$el.querySelector('.close-btn').click(); - expect(RepoStore.removeFromOpenedFiles).toHaveBeenCalledWith(tab); + vm.$nextTick(() => { + expect(tab.opened).toBeFalsy(); + + done(); + }); }); }); }); diff --git a/spec/javascripts/repo/components/repo_tabs_spec.js b/spec/javascripts/repo/components/repo_tabs_spec.js index 431129bc866..d0246cc72e6 100644 --- a/spec/javascripts/repo/components/repo_tabs_spec.js +++ b/spec/javascripts/repo/components/repo_tabs_spec.js @@ -1,35 +1,38 @@ import Vue from 'vue'; -import RepoStore from '~/repo/stores/repo_store'; +import store from '~/repo/stores'; import repoTabs from '~/repo/components/repo_tabs.vue'; +import { file, resetStore } from '../helpers'; describe('RepoTabs', () => { - const openedFiles = [{ - id: 0, - active: true, - }, { - id: 1, - }]; + const openedFiles = [file(), file()]; + let vm; function createComponent() { const RepoTabs = Vue.extend(repoTabs); - return new RepoTabs().$mount(); + return new RepoTabs({ + store, + }).$mount(); } afterEach(() => { - RepoStore.openedFiles = []; + resetStore(vm.$store); }); - it('renders a list of tabs', () => { - RepoStore.openedFiles = openedFiles; + it('renders a list of tabs', (done) => { + vm = createComponent(); + openedFiles[0].active = true; + vm.$store.state.openFiles = openedFiles; - const vm = createComponent(); - const tabs = [...vm.$el.querySelectorAll(':scope > li')]; + vm.$nextTick(() => { + const tabs = [...vm.$el.querySelectorAll(':scope > li')]; - expect(vm.$el.id).toEqual('tabs'); - expect(tabs.length).toEqual(3); - expect(tabs[0].classList.contains('active')).toBeTruthy(); - expect(tabs[1].classList.contains('active')).toBeFalsy(); - expect(tabs[2].classList.contains('tabs-divider')).toBeTruthy(); + expect(tabs.length).toEqual(3); + expect(tabs[0].classList.contains('active')).toBeTruthy(); + expect(tabs[1].classList.contains('active')).toBeFalsy(); + expect(tabs[2].classList.contains('tabs-divider')).toBeTruthy(); + + done(); + }); }); }); |