diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-29 00:09:35 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-29 00:09:35 +0300 |
commit | abe11a6a2c04112d0b7d6d4facfd0c8370f51831 (patch) | |
tree | b0c9e9e019417e7b438bf24c6a4a28acfc0fd95b /spec/javascripts | |
parent | 95e18e32833de71b46d73ead66c8f13e261af3f4 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/javascripts')
21 files changed, 0 insertions, 2282 deletions
diff --git a/spec/javascripts/ide/components/activity_bar_spec.js b/spec/javascripts/ide/components/activity_bar_spec.js deleted file mode 100644 index 823ca29dab9..00000000000 --- a/spec/javascripts/ide/components/activity_bar_spec.js +++ /dev/null @@ -1,72 +0,0 @@ -import Vue from 'vue'; -import store from '~/ide/stores'; -import { leftSidebarViews } 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('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(leftSidebarViews.edit.name); - }); - - it('calls updateActivityBarView with commit value on click', () => { - vm.$el.querySelector('.js-ide-commit-mode').click(); - - expect(vm.updateActivityBarView).toHaveBeenCalledWith(leftSidebarViews.commit.name); - }); - - it('calls updateActivityBarView with review value on click', () => { - vm.$el.querySelector('.js-ide-review-mode').click(); - - expect(vm.updateActivityBarView).toHaveBeenCalledWith(leftSidebarViews.review.name); - }); - }); - - 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 = leftSidebarViews.commit.name; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.js-ide-commit-mode').classList).toContain('active'); - - done(); - }); - }); - }); -}); diff --git a/spec/javascripts/ide/components/file_templates/bar_spec.js b/spec/javascripts/ide/components/file_templates/bar_spec.js deleted file mode 100644 index 5399ada94ae..00000000000 --- a/spec/javascripts/ide/components/file_templates/bar_spec.js +++ /dev/null @@ -1,117 +0,0 @@ -import Vue from 'vue'; -import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import { createStore } from '~/ide/stores'; -import Bar from '~/ide/components/file_templates/bar.vue'; -import { resetStore, file } from '../../helpers'; - -describe('IDE file templates bar component', () => { - let Component; - let vm; - - beforeAll(() => { - Component = Vue.extend(Bar); - }); - - beforeEach(() => { - const store = createStore(); - - store.state.openFiles.push({ - ...file('file'), - opened: true, - active: true, - }); - - vm = mountComponentWithStore(Component, { store }); - }); - - afterEach(() => { - vm.$destroy(); - resetStore(vm.$store); - }); - - describe('template type dropdown', () => { - it('renders dropdown component', () => { - expect(vm.$el.querySelector('.dropdown').textContent).toContain('Choose a type'); - }); - - it('calls setSelectedTemplateType when clicking item', () => { - spyOn(vm, 'setSelectedTemplateType').and.stub(); - - vm.$el.querySelector('.dropdown-content button').click(); - - expect(vm.setSelectedTemplateType).toHaveBeenCalledWith({ - name: '.gitlab-ci.yml', - key: 'gitlab_ci_ymls', - }); - }); - }); - - describe('template dropdown', () => { - beforeEach(done => { - vm.$store.state.fileTemplates.templates = [ - { - name: 'test', - }, - ]; - vm.$store.state.fileTemplates.selectedTemplateType = { - name: '.gitlab-ci.yml', - key: 'gitlab_ci_ymls', - }; - - vm.$nextTick(done); - }); - - it('renders dropdown component', () => { - expect(vm.$el.querySelectorAll('.dropdown')[1].textContent).toContain('Choose a template'); - }); - - it('calls fetchTemplate on click', () => { - spyOn(vm, 'fetchTemplate').and.stub(); - - vm.$el - .querySelectorAll('.dropdown-content')[1] - .querySelector('button') - .click(); - - expect(vm.fetchTemplate).toHaveBeenCalledWith({ - name: 'test', - }); - }); - }); - - it('shows undo button if updateSuccess is true', done => { - vm.$store.state.fileTemplates.updateSuccess = true; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.btn-default').style.display).not.toBe('none'); - - done(); - }); - }); - - it('calls undoFileTemplate when clicking undo button', () => { - spyOn(vm, 'undoFileTemplate').and.stub(); - - vm.$el.querySelector('.btn-default').click(); - - expect(vm.undoFileTemplate).toHaveBeenCalled(); - }); - - it('calls setSelectedTemplateType if activeFile name matches a template', done => { - const fileName = '.gitlab-ci.yml'; - - spyOn(vm, 'setSelectedTemplateType'); - vm.$store.state.openFiles[0].name = fileName; - - vm.setInitialType(); - - vm.$nextTick(() => { - expect(vm.setSelectedTemplateType).toHaveBeenCalledWith({ - name: fileName, - key: 'gitlab_ci_ymls', - }); - - done(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_side_bar_spec.js b/spec/javascripts/ide/components/ide_side_bar_spec.js deleted file mode 100644 index 28f127a61c0..00000000000 --- a/spec/javascripts/ide/components/ide_side_bar_spec.js +++ /dev/null @@ -1,57 +0,0 @@ -import Vue from 'vue'; -import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import store from '~/ide/stores'; -import ideSidebar from '~/ide/components/ide_side_bar.vue'; -import { leftSidebarViews } from '~/ide/constants'; -import { resetStore } from '../helpers'; -import { projectData } from '../mock_data'; - -describe('IdeSidebar', () => { - let vm; - - beforeEach(() => { - const Component = Vue.extend(ideSidebar); - - store.state.currentProjectId = 'abcproject'; - store.state.projects.abcproject = projectData; - - vm = createComponentWithStore(Component, store).$mount(); - }); - - afterEach(() => { - vm.$destroy(); - - resetStore(vm.$store); - }); - - it('renders a sidebar', () => { - 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); - - 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 = leftSidebarViews.commit.name; - - 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 deleted file mode 100644 index 4241b994cba..00000000000 --- a/spec/javascripts/ide/components/ide_spec.js +++ /dev/null @@ -1,125 +0,0 @@ -import Vue from 'vue'; -import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import store from '~/ide/stores'; -import ide from '~/ide/components/ide.vue'; -import { file, resetStore } from '../helpers'; -import { projectData } from '../mock_data'; - -function bootstrap(projData) { - const Component = Vue.extend(ide); - - store.state.currentProjectId = 'abcproject'; - store.state.currentBranchId = 'master'; - store.state.projects.abcproject = Object.assign({}, projData); - Vue.set(store.state.trees, 'abcproject/master', { - tree: [], - loading: false, - }); - - return createComponentWithStore(Component, store, { - emptyStateSvgPath: 'svg', - noChangesStateSvgPath: 'svg', - committedStateSvgPath: 'svg', - }); -} - -describe('ide component, empty repo', () => { - let vm; - - beforeEach(() => { - const emptyProjData = Object.assign({}, projectData, { empty_repo: true, branches: {} }); - vm = bootstrap(emptyProjData); - vm.$mount(); - }); - - afterEach(() => { - vm.$destroy(); - - resetStore(vm.$store); - }); - - it('renders "New file" button in empty repo', done => { - vm.$nextTick(() => { - expect(vm.$el.querySelector('.ide-empty-state button[title="New file"]')).not.toBeNull(); - done(); - }); - }); -}); - -describe('ide component, non-empty repo', () => { - let vm; - - beforeEach(() => { - vm = bootstrap(projectData); - vm.$mount(); - }); - - afterEach(() => { - vm.$destroy(); - - resetStore(vm.$store); - }); - - it('shows error message when set', done => { - expect(vm.$el.querySelector('.gl-alert')).toBe(null); - - vm.$store.state.errorMessage = { - text: 'error', - }; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.gl-alert')).not.toBe(null); - - done(); - }); - }); - - describe('onBeforeUnload', () => { - it('returns undefined when no staged files or changed files', () => { - expect(vm.onBeforeUnload()).toBe(undefined); - }); - - it('returns warning text when their are changed files', () => { - vm.$store.state.changedFiles.push(file()); - - expect(vm.onBeforeUnload()).toBe('Are you sure you want to lose unsaved changes?'); - }); - - it('returns warning text when their are staged files', () => { - vm.$store.state.stagedFiles.push(file()); - - expect(vm.onBeforeUnload()).toBe('Are you sure you want to lose unsaved changes?'); - }); - - it('updates event object', () => { - const event = {}; - vm.$store.state.stagedFiles.push(file()); - - vm.onBeforeUnload(event); - - expect(event.returnValue).toBe('Are you sure you want to lose unsaved changes?'); - }); - }); - - describe('non-existent branch', () => { - it('does not render "New file" button for non-existent branch when repo is not empty', done => { - vm.$nextTick(() => { - expect(vm.$el.querySelector('.ide-empty-state button[title="New file"]')).toBeNull(); - done(); - }); - }); - }); - - describe('branch with files', () => { - beforeEach(() => { - store.state.trees['abcproject/master'].tree = [file()]; - }); - - it('does not render "New file" button', done => { - vm.$nextTick(() => { - expect(vm.$el.querySelector('.ide-empty-state button[title="New file"]')).toBeNull(); - done(); - }); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_tree_list_spec.js b/spec/javascripts/ide/components/ide_tree_list_spec.js deleted file mode 100644 index f63007c7dd2..00000000000 --- a/spec/javascripts/ide/components/ide_tree_list_spec.js +++ /dev/null @@ -1,77 +0,0 @@ -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); - const normalBranchTree = [file('fileName')]; - const emptyBranchTree = []; - let vm; - - const bootstrapWithTree = (tree = normalBranchTree) => { - store.state.currentProjectId = 'abcproject'; - store.state.currentBranchId = 'master'; - store.state.projects.abcproject = Object.assign({}, projectData); - Vue.set(store.state.trees, 'abcproject/master', { - tree, - loading: false, - }); - - vm = createComponentWithStore(Component, store, { - viewerType: 'edit', - }); - }; - - afterEach(() => { - vm.$destroy(); - - resetStore(vm.$store); - }); - - describe('normal branch', () => { - beforeEach(() => { - bootstrapWithTree(); - - spyOn(vm, 'updateViewer').and.callThrough(); - - vm.$mount(); - }); - - 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'); - }); - }); - - describe('empty-branch state', () => { - beforeEach(() => { - bootstrapWithTree(emptyBranchTree); - - spyOn(vm, 'updateViewer').and.callThrough(); - - vm.$mount(); - }); - - it('does not load files if the branch is empty', () => { - expect(vm.$el.textContent).not.toContain('fileName'); - expect(vm.$el.textContent).toContain('No files'); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_tree_spec.js b/spec/javascripts/ide/components/ide_tree_spec.js deleted file mode 100644 index 97a0a2432f1..00000000000 --- a/spec/javascripts/ide/components/ide_tree_spec.js +++ /dev/null @@ -1,34 +0,0 @@ -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/jobs/detail/description_spec.js b/spec/javascripts/ide/components/jobs/detail/description_spec.js deleted file mode 100644 index babae00d2f7..00000000000 --- a/spec/javascripts/ide/components/jobs/detail/description_spec.js +++ /dev/null @@ -1,28 +0,0 @@ -import Vue from 'vue'; -import Description from '~/ide/components/jobs/detail/description.vue'; -import mountComponent from '../../../../helpers/vue_mount_component_helper'; -import { jobs } from '../../../mock_data'; - -describe('IDE job description', () => { - const Component = Vue.extend(Description); - let vm; - - beforeEach(() => { - vm = mountComponent(Component, { - job: jobs[0], - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders job details', () => { - expect(vm.$el.textContent).toContain('#1'); - expect(vm.$el.textContent).toContain('test'); - }); - - it('renders CI icon', () => { - expect(vm.$el.querySelector('.ci-status-icon .ic-status_success_borderless')).not.toBe(null); - }); -}); diff --git a/spec/javascripts/ide/components/jobs/item_spec.js b/spec/javascripts/ide/components/jobs/item_spec.js deleted file mode 100644 index 2f97d39e98e..00000000000 --- a/spec/javascripts/ide/components/jobs/item_spec.js +++ /dev/null @@ -1,39 +0,0 @@ -import Vue from 'vue'; -import JobItem from '~/ide/components/jobs/item.vue'; -import mountComponent from '../../../helpers/vue_mount_component_helper'; -import { jobs } from '../../mock_data'; - -describe('IDE jobs item', () => { - const Component = Vue.extend(JobItem); - const job = jobs[0]; - let vm; - - beforeEach(() => { - vm = mountComponent(Component, { - job, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders job details', () => { - expect(vm.$el.textContent).toContain(job.name); - expect(vm.$el.textContent).toContain(`#${job.id}`); - }); - - it('renders CI icon', () => { - expect(vm.$el.querySelector('.ic-status_success_borderless')).not.toBe(null); - }); - - it('does not render view logs button if not started', done => { - vm.job.started = false; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.btn')).toBe(null); - - done(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/nav_dropdown_button_spec.js b/spec/javascripts/ide/components/nav_dropdown_button_spec.js deleted file mode 100644 index bbaf97164ea..00000000000 --- a/spec/javascripts/ide/components/nav_dropdown_button_spec.js +++ /dev/null @@ -1,93 +0,0 @@ -import Vue from 'vue'; -import { trimText } from 'spec/helpers/text_helper'; -import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import NavDropdownButton from '~/ide/components/nav_dropdown_button.vue'; -import { createStore } from '~/ide/stores'; - -describe('NavDropdown', () => { - const TEST_BRANCH_ID = 'lorem-ipsum-dolar'; - const TEST_MR_ID = '12345'; - let store; - let vm; - - beforeEach(() => { - store = createStore(); - }); - - afterEach(() => { - vm.$destroy(); - }); - - const createComponent = (props = {}) => { - vm = mountComponentWithStore(Vue.extend(NavDropdownButton), { props, store }); - vm.$mount(); - }; - - const findIcon = name => vm.$el.querySelector(`.ic-${name}`); - const findMRIcon = () => findIcon('merge-request'); - const findBranchIcon = () => findIcon('branch'); - - describe('normal', () => { - beforeEach(() => { - createComponent(); - }); - - it('renders empty placeholders, if state is falsey', () => { - expect(trimText(vm.$el.textContent)).toEqual('- -'); - }); - - it('renders branch name, if state has currentBranchId', done => { - vm.$store.state.currentBranchId = TEST_BRANCH_ID; - - vm.$nextTick() - .then(() => { - expect(trimText(vm.$el.textContent)).toEqual(`${TEST_BRANCH_ID} -`); - }) - .then(done) - .catch(done.fail); - }); - - it('renders mr id, if state has currentMergeRequestId', done => { - vm.$store.state.currentMergeRequestId = TEST_MR_ID; - - vm.$nextTick() - .then(() => { - expect(trimText(vm.$el.textContent)).toEqual(`- !${TEST_MR_ID}`); - }) - .then(done) - .catch(done.fail); - }); - - it('renders branch and mr, if state has both', done => { - vm.$store.state.currentBranchId = TEST_BRANCH_ID; - vm.$store.state.currentMergeRequestId = TEST_MR_ID; - - vm.$nextTick() - .then(() => { - expect(trimText(vm.$el.textContent)).toEqual(`${TEST_BRANCH_ID} !${TEST_MR_ID}`); - }) - .then(done) - .catch(done.fail); - }); - - it('shows icons', () => { - expect(findBranchIcon()).toBeTruthy(); - expect(findMRIcon()).toBeTruthy(); - }); - }); - - describe('with showMergeRequests false', () => { - beforeEach(() => { - createComponent({ showMergeRequests: false }); - }); - - it('shows single empty placeholder, if state is falsey', () => { - expect(trimText(vm.$el.textContent)).toEqual('-'); - }); - - it('shows only branch icon', () => { - expect(findBranchIcon()).toBeTruthy(); - expect(findMRIcon()).toBe(null); - }); - }); -}); diff --git a/spec/javascripts/ide/components/nav_dropdown_spec.js b/spec/javascripts/ide/components/nav_dropdown_spec.js deleted file mode 100644 index dfb4d03540f..00000000000 --- a/spec/javascripts/ide/components/nav_dropdown_spec.js +++ /dev/null @@ -1,80 +0,0 @@ -import $ from 'jquery'; -import Vue from 'vue'; -import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import store from '~/ide/stores'; -import NavDropdown from '~/ide/components/nav_dropdown.vue'; -import { PERMISSION_READ_MR } from '~/ide/constants'; - -const TEST_PROJECT_ID = 'lorem-ipsum'; - -describe('IDE NavDropdown', () => { - const Component = Vue.extend(NavDropdown); - let vm; - let $dropdown; - - beforeEach(() => { - store.state.currentProjectId = TEST_PROJECT_ID; - Vue.set(store.state.projects, TEST_PROJECT_ID, { - userPermissions: { - [PERMISSION_READ_MR]: true, - }, - }); - vm = mountComponentWithStore(Component, { store }); - $dropdown = $(vm.$el); - - // block dispatch from doing anything - spyOn(vm.$store, 'dispatch'); - }); - - afterEach(() => { - vm.$destroy(); - }); - - const findIcon = name => vm.$el.querySelector(`.ic-${name}`); - const findMRIcon = () => findIcon('merge-request'); - - it('renders nothing initially', () => { - expect(vm.$el).not.toContainElement('.ide-nav-form'); - }); - - it('renders nav form when show.bs.dropdown', done => { - $dropdown.trigger('show.bs.dropdown'); - - vm.$nextTick() - .then(() => { - expect(vm.$el).toContainElement('.ide-nav-form'); - }) - .then(done) - .catch(done.fail); - }); - - it('destroys nav form when closed', done => { - $dropdown.trigger('show.bs.dropdown'); - $dropdown.trigger('hide.bs.dropdown'); - - vm.$nextTick() - .then(() => { - expect(vm.$el).not.toContainElement('.ide-nav-form'); - }) - .then(done) - .catch(done.fail); - }); - - it('renders merge request icon', () => { - expect(findMRIcon()).not.toBeNull(); - }); - - describe('when user cannot read merge requests', () => { - beforeEach(done => { - store.state.projects[TEST_PROJECT_ID].userPermissions = {}; - - vm.$nextTick() - .then(done) - .catch(done.fail); - }); - - it('does not render merge requests', () => { - expect(findMRIcon()).toBeNull(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/new_dropdown/button_spec.js b/spec/javascripts/ide/components/new_dropdown/button_spec.js deleted file mode 100644 index 6a326b5bd92..00000000000 --- a/spec/javascripts/ide/components/new_dropdown/button_spec.js +++ /dev/null @@ -1,65 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import Button from '~/ide/components/new_dropdown/button.vue'; - -describe('IDE new entry dropdown button component', () => { - let Component; - let vm; - - beforeAll(() => { - Component = Vue.extend(Button); - }); - - beforeEach(() => { - vm = mountComponent(Component, { - label: 'Testing', - icon: 'doc-new', - }); - - spyOn(vm, '$emit'); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders button with label', () => { - expect(vm.$el.textContent).toContain('Testing'); - }); - - it('renders icon', () => { - expect(vm.$el.querySelector('.ic-doc-new')).not.toBe(null); - }); - - it('emits click event', () => { - vm.$el.click(); - - expect(vm.$emit).toHaveBeenCalledWith('click'); - }); - - it('hides label if showLabel is false', done => { - vm.showLabel = false; - - vm.$nextTick(() => { - expect(vm.$el.textContent).not.toContain('Testing'); - - done(); - }); - }); - - describe('tooltipTitle', () => { - it('returns empty string when showLabel is true', () => { - expect(vm.tooltipTitle).toBe(''); - }); - - it('returns label', done => { - vm.showLabel = false; - - vm.$nextTick(() => { - expect(vm.tooltipTitle).toBe('Testing'); - - done(); - }); - }); - }); -}); diff --git a/spec/javascripts/ide/components/new_dropdown/index_spec.js b/spec/javascripts/ide/components/new_dropdown/index_spec.js deleted file mode 100644 index 03afe997fed..00000000000 --- a/spec/javascripts/ide/components/new_dropdown/index_spec.js +++ /dev/null @@ -1,84 +0,0 @@ -import Vue from 'vue'; -import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import store from '~/ide/stores'; -import newDropdown from '~/ide/components/new_dropdown/index.vue'; -import { resetStore } from '../../helpers'; - -describe('new dropdown component', () => { - let vm; - - beforeEach(() => { - const component = Vue.extend(newDropdown); - - vm = createComponentWithStore(component, store, { - branch: 'master', - path: '', - mouseOver: false, - type: 'tree', - }); - - vm.$store.state.currentProjectId = 'abcproject'; - vm.$store.state.path = ''; - vm.$store.state.trees['abcproject/mybranch'] = { - tree: [], - }; - - spyOn(vm, 'openNewEntryModal'); - - vm.$mount(); - }); - - afterEach(() => { - vm.$destroy(); - - resetStore(vm.$store); - }); - - it('renders new file, upload and new directory links', () => { - const buttons = vm.$el.querySelectorAll('.dropdown-menu button'); - - expect(buttons[0].textContent.trim()).toBe('New file'); - expect(buttons[1].textContent.trim()).toBe('Upload file'); - expect(buttons[2].textContent.trim()).toBe('New directory'); - }); - - describe('createNewItem', () => { - it('sets modalType to blob when new file is clicked', () => { - vm.$el.querySelectorAll('.dropdown-menu button')[0].click(); - - expect(vm.openNewEntryModal).toHaveBeenCalledWith({ type: 'blob', path: '' }); - }); - - it('sets modalType to tree when new directory is clicked', () => { - vm.$el.querySelectorAll('.dropdown-menu button')[2].click(); - - expect(vm.openNewEntryModal).toHaveBeenCalledWith({ type: 'tree', path: '' }); - }); - }); - - describe('isOpen', () => { - it('scrolls dropdown into view', done => { - spyOn(vm.$refs.dropdownMenu, 'scrollIntoView'); - - vm.isOpen = true; - - setTimeout(() => { - expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalledWith({ - block: 'nearest', - }); - - done(); - }); - }); - }); - - describe('delete entry', () => { - it('calls delete action', () => { - spyOn(vm, 'deleteEntry'); - - vm.$el.querySelectorAll('.dropdown-menu button')[4].click(); - - expect(vm.deleteEntry).toHaveBeenCalledWith(''); - }); - }); -}); diff --git a/spec/javascripts/ide/components/new_dropdown/modal_spec.js b/spec/javascripts/ide/components/new_dropdown/modal_spec.js deleted file mode 100644 index 0ea767e087d..00000000000 --- a/spec/javascripts/ide/components/new_dropdown/modal_spec.js +++ /dev/null @@ -1,150 +0,0 @@ -import Vue from 'vue'; -import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import { createStore } from '~/ide/stores'; -import modal from '~/ide/components/new_dropdown/modal.vue'; - -describe('new file modal component', () => { - const Component = Vue.extend(modal); - let vm; - - afterEach(() => { - vm.$destroy(); - }); - - ['tree', 'blob'].forEach(type => { - describe(type, () => { - beforeEach(() => { - const store = createStore(); - store.state.entryModal = { - type, - path: '', - entry: { - path: '', - }, - }; - - vm = createComponentWithStore(Component, store).$mount(); - - vm.name = '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}`, () => { - expect(vm.$el.querySelector('.label-bold').textContent.trim()).toBe('Name'); - }); - - it(`${type === 'tree' ? 'does not show' : 'shows'} file templates`, () => { - const templateFilesEl = vm.$el.querySelector('.file-templates'); - if (type === 'tree') { - expect(templateFilesEl).toBeNull(); - } else { - expect(templateFilesEl instanceof Element).toBeTruthy(); - } - }); - }); - }); - - describe('rename entry', () => { - beforeEach(() => { - const store = createStore(); - store.state.entryModal = { - type: 'rename', - path: '', - entry: { - name: 'test', - type: 'blob', - path: 'test-path', - }, - }; - - vm = createComponentWithStore(Component, store).$mount(); - }); - - ['tree', 'blob'].forEach(type => { - it(`renders title and button for renaming ${type}`, done => { - const text = type === 'tree' ? 'folder' : 'file'; - - vm.$store.state.entryModal.entry.type = type; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Rename ${text}`); - expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Rename ${text}`); - - done(); - }); - }); - }); - - describe('entryName', () => { - it('returns entries name', () => { - expect(vm.entryName).toBe('test-path'); - }); - - it('updated name', () => { - vm.name = 'index.js'; - - expect(vm.entryName).toBe('index.js'); - }); - - it('removes leading/trailing spaces when found in the new name', () => { - vm.entryName = ' index.js '; - - expect(vm.entryName).toBe('index.js'); - }); - - it('does not remove internal spaces in the file name', () => { - vm.entryName = ' In Praise of Idleness.txt '; - - expect(vm.entryName).toBe('In Praise of Idleness.txt'); - }); - }); - }); - - describe('submitForm', () => { - it('throws an error when target entry exists', () => { - const store = createStore(); - store.state.entryModal = { - type: 'rename', - path: 'test-path/test', - entry: { - name: 'test', - type: 'blob', - path: 'test-path/test', - }, - }; - store.state.entries = { - 'test-path/test': { - name: 'test', - deleted: false, - }, - }; - - vm = createComponentWithStore(Component, store).$mount(); - const flashSpy = spyOnDependency(modal, 'flash'); - - expect(flashSpy).not.toHaveBeenCalled(); - - vm.submitForm(); - - expect(flashSpy).toHaveBeenCalledWith( - 'The name "test-path/test" is already taken in this directory.', - 'alert', - jasmine.anything(), - null, - false, - true, - ); - }); - }); -}); diff --git a/spec/javascripts/ide/components/repo_tab_spec.js b/spec/javascripts/ide/components/repo_tab_spec.js deleted file mode 100644 index 3b52f279bf2..00000000000 --- a/spec/javascripts/ide/components/repo_tab_spec.js +++ /dev/null @@ -1,185 +0,0 @@ -import Vue from 'vue'; -import store from '~/ide/stores'; -import repoTab from '~/ide/components/repo_tab.vue'; -import router from '~/ide/ide_router'; -import { file, resetStore } from '../helpers'; - -describe('RepoTab', () => { - let vm; - - function createComponent(propsData) { - const RepoTab = Vue.extend(repoTab); - - return new RepoTab({ - store, - propsData, - }).$mount(); - } - - beforeEach(() => { - spyOn(router, 'push'); - }); - - afterEach(() => { - vm.$destroy(); - - resetStore(vm.$store); - }); - - it('renders a close link and a name link', () => { - vm = createComponent({ - tab: file(), - }); - vm.$store.state.openFiles.push(vm.tab); - const close = vm.$el.querySelector('.multi-file-tab-close'); - const name = vm.$el.querySelector(`[title="${vm.tab.url}"]`); - - expect(close.innerHTML).toContain('#close'); - expect(name.textContent.trim()).toEqual(vm.tab.name); - }); - - it('does not call openPendingTab when tab is active', done => { - vm = createComponent({ - tab: { - ...file(), - pending: true, - active: true, - }, - }); - - spyOn(vm, 'openPendingTab'); - - vm.$el.click(); - - vm.$nextTick(() => { - expect(vm.openPendingTab).not.toHaveBeenCalled(); - - done(); - }); - }); - - it('fires clickFile when the link is clicked', () => { - vm = createComponent({ - tab: file(), - }); - - spyOn(vm, 'clickFile'); - - vm.$el.click(); - - expect(vm.clickFile).toHaveBeenCalledWith(vm.tab); - }); - - it('calls closeFile when clicking close button', () => { - vm = createComponent({ - tab: file(), - }); - - spyOn(vm, 'closeFile'); - - vm.$el.querySelector('.multi-file-tab-close').click(); - - expect(vm.closeFile).toHaveBeenCalledWith(vm.tab); - }); - - it('changes icon on hover', done => { - const tab = file(); - tab.changed = true; - vm = createComponent({ - tab, - }); - - vm.$el.dispatchEvent(new Event('mouseover')); - - Vue.nextTick() - .then(() => { - expect(vm.$el.querySelector('.file-modified')).toBeNull(); - - vm.$el.dispatchEvent(new Event('mouseout')); - }) - .then(Vue.nextTick) - .then(() => { - expect(vm.$el.querySelector('.file-modified')).not.toBeNull(); - - done(); - }) - .catch(done.fail); - }); - - describe('locked file', () => { - let f; - - beforeEach(() => { - f = file('locked file'); - f.file_lock = { - user: { - name: 'testuser', - updated_at: new Date(), - }, - }; - - vm = createComponent({ - tab: f, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders lock icon', () => { - expect(vm.$el.querySelector('.file-status-icon')).not.toBeNull(); - }); - - it('renders a tooltip', () => { - expect(vm.$el.querySelector('span:nth-child(2)').dataset.originalTitle).toContain( - 'Locked by testuser', - ); - }); - }); - - describe('methods', () => { - describe('closeTab', () => { - it('closes tab if file has changed', done => { - const tab = file(); - tab.changed = true; - tab.opened = true; - vm = createComponent({ - tab, - }); - vm.$store.state.openFiles.push(tab); - vm.$store.state.changedFiles.push(tab); - vm.$store.state.entries[tab.path] = tab; - vm.$store.dispatch('setFileActive', tab.path); - - vm.$el.querySelector('.multi-file-tab-close').click(); - - vm.$nextTick(() => { - expect(tab.opened).toBeFalsy(); - expect(vm.$store.state.changedFiles.length).toBe(1); - - done(); - }); - }); - - it('closes tab when clicking close btn', done => { - const tab = file('lose'); - tab.opened = true; - vm = createComponent({ - tab, - }); - vm.$store.state.openFiles.push(tab); - vm.$store.state.entries[tab.path] = tab; - vm.$store.dispatch('setFileActive', tab.path); - - vm.$el.querySelector('.multi-file-tab-close').click(); - - vm.$nextTick(() => { - expect(tab.opened).toBeFalsy(); - - done(); - }); - }); - }); - }); -}); diff --git a/spec/javascripts/ide/components/repo_tabs_spec.js b/spec/javascripts/ide/components/repo_tabs_spec.js deleted file mode 100644 index 583f71e6121..00000000000 --- a/spec/javascripts/ide/components/repo_tabs_spec.js +++ /dev/null @@ -1,35 +0,0 @@ -import Vue from 'vue'; -import repoTabs from '~/ide/components/repo_tabs.vue'; -import createComponent from '../../helpers/vue_mount_component_helper'; -import { file } from '../helpers'; - -describe('RepoTabs', () => { - const openedFiles = [file('open1'), file('open2')]; - const RepoTabs = Vue.extend(repoTabs); - let vm; - - afterEach(() => { - vm.$destroy(); - }); - - it('renders a list of tabs', done => { - vm = createComponent(RepoTabs, { - files: openedFiles, - viewer: 'editor', - hasChanges: false, - activeFile: file('activeFile'), - hasMergeRequest: false, - }); - openedFiles[0].active = true; - - vm.$nextTick(() => { - const tabs = [...vm.$el.querySelectorAll('.multi-file-tab')]; - - expect(tabs.length).toEqual(2); - expect(tabs[0].parentNode.classList.contains('active')).toEqual(true); - expect(tabs[1].parentNode.classList.contains('active')).toEqual(false); - - done(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/shared/tokened_input_spec.js b/spec/javascripts/ide/components/shared/tokened_input_spec.js deleted file mode 100644 index 885fd976655..00000000000 --- a/spec/javascripts/ide/components/shared/tokened_input_spec.js +++ /dev/null @@ -1,133 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import TokenedInput from '~/ide/components/shared/tokened_input.vue'; - -const TEST_PLACEHOLDER = 'Searching in test'; -const TEST_TOKENS = [ - { label: 'lorem', id: 1 }, - { label: 'ipsum', id: 2 }, - { label: 'dolar', id: 3 }, -]; -const TEST_VALUE = 'lorem'; - -function getTokenElements(vm) { - return Array.from(vm.$el.querySelectorAll('.filtered-search-token button')); -} - -function createBackspaceEvent() { - const e = new Event('keyup'); - e.keyCode = 8; - e.which = e.keyCode; - e.altKey = false; - e.ctrlKey = true; - e.shiftKey = false; - e.metaKey = false; - return e; -} - -describe('IDE shared/TokenedInput', () => { - const Component = Vue.extend(TokenedInput); - let vm; - - beforeEach(() => { - vm = mountComponent(Component, { - tokens: TEST_TOKENS, - placeholder: TEST_PLACEHOLDER, - value: TEST_VALUE, - }); - - spyOn(vm, '$emit'); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders tokens', () => { - const renderedTokens = getTokenElements(vm).map(x => x.textContent.trim()); - - expect(renderedTokens).toEqual(TEST_TOKENS.map(x => x.label)); - }); - - it('renders input', () => { - expect(vm.$refs.input).toBeTruthy(); - expect(vm.$refs.input).toHaveValue(TEST_VALUE); - }); - - it('renders placeholder, when tokens are empty', done => { - vm.tokens = []; - - vm.$nextTick() - .then(() => { - expect(vm.$refs.input).toHaveAttr('placeholder', TEST_PLACEHOLDER); - }) - .then(done) - .catch(done.fail); - }); - - it('triggers "removeToken" on token click', () => { - getTokenElements(vm)[0].click(); - - expect(vm.$emit).toHaveBeenCalledWith('removeToken', TEST_TOKENS[0]); - }); - - it('when input triggers backspace event, it calls "onBackspace"', () => { - spyOn(vm, 'onBackspace'); - - vm.$refs.input.dispatchEvent(createBackspaceEvent()); - vm.$refs.input.dispatchEvent(createBackspaceEvent()); - - expect(vm.onBackspace).toHaveBeenCalledTimes(2); - }); - - it('triggers "removeToken" on backspaces when value is empty', () => { - vm.value = ''; - - vm.onBackspace(); - - expect(vm.$emit).not.toHaveBeenCalled(); - expect(vm.backspaceCount).toEqual(1); - - vm.onBackspace(); - - expect(vm.$emit).toHaveBeenCalledWith('removeToken', TEST_TOKENS[TEST_TOKENS.length - 1]); - expect(vm.backspaceCount).toEqual(0); - }); - - it('does not trigger "removeToken" on backspaces when value is not empty', () => { - vm.onBackspace(); - vm.onBackspace(); - - expect(vm.backspaceCount).toEqual(0); - expect(vm.$emit).not.toHaveBeenCalled(); - }); - - it('does not trigger "removeToken" on backspaces when tokens are empty', () => { - vm.tokens = []; - - vm.onBackspace(); - vm.onBackspace(); - - expect(vm.backspaceCount).toEqual(0); - expect(vm.$emit).not.toHaveBeenCalled(); - }); - - it('triggers "focus" on input focus', () => { - vm.$refs.input.dispatchEvent(new Event('focus')); - - expect(vm.$emit).toHaveBeenCalledWith('focus'); - }); - - it('triggers "blur" on input blur', () => { - vm.$refs.input.dispatchEvent(new Event('blur')); - - expect(vm.$emit).toHaveBeenCalledWith('blur'); - }); - - it('triggers "input" with value on input change', () => { - vm.$refs.input.value = 'something-else'; - vm.$refs.input.dispatchEvent(new Event('input')); - - expect(vm.$emit).toHaveBeenCalledWith('input', 'something-else'); - }); -}); diff --git a/spec/javascripts/ide/lib/common/model_manager_spec.js b/spec/javascripts/ide/lib/common/model_manager_spec.js deleted file mode 100644 index 38ffa317e8e..00000000000 --- a/spec/javascripts/ide/lib/common/model_manager_spec.js +++ /dev/null @@ -1,126 +0,0 @@ -import eventHub from '~/ide/eventhub'; -import ModelManager from '~/ide/lib/common/model_manager'; -import { file } from '../../helpers'; - -describe('Multi-file editor library model manager', () => { - let instance; - - beforeEach(() => { - instance = new ModelManager(); - }); - - afterEach(() => { - instance.dispose(); - }); - - describe('addModel', () => { - it('caches model', () => { - instance.addModel(file()); - - expect(instance.models.size).toBe(1); - }); - - it('caches model by file path', () => { - const f = file('path-name'); - instance.addModel(f); - - expect(instance.models.keys().next().value).toBe(f.key); - }); - - it('adds model into disposable', () => { - spyOn(instance.disposable, 'add').and.callThrough(); - - instance.addModel(file()); - - expect(instance.disposable.add).toHaveBeenCalled(); - }); - - it('returns cached model', () => { - spyOn(instance.models, 'get').and.callThrough(); - - instance.addModel(file()); - instance.addModel(file()); - - expect(instance.models.get).toHaveBeenCalled(); - }); - - it('adds eventHub listener', () => { - const f = file(); - spyOn(eventHub, '$on').and.callThrough(); - - instance.addModel(f); - - expect(eventHub.$on).toHaveBeenCalledWith( - `editor.update.model.dispose.${f.key}`, - jasmine.anything(), - ); - }); - }); - - describe('hasCachedModel', () => { - it('returns false when no models exist', () => { - expect(instance.hasCachedModel('path')).toBeFalsy(); - }); - - it('returns true when model exists', () => { - const f = file('path-name'); - - instance.addModel(f); - - expect(instance.hasCachedModel(f.key)).toBeTruthy(); - }); - }); - - describe('getModel', () => { - it('returns cached model', () => { - instance.addModel(file('path-name')); - - expect(instance.getModel('path-name')).not.toBeNull(); - }); - }); - - describe('removeCachedModel', () => { - let f; - - beforeEach(() => { - f = file(); - - instance.addModel(f); - }); - - it('clears cached model', () => { - instance.removeCachedModel(f); - - expect(instance.models.size).toBe(0); - }); - - it('removes eventHub listener', () => { - spyOn(eventHub, '$off').and.callThrough(); - - instance.removeCachedModel(f); - - expect(eventHub.$off).toHaveBeenCalledWith( - `editor.update.model.dispose.${f.key}`, - jasmine.anything(), - ); - }); - }); - - describe('dispose', () => { - it('clears cached models', () => { - instance.addModel(file()); - - instance.dispose(); - - expect(instance.models.size).toBe(0); - }); - - it('calls disposable dispose', () => { - spyOn(instance.disposable, 'dispose').and.callThrough(); - - instance.dispose(); - - expect(instance.disposable.dispose).toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/javascripts/ide/lib/common/model_spec.js b/spec/javascripts/ide/lib/common/model_spec.js deleted file mode 100644 index f096e06f43c..00000000000 --- a/spec/javascripts/ide/lib/common/model_spec.js +++ /dev/null @@ -1,137 +0,0 @@ -import eventHub from '~/ide/eventhub'; -import Model from '~/ide/lib/common/model'; -import { file } from '../../helpers'; - -describe('Multi-file editor library model', () => { - let model; - - beforeEach(() => { - spyOn(eventHub, '$on').and.callThrough(); - - const f = file('path'); - f.mrChange = { diff: 'ABC' }; - f.baseRaw = 'test'; - model = new Model(f); - }); - - afterEach(() => { - model.dispose(); - }); - - it('creates original model & base model & new model', () => { - expect(model.originalModel).not.toBeNull(); - expect(model.model).not.toBeNull(); - expect(model.baseModel).not.toBeNull(); - - expect(model.originalModel.uri.path).toBe('original/path--path'); - expect(model.model.uri.path).toBe('path--path'); - expect(model.baseModel.uri.path).toBe('target/path--path'); - }); - - it('creates model with head file to compare against', () => { - const f = file('path'); - model.dispose(); - - model = new Model(f, { - ...f, - content: '123 testing', - }); - - expect(model.head).not.toBeNull(); - expect(model.getOriginalModel().getValue()).toBe('123 testing'); - }); - - it('adds eventHub listener', () => { - expect(eventHub.$on).toHaveBeenCalledWith( - `editor.update.model.dispose.${model.file.key}`, - jasmine.anything(), - ); - }); - - describe('path', () => { - it('returns file path', () => { - expect(model.path).toBe(model.file.key); - }); - }); - - describe('getModel', () => { - it('returns model', () => { - expect(model.getModel()).toBe(model.model); - }); - }); - - describe('getOriginalModel', () => { - it('returns original model', () => { - expect(model.getOriginalModel()).toBe(model.originalModel); - }); - }); - - describe('getBaseModel', () => { - it('returns base model', () => { - expect(model.getBaseModel()).toBe(model.baseModel); - }); - }); - - describe('setValue', () => { - it('updates models value', () => { - model.setValue('testing 123'); - - expect(model.getModel().getValue()).toBe('testing 123'); - }); - }); - - describe('onChange', () => { - it('calls callback on change', done => { - const spy = jasmine.createSpy(); - model.onChange(spy); - - model.getModel().setValue('123'); - - setTimeout(() => { - expect(spy).toHaveBeenCalledWith(model, jasmine.anything()); - done(); - }); - }); - }); - - describe('dispose', () => { - it('calls disposable dispose', () => { - spyOn(model.disposable, 'dispose').and.callThrough(); - - model.dispose(); - - expect(model.disposable.dispose).toHaveBeenCalled(); - }); - - it('clears events', () => { - model.onChange(() => {}); - - expect(model.events.size).toBe(1); - - model.dispose(); - - expect(model.events.size).toBe(0); - }); - - it('removes eventHub listener', () => { - spyOn(eventHub, '$off').and.callThrough(); - - model.dispose(); - - expect(eventHub.$off).toHaveBeenCalledWith( - `editor.update.model.dispose.${model.file.key}`, - jasmine.anything(), - ); - }); - - it('calls onDispose callback', () => { - const disposeSpy = jasmine.createSpy(); - - model.onDispose(disposeSpy); - - model.dispose(); - - expect(disposeSpy).toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/javascripts/ide/lib/decorations/controller_spec.js b/spec/javascripts/ide/lib/decorations/controller_spec.js deleted file mode 100644 index 4118774cca3..00000000000 --- a/spec/javascripts/ide/lib/decorations/controller_spec.js +++ /dev/null @@ -1,143 +0,0 @@ -import Editor from '~/ide/lib/editor'; -import DecorationsController from '~/ide/lib/decorations/controller'; -import Model from '~/ide/lib/common/model'; -import { file } from '../../helpers'; - -describe('Multi-file editor library decorations controller', () => { - let editorInstance; - let controller; - let model; - - beforeEach(() => { - editorInstance = Editor.create(); - editorInstance.createInstance(document.createElement('div')); - - controller = new DecorationsController(editorInstance); - model = new Model(file('path')); - }); - - afterEach(() => { - model.dispose(); - editorInstance.dispose(); - controller.dispose(); - }); - - describe('getAllDecorationsForModel', () => { - it('returns empty array when no decorations exist for model', () => { - const decorations = controller.getAllDecorationsForModel(model); - - expect(decorations).toEqual([]); - }); - - it('returns decorations by model URL', () => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - - const decorations = controller.getAllDecorationsForModel(model); - - expect(decorations[0]).toEqual({ decoration: 'decorationValue' }); - }); - }); - - describe('addDecorations', () => { - it('caches decorations in a new map', () => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - - expect(controller.decorations.size).toBe(1); - }); - - it('does not create new cache model', () => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue2' }]); - - expect(controller.decorations.size).toBe(1); - }); - - it('caches decorations by model URL', () => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - - expect(controller.decorations.size).toBe(1); - expect(controller.decorations.keys().next().value).toBe('gitlab:path--path'); - }); - - it('calls decorate method', () => { - spyOn(controller, 'decorate'); - - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - - expect(controller.decorate).toHaveBeenCalled(); - }); - }); - - describe('decorate', () => { - it('sets decorations on editor instance', () => { - spyOn(controller.editor.instance, 'deltaDecorations'); - - controller.decorate(model); - - expect(controller.editor.instance.deltaDecorations).toHaveBeenCalledWith([], []); - }); - - it('caches decorations', () => { - spyOn(controller.editor.instance, 'deltaDecorations').and.returnValue([]); - - controller.decorate(model); - - expect(controller.editorDecorations.size).toBe(1); - }); - - it('caches decorations by model URL', () => { - spyOn(controller.editor.instance, 'deltaDecorations').and.returnValue([]); - - controller.decorate(model); - - expect(controller.editorDecorations.keys().next().value).toBe('gitlab:path--path'); - }); - }); - - describe('dispose', () => { - it('clears cached decorations', () => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - - controller.dispose(); - - expect(controller.decorations.size).toBe(0); - }); - - it('clears cached editorDecorations', () => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - - controller.dispose(); - - expect(controller.editorDecorations.size).toBe(0); - }); - }); - - describe('hasDecorations', () => { - it('returns true when decorations are cached', () => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - - expect(controller.hasDecorations(model)).toBe(true); - }); - - it('returns false when no model decorations exist', () => { - expect(controller.hasDecorations(model)).toBe(false); - }); - }); - - describe('removeDecorations', () => { - beforeEach(() => { - controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); - controller.decorate(model); - }); - - it('removes cached decorations', () => { - expect(controller.decorations.size).not.toBe(0); - expect(controller.editorDecorations.size).not.toBe(0); - - controller.removeDecorations(model); - - expect(controller.decorations.size).toBe(0); - expect(controller.editorDecorations.size).toBe(0); - }); - }); -}); diff --git a/spec/javascripts/ide/lib/diff/controller_spec.js b/spec/javascripts/ide/lib/diff/controller_spec.js deleted file mode 100644 index 90ebb95b687..00000000000 --- a/spec/javascripts/ide/lib/diff/controller_spec.js +++ /dev/null @@ -1,215 +0,0 @@ -import { Range } from 'monaco-editor'; -import Editor from '~/ide/lib/editor'; -import ModelManager from '~/ide/lib/common/model_manager'; -import DecorationsController from '~/ide/lib/decorations/controller'; -import DirtyDiffController, { getDiffChangeType, getDecorator } from '~/ide/lib/diff/controller'; -import { computeDiff } from '~/ide/lib/diff/diff'; -import { file } from '../../helpers'; - -describe('Multi-file editor library dirty diff controller', () => { - let editorInstance; - let controller; - let modelManager; - let decorationsController; - let model; - - beforeEach(() => { - editorInstance = Editor.create(); - editorInstance.createInstance(document.createElement('div')); - - modelManager = new ModelManager(); - decorationsController = new DecorationsController(editorInstance); - - model = modelManager.addModel(file('path')); - - controller = new DirtyDiffController(modelManager, decorationsController); - }); - - afterEach(() => { - controller.dispose(); - model.dispose(); - decorationsController.dispose(); - editorInstance.dispose(); - }); - - describe('getDiffChangeType', () => { - ['added', 'removed', 'modified'].forEach(type => { - it(`returns ${type}`, () => { - const change = { - [type]: true, - }; - - expect(getDiffChangeType(change)).toBe(type); - }); - }); - }); - - describe('getDecorator', () => { - ['added', 'removed', 'modified'].forEach(type => { - it(`returns with linesDecorationsClassName for ${type}`, () => { - const change = { - [type]: true, - }; - - expect(getDecorator(change).options.linesDecorationsClassName).toBe( - `dirty-diff dirty-diff-${type}`, - ); - }); - - it('returns with line numbers', () => { - const change = { - lineNumber: 1, - endLineNumber: 2, - [type]: true, - }; - - const { range } = getDecorator(change); - - expect(range.startLineNumber).toBe(1); - expect(range.endLineNumber).toBe(2); - expect(range.startColumn).toBe(1); - expect(range.endColumn).toBe(1); - }); - }); - }); - - describe('attachModel', () => { - it('adds change event callback', () => { - spyOn(model, 'onChange'); - - controller.attachModel(model); - - expect(model.onChange).toHaveBeenCalled(); - }); - - it('adds dispose event callback', () => { - spyOn(model, 'onDispose'); - - controller.attachModel(model); - - expect(model.onDispose).toHaveBeenCalled(); - }); - - it('calls throttledComputeDiff on change', () => { - spyOn(controller, 'throttledComputeDiff'); - - controller.attachModel(model); - - model.getModel().setValue('123'); - - expect(controller.throttledComputeDiff).toHaveBeenCalled(); - }); - - it('caches model', () => { - controller.attachModel(model); - - expect(controller.models.has(model.url)).toBe(true); - }); - }); - - describe('computeDiff', () => { - it('posts to worker', () => { - spyOn(controller.dirtyDiffWorker, 'postMessage'); - - controller.computeDiff(model); - - expect(controller.dirtyDiffWorker.postMessage).toHaveBeenCalledWith({ - path: model.path, - originalContent: '', - newContent: '', - }); - }); - }); - - describe('reDecorate', () => { - it('calls computeDiff when no decorations are cached', () => { - spyOn(controller, 'computeDiff'); - - controller.reDecorate(model); - - expect(controller.computeDiff).toHaveBeenCalledWith(model); - }); - - it('calls decorate when decorations are cached', () => { - spyOn(controller.decorationsController, 'decorate'); - - controller.decorationsController.decorations.set(model.url, 'test'); - - controller.reDecorate(model); - - expect(controller.decorationsController.decorate).toHaveBeenCalledWith(model); - }); - }); - - describe('decorate', () => { - it('adds decorations into decorations controller', () => { - spyOn(controller.decorationsController, 'addDecorations'); - - controller.decorate({ data: { changes: [], path: model.path } }); - - expect(controller.decorationsController.addDecorations).toHaveBeenCalledWith( - model, - 'dirtyDiff', - jasmine.anything(), - ); - }); - - it('adds decorations into editor', () => { - const spy = spyOn(controller.decorationsController.editor.instance, 'deltaDecorations'); - - controller.decorate({ - data: { changes: computeDiff('123', '1234'), path: model.path }, - }); - - expect(spy).toHaveBeenCalledWith( - [], - [ - { - range: new Range(1, 1, 1, 1), - options: { - isWholeLine: true, - linesDecorationsClassName: 'dirty-diff dirty-diff-modified', - }, - }, - ], - ); - }); - }); - - describe('dispose', () => { - it('calls disposable dispose', () => { - spyOn(controller.disposable, 'dispose').and.callThrough(); - - controller.dispose(); - - expect(controller.disposable.dispose).toHaveBeenCalled(); - }); - - it('terminates worker', () => { - spyOn(controller.dirtyDiffWorker, 'terminate').and.callThrough(); - - controller.dispose(); - - expect(controller.dirtyDiffWorker.terminate).toHaveBeenCalled(); - }); - - it('removes worker event listener', () => { - spyOn(controller.dirtyDiffWorker, 'removeEventListener').and.callThrough(); - - controller.dispose(); - - expect(controller.dirtyDiffWorker.removeEventListener).toHaveBeenCalledWith( - 'message', - jasmine.anything(), - ); - }); - - it('clears cached models', () => { - controller.attachModel(model); - - model.dispose(); - - expect(controller.models.size).toBe(0); - }); - }); -}); diff --git a/spec/javascripts/ide/lib/editor_spec.js b/spec/javascripts/ide/lib/editor_spec.js deleted file mode 100644 index 556bd45d3a5..00000000000 --- a/spec/javascripts/ide/lib/editor_spec.js +++ /dev/null @@ -1,287 +0,0 @@ -import { editor as monacoEditor } from 'monaco-editor'; -import Editor from '~/ide/lib/editor'; -import { file } from '../helpers'; - -describe('Multi-file editor library', () => { - let instance; - let el; - let holder; - - beforeEach(() => { - el = document.createElement('div'); - holder = document.createElement('div'); - el.appendChild(holder); - - document.body.appendChild(el); - - instance = Editor.create(); - }); - - afterEach(() => { - instance.dispose(); - - el.remove(); - }); - - it('creates instance of editor', () => { - expect(Editor.editorInstance).not.toBeNull(); - }); - - it('creates instance returns cached instance', () => { - expect(Editor.create()).toEqual(instance); - }); - - describe('createInstance', () => { - it('creates editor instance', () => { - spyOn(monacoEditor, 'create').and.callThrough(); - - instance.createInstance(holder); - - expect(monacoEditor.create).toHaveBeenCalled(); - }); - - it('creates dirty diff controller', () => { - instance.createInstance(holder); - - expect(instance.dirtyDiffController).not.toBeNull(); - }); - - it('creates model manager', () => { - instance.createInstance(holder); - - expect(instance.modelManager).not.toBeNull(); - }); - }); - - describe('createDiffInstance', () => { - it('creates editor instance', () => { - spyOn(monacoEditor, 'createDiffEditor').and.callThrough(); - - instance.createDiffInstance(holder); - - expect(monacoEditor.createDiffEditor).toHaveBeenCalledWith(holder, { - model: null, - contextmenu: true, - minimap: { - enabled: false, - }, - readOnly: true, - scrollBeyondLastLine: false, - renderWhitespace: 'none', - quickSuggestions: false, - occurrencesHighlight: false, - wordWrap: 'on', - renderSideBySide: true, - renderLineHighlight: 'all', - hideCursorInOverviewRuler: false, - theme: 'vs white', - }); - }); - }); - - describe('createModel', () => { - it('calls model manager addModel', () => { - spyOn(instance.modelManager, 'addModel'); - - instance.createModel('FILE'); - - expect(instance.modelManager.addModel).toHaveBeenCalledWith('FILE', null); - }); - }); - - describe('attachModel', () => { - let model; - - beforeEach(() => { - instance.createInstance(document.createElement('div')); - - model = instance.createModel(file()); - }); - - it('sets the current model on the instance', () => { - instance.attachModel(model); - - expect(instance.currentModel).toBe(model); - }); - - it('attaches the model to the current instance', () => { - spyOn(instance.instance, 'setModel'); - - instance.attachModel(model); - - expect(instance.instance.setModel).toHaveBeenCalledWith(model.getModel()); - }); - - it('sets original & modified when diff editor', () => { - spyOn(instance.instance, 'getEditorType').and.returnValue('vs.editor.IDiffEditor'); - spyOn(instance.instance, 'setModel'); - - instance.attachModel(model); - - expect(instance.instance.setModel).toHaveBeenCalledWith({ - original: model.getOriginalModel(), - modified: model.getModel(), - }); - }); - - it('attaches the model to the dirty diff controller', () => { - spyOn(instance.dirtyDiffController, 'attachModel'); - - instance.attachModel(model); - - expect(instance.dirtyDiffController.attachModel).toHaveBeenCalledWith(model); - }); - - it('re-decorates with the dirty diff controller', () => { - spyOn(instance.dirtyDiffController, 'reDecorate'); - - instance.attachModel(model); - - expect(instance.dirtyDiffController.reDecorate).toHaveBeenCalledWith(model); - }); - }); - - describe('attachMergeRequestModel', () => { - let model; - - beforeEach(() => { - instance.createDiffInstance(document.createElement('div')); - - const f = file(); - f.mrChanges = { diff: 'ABC' }; - f.baseRaw = 'testing'; - - model = instance.createModel(f); - }); - - it('sets original & modified', () => { - spyOn(instance.instance, 'setModel'); - - instance.attachMergeRequestModel(model); - - expect(instance.instance.setModel).toHaveBeenCalledWith({ - original: model.getBaseModel(), - modified: model.getModel(), - }); - }); - }); - - describe('clearEditor', () => { - it('resets the editor model', () => { - instance.createInstance(document.createElement('div')); - - spyOn(instance.instance, 'setModel'); - - instance.clearEditor(); - - expect(instance.instance.setModel).toHaveBeenCalledWith(null); - }); - }); - - describe('dispose', () => { - it('calls disposble dispose method', () => { - spyOn(instance.disposable, 'dispose').and.callThrough(); - - instance.dispose(); - - expect(instance.disposable.dispose).toHaveBeenCalled(); - }); - - it('resets instance', () => { - instance.createInstance(document.createElement('div')); - - expect(instance.instance).not.toBeNull(); - - instance.dispose(); - - expect(instance.instance).toBeNull(); - }); - - it('does not dispose modelManager', () => { - spyOn(instance.modelManager, 'dispose'); - - instance.dispose(); - - expect(instance.modelManager.dispose).not.toHaveBeenCalled(); - }); - - it('does not dispose decorationsController', () => { - spyOn(instance.decorationsController, 'dispose'); - - instance.dispose(); - - expect(instance.decorationsController.dispose).not.toHaveBeenCalled(); - }); - }); - - describe('updateDiffView', () => { - describe('edit mode', () => { - it('does not update options', () => { - instance.createInstance(holder); - - spyOn(instance.instance, 'updateOptions'); - - instance.updateDiffView(); - - expect(instance.instance.updateOptions).not.toHaveBeenCalled(); - }); - }); - - describe('diff mode', () => { - beforeEach(() => { - instance.createDiffInstance(holder); - - spyOn(instance.instance, 'updateOptions').and.callThrough(); - }); - - it('sets renderSideBySide to false if el is less than 700 pixels', () => { - spyOnProperty(instance.instance.getDomNode(), 'offsetWidth').and.returnValue(600); - - expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({ - renderSideBySide: false, - }); - }); - - it('sets renderSideBySide to false if el is more than 700 pixels', () => { - spyOnProperty(instance.instance.getDomNode(), 'offsetWidth').and.returnValue(800); - - expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({ - renderSideBySide: true, - }); - }); - }); - }); - - describe('isDiffEditorType', () => { - it('returns true when diff editor', () => { - instance.createDiffInstance(holder); - - expect(instance.isDiffEditorType).toBe(true); - }); - - it('returns false when not diff editor', () => { - instance.createInstance(holder); - - expect(instance.isDiffEditorType).toBe(false); - }); - }); - - it('sets quickSuggestions to false when language is markdown', () => { - instance.createInstance(holder); - - spyOn(instance.instance, 'updateOptions').and.callThrough(); - - const model = instance.createModel({ - ...file(), - key: 'index.md', - path: 'index.md', - }); - - instance.attachModel(model); - - expect(instance.instance.updateOptions).toHaveBeenCalledWith({ - readOnly: false, - quickSuggestions: false, - }); - }); -}); |