Commit 79cfa9a3 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch 'fe-jestodus-ide' into 'master'

Move some IDE specs to Jest

See merge request gitlab-org/gitlab!30398
parents 3d5e0401 45003c2a
/* eslint-disable class-methods-use-this */
export default class WebWorkerMock {
addEventListener() {}
removeEventListener() {}
terminate() {}
postMessage() {}
}
...@@ -26,7 +26,7 @@ describe('IDE activity bar', () => { ...@@ -26,7 +26,7 @@ describe('IDE activity bar', () => {
describe('updateActivityBarView', () => { describe('updateActivityBarView', () => {
beforeEach(() => { beforeEach(() => {
spyOn(vm, 'updateActivityBarView'); jest.spyOn(vm, 'updateActivityBarView').mockImplementation(() => {});
vm.$mount(); vm.$mount();
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
import Bar from '~/ide/components/file_templates/bar.vue'; import Bar from '~/ide/components/file_templates/bar.vue';
import { resetStore, file } from '../../helpers'; import { resetStore, file } from '../../helpers';
...@@ -35,7 +35,7 @@ describe('IDE file templates bar component', () => { ...@@ -35,7 +35,7 @@ describe('IDE file templates bar component', () => {
}); });
it('calls setSelectedTemplateType when clicking item', () => { it('calls setSelectedTemplateType when clicking item', () => {
spyOn(vm, 'setSelectedTemplateType').and.stub(); jest.spyOn(vm, 'setSelectedTemplateType').mockImplementation();
vm.$el.querySelector('.dropdown-content button').click(); vm.$el.querySelector('.dropdown-content button').click();
...@@ -66,7 +66,7 @@ describe('IDE file templates bar component', () => { ...@@ -66,7 +66,7 @@ describe('IDE file templates bar component', () => {
}); });
it('calls fetchTemplate on click', () => { it('calls fetchTemplate on click', () => {
spyOn(vm, 'fetchTemplate').and.stub(); jest.spyOn(vm, 'fetchTemplate').mockImplementation();
vm.$el vm.$el
.querySelectorAll('.dropdown-content')[1] .querySelectorAll('.dropdown-content')[1]
...@@ -90,7 +90,7 @@ describe('IDE file templates bar component', () => { ...@@ -90,7 +90,7 @@ describe('IDE file templates bar component', () => {
}); });
it('calls undoFileTemplate when clicking undo button', () => { it('calls undoFileTemplate when clicking undo button', () => {
spyOn(vm, 'undoFileTemplate').and.stub(); jest.spyOn(vm, 'undoFileTemplate').mockImplementation();
vm.$el.querySelector('.btn-default').click(); vm.$el.querySelector('.btn-default').click();
...@@ -100,7 +100,7 @@ describe('IDE file templates bar component', () => { ...@@ -100,7 +100,7 @@ describe('IDE file templates bar component', () => {
it('calls setSelectedTemplateType if activeFile name matches a template', done => { it('calls setSelectedTemplateType if activeFile name matches a template', done => {
const fileName = '.gitlab-ci.yml'; const fileName = '.gitlab-ci.yml';
spyOn(vm, 'setSelectedTemplateType'); jest.spyOn(vm, 'setSelectedTemplateType').mockImplementation(() => {});
vm.$store.state.openFiles[0].name = fileName; vm.$store.state.openFiles[0].name = fileName;
vm.setInitialType(); vm.setInitialType();
......
import Vue from 'vue'; import Vue from 'vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import store from '~/ide/stores'; import store from '~/ide/stores';
import ideSidebar from '~/ide/components/ide_side_bar.vue'; import ideSidebar from '~/ide/components/ide_side_bar.vue';
import { leftSidebarViews } from '~/ide/constants'; import { leftSidebarViews } from '~/ide/constants';
......
import Vue from 'vue'; import Vue from 'vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import store from '~/ide/stores'; import store from '~/ide/stores';
import ide from '~/ide/components/ide.vue'; import ide from '~/ide/components/ide.vue';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
......
...@@ -35,7 +35,7 @@ describe('IDE tree list', () => { ...@@ -35,7 +35,7 @@ describe('IDE tree list', () => {
beforeEach(() => { beforeEach(() => {
bootstrapWithTree(); bootstrapWithTree();
spyOn(vm, 'updateViewer').and.callThrough(); jest.spyOn(vm, 'updateViewer');
vm.$mount(); vm.$mount();
}); });
...@@ -64,7 +64,7 @@ describe('IDE tree list', () => { ...@@ -64,7 +64,7 @@ describe('IDE tree list', () => {
beforeEach(() => { beforeEach(() => {
bootstrapWithTree(emptyBranchTree); bootstrapWithTree(emptyBranchTree);
spyOn(vm, 'updateViewer').and.callThrough(); jest.spyOn(vm, 'updateViewer');
vm.$mount(); vm.$mount();
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import { trimText } from 'spec/helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import NavDropdownButton from '~/ide/components/nav_dropdown_button.vue'; import NavDropdownButton from '~/ide/components/nav_dropdown_button.vue';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
......
import $ from 'jquery';
import { mount } from '@vue/test-utils';
import { createStore } 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', () => {
let store;
let wrapper;
beforeEach(() => {
store = createStore();
Object.assign(store.state, {
currentProjectId: TEST_PROJECT_ID,
currentBranchId: 'master',
projects: {
[TEST_PROJECT_ID]: {
userPermissions: {
[PERMISSION_READ_MR]: true,
},
branches: {
master: { id: 'master' },
},
},
},
});
jest.spyOn(store, 'dispatch').mockImplementation(() => {});
});
afterEach(() => {
wrapper.destroy();
});
const createComponent = () => {
wrapper = mount(NavDropdown, {
store,
});
};
const findIcon = name => wrapper.find(`.ic-${name}`);
const findMRIcon = () => findIcon('merge-request');
const findNavForm = () => wrapper.find('.ide-nav-form');
const showDropdown = () => {
$(wrapper.vm.$el).trigger('show.bs.dropdown');
};
const hideDropdown = () => {
$(wrapper.vm.$el).trigger('hide.bs.dropdown');
};
describe('default', () => {
beforeEach(() => {
createComponent();
});
it('renders nothing initially', () => {
expect(findNavForm().exists()).toBe(false);
});
it('renders nav form when show.bs.dropdown', done => {
showDropdown();
wrapper.vm
.$nextTick()
.then(() => {
expect(findNavForm().exists()).toBe(true);
})
.then(done)
.catch(done.fail);
});
it('destroys nav form when closed', done => {
showDropdown();
hideDropdown();
wrapper.vm
.$nextTick()
.then(() => {
expect(findNavForm().exists()).toBe(false);
})
.then(done)
.catch(done.fail);
});
it('renders merge request icon', () => {
expect(findMRIcon().exists()).toBe(true);
});
});
describe('when user cannot read merge requests', () => {
beforeEach(() => {
store.state.projects[TEST_PROJECT_ID].userPermissions = {};
createComponent();
});
it('does not render merge requests', () => {
expect(findMRIcon().exists()).toBe(false);
});
});
});
import Vue from 'vue'; import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import Button from '~/ide/components/new_dropdown/button.vue'; import Button from '~/ide/components/new_dropdown/button.vue';
describe('IDE new entry dropdown button component', () => { describe('IDE new entry dropdown button component', () => {
...@@ -16,7 +16,7 @@ describe('IDE new entry dropdown button component', () => { ...@@ -16,7 +16,7 @@ describe('IDE new entry dropdown button component', () => {
icon: 'doc-new', icon: 'doc-new',
}); });
spyOn(vm, '$emit'); jest.spyOn(vm, '$emit').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
......
import Vue from 'vue'; import Vue from 'vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import store from '~/ide/stores'; import store from '~/ide/stores';
import newDropdown from '~/ide/components/new_dropdown/index.vue'; import newDropdown from '~/ide/components/new_dropdown/index.vue';
import { resetStore } from '../../helpers'; import { resetStore } from '../../helpers';
...@@ -23,7 +23,7 @@ describe('new dropdown component', () => { ...@@ -23,7 +23,7 @@ describe('new dropdown component', () => {
tree: [], tree: [],
}; };
spyOn(vm, 'openNewEntryModal'); jest.spyOn(vm, 'openNewEntryModal').mockImplementation(() => {});
vm.$mount(); vm.$mount();
}); });
...@@ -58,11 +58,11 @@ describe('new dropdown component', () => { ...@@ -58,11 +58,11 @@ describe('new dropdown component', () => {
describe('isOpen', () => { describe('isOpen', () => {
it('scrolls dropdown into view', done => { it('scrolls dropdown into view', done => {
spyOn(vm.$refs.dropdownMenu, 'scrollIntoView'); jest.spyOn(vm.$refs.dropdownMenu, 'scrollIntoView').mockImplementation(() => {});
vm.isOpen = true; vm.isOpen = true;
setTimeout(() => { setImmediate(() => {
expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalledWith({ expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalledWith({
block: 'nearest', block: 'nearest',
}); });
...@@ -74,7 +74,7 @@ describe('new dropdown component', () => { ...@@ -74,7 +74,7 @@ describe('new dropdown component', () => {
describe('delete entry', () => { describe('delete entry', () => {
it('calls delete action', () => { it('calls delete action', () => {
spyOn(vm, 'deleteEntry'); jest.spyOn(vm, 'deleteEntry').mockImplementation(() => {});
vm.$el.querySelectorAll('.dropdown-menu button')[4].click(); vm.$el.querySelectorAll('.dropdown-menu button')[4].click();
......
import Vue from 'vue'; import Vue from 'vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
import modal from '~/ide/components/new_dropdown/modal.vue'; import modal from '~/ide/components/new_dropdown/modal.vue';
import createFlash from '~/flash';
jest.mock('~/flash');
describe('new file modal component', () => { describe('new file modal component', () => {
const Component = Vue.extend(modal); const Component = Vue.extend(modal);
...@@ -11,47 +14,45 @@ describe('new file modal component', () => { ...@@ -11,47 +14,45 @@ describe('new file modal component', () => {
vm.$destroy(); vm.$destroy();
}); });
['tree', 'blob'].forEach(type => { describe.each(['tree', 'blob'])('%s', type => {
describe(type, () => { beforeEach(() => {
beforeEach(() => { const store = createStore();
const store = createStore(); store.state.entryModal = {
store.state.entryModal = { type,
type, path: '',
entry: {
path: '', path: '',
entry: { },
path: '', };
},
};
vm = createComponentWithStore(Component, store).$mount(); vm = createComponentWithStore(Component, store).$mount();
vm.name = 'testing'; vm.name = 'testing';
}); });
it(`sets modal title as ${type}`, () => { it(`sets modal title as ${type}`, () => {
const title = type === 'tree' ? 'directory' : 'file'; const title = type === 'tree' ? 'directory' : 'file';
expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Create new ${title}`); expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Create new ${title}`);
}); });
it(`sets button label as ${type}`, () => { it(`sets button label as ${type}`, () => {
const title = type === 'tree' ? 'directory' : 'file'; const title = type === 'tree' ? 'directory' : 'file';
expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Create ${title}`); expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Create ${title}`);
}); });
it(`sets form label as ${type}`, () => { it(`sets form label as ${type}`, () => {
expect(vm.$el.querySelector('.label-bold').textContent.trim()).toBe('Name'); expect(vm.$el.querySelector('.label-bold').textContent.trim()).toBe('Name');
}); });
it(`${type === 'tree' ? 'does not show' : 'shows'} file templates`, () => { it(`${type === 'tree' ? 'does not show' : 'shows'} file templates`, () => {
const templateFilesEl = vm.$el.querySelector('.file-templates'); const templateFilesEl = vm.$el.querySelector('.file-templates');
if (type === 'tree') { if (type === 'tree') {
expect(templateFilesEl).toBeNull(); expect(templateFilesEl).toBeNull();
} else { } else {
expect(templateFilesEl instanceof Element).toBeTruthy(); expect(templateFilesEl instanceof Element).toBeTruthy();
} }
});
}); });
}); });
...@@ -131,16 +132,15 @@ describe('new file modal component', () => { ...@@ -131,16 +132,15 @@ describe('new file modal component', () => {
}; };
vm = createComponentWithStore(Component, store).$mount(); vm = createComponentWithStore(Component, store).$mount();
const flashSpy = spyOnDependency(modal, 'flash');
expect(flashSpy).not.toHaveBeenCalled(); expect(createFlash).not.toHaveBeenCalled();
vm.submitForm(); vm.submitForm();
expect(flashSpy).toHaveBeenCalledWith( expect(createFlash).toHaveBeenCalledWith(
'The name "test-path/test" is already taken in this directory.', 'The name "test-path/test" is already taken in this directory.',
'alert', 'alert',
jasmine.anything(), expect.anything(),
null, null,
false, false,
true, true,
......
...@@ -17,7 +17,7 @@ describe('RepoTab', () => { ...@@ -17,7 +17,7 @@ describe('RepoTab', () => {
} }
beforeEach(() => { beforeEach(() => {
spyOn(router, 'push'); jest.spyOn(router, 'push').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
...@@ -47,7 +47,7 @@ describe('RepoTab', () => { ...@@ -47,7 +47,7 @@ describe('RepoTab', () => {
}, },
}); });
spyOn(vm, 'openPendingTab'); jest.spyOn(vm, 'openPendingTab').mockImplementation(() => {});
vm.$el.click(); vm.$el.click();
...@@ -63,7 +63,7 @@ describe('RepoTab', () => { ...@@ -63,7 +63,7 @@ describe('RepoTab', () => {
tab: file(), tab: file(),
}); });
spyOn(vm, 'clickFile'); jest.spyOn(vm, 'clickFile').mockImplementation(() => {});
vm.$el.click(); vm.$el.click();
...@@ -75,7 +75,7 @@ describe('RepoTab', () => { ...@@ -75,7 +75,7 @@ describe('RepoTab', () => {
tab: file(), tab: file(),
}); });
spyOn(vm, 'closeFile'); jest.spyOn(vm, 'closeFile').mockImplementation(() => {});
vm.$el.querySelector('.multi-file-tab-close').click(); vm.$el.querySelector('.multi-file-tab-close').click();
......
import Vue from 'vue'; import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import TokenedInput from '~/ide/components/shared/tokened_input.vue'; import TokenedInput from '~/ide/components/shared/tokened_input.vue';
const TEST_PLACEHOLDER = 'Searching in test'; const TEST_PLACEHOLDER = 'Searching in test';
...@@ -36,7 +36,7 @@ describe('IDE shared/TokenedInput', () => { ...@@ -36,7 +36,7 @@ describe('IDE shared/TokenedInput', () => {
value: TEST_VALUE, value: TEST_VALUE,
}); });
spyOn(vm, '$emit'); jest.spyOn(vm, '$emit').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
...@@ -72,7 +72,7 @@ describe('IDE shared/TokenedInput', () => { ...@@ -72,7 +72,7 @@ describe('IDE shared/TokenedInput', () => {
}); });
it('when input triggers backspace event, it calls "onBackspace"', () => { it('when input triggers backspace event, it calls "onBackspace"', () => {
spyOn(vm, 'onBackspace'); jest.spyOn(vm, 'onBackspace').mockImplementation(() => {});
vm.$refs.input.dispatchEvent(createBackspaceEvent()); vm.$refs.input.dispatchEvent(createBackspaceEvent());
vm.$refs.input.dispatchEvent(createBackspaceEvent()); vm.$refs.input.dispatchEvent(createBackspaceEvent());
......
...@@ -28,7 +28,7 @@ describe('Multi-file editor library model manager', () => { ...@@ -28,7 +28,7 @@ describe('Multi-file editor library model manager', () => {
}); });
it('adds model into disposable', () => { it('adds model into disposable', () => {
spyOn(instance.disposable, 'add').and.callThrough(); jest.spyOn(instance.disposable, 'add');
instance.addModel(file()); instance.addModel(file());
...@@ -36,7 +36,7 @@ describe('Multi-file editor library model manager', () => { ...@@ -36,7 +36,7 @@ describe('Multi-file editor library model manager', () => {
}); });
it('returns cached model', () => { it('returns cached model', () => {
spyOn(instance.models, 'get').and.callThrough(); jest.spyOn(instance.models, 'get');
instance.addModel(file()); instance.addModel(file());
instance.addModel(file()); instance.addModel(file());
...@@ -46,13 +46,13 @@ describe('Multi-file editor library model manager', () => { ...@@ -46,13 +46,13 @@ describe('Multi-file editor library model manager', () => {
it('adds eventHub listener', () => { it('adds eventHub listener', () => {
const f = file(); const f = file();
spyOn(eventHub, '$on').and.callThrough(); jest.spyOn(eventHub, '$on');
instance.addModel(f); instance.addModel(f);
expect(eventHub.$on).toHaveBeenCalledWith( expect(eventHub.$on).toHaveBeenCalledWith(
`editor.update.model.dispose.${f.key}`, `editor.update.model.dispose.${f.key}`,
jasmine.anything(), expect.anything(),
); );
}); });
}); });
...@@ -95,13 +95,13 @@ describe('Multi-file editor library model manager', () => { ...@@ -95,13 +95,13 @@ describe('Multi-file editor library model manager', () => {
}); });
it('removes eventHub listener', () => { it('removes eventHub listener', () => {
spyOn(eventHub, '$off').and.callThrough(); jest.spyOn(eventHub, '$off');
instance.removeCachedModel(f); instance.removeCachedModel(f);
expect(eventHub.$off).toHaveBeenCalledWith( expect(eventHub.$off).toHaveBeenCalledWith(
`editor.update.model.dispose.${f.key}`, `editor.update.model.dispose.${f.key}`,
jasmine.anything(), expect.anything(),
); );
}); });
}); });
...@@ -116,7 +116,7 @@ describe('Multi-file editor library model manager', () => { ...@@ -116,7 +116,7 @@ describe('Multi-file editor library model manager', () => {
}); });
it('calls disposable dispose', () => { it('calls disposable dispose', () => {
spyOn(instance.disposable, 'dispose').and.callThrough(); jest.spyOn(instance.disposable, 'dispose');
instance.dispose(); instance.dispose();
......
...@@ -6,7 +6,7 @@ describe('Multi-file editor library model', () => { ...@@ -6,7 +6,7 @@ describe('Multi-file editor library model', () => {
let model; let model;
beforeEach(() => { beforeEach(() => {
spyOn(eventHub, '$on').and.callThrough(); jest.spyOn(eventHub, '$on');
const f = file('path'); const f = file('path');
f.mrChange = { diff: 'ABC' }; f.mrChange = { diff: 'ABC' };
...@@ -44,7 +44,7 @@ describe('Multi-file editor library model', () => { ...@@ -44,7 +44,7 @@ describe('Multi-file editor library model', () => {
it('adds eventHub listener', () => { it('adds eventHub listener', () => {
expect(eventHub.$on).toHaveBeenCalledWith( expect(eventHub.$on).toHaveBeenCalledWith(
`editor.update.model.dispose.${model.file.key}`, `editor.update.model.dispose.${model.file.key}`,
jasmine.anything(), expect.anything(),
); );
}); });
...@@ -82,13 +82,13 @@ describe('Multi-file editor library model', () => { ...@@ -82,13 +82,13 @@ describe('Multi-file editor library model', () => {
describe('onChange', () => { describe('onChange', () => {
it('calls callback on change', done => { it('calls callback on change', done => {
const spy = jasmine.createSpy(); const spy = jest.fn();
model.onChange(spy); model.onChange(spy);
model.getModel().setValue('123'); model.getModel().setValue('123');
setTimeout(() => { setImmediate(() => {
expect(spy).toHaveBeenCalledWith(model, jasmine.anything()); expect(spy).toHaveBeenCalledWith(model, expect.anything());
done(); done();
}); });
}); });
...@@ -96,7 +96,7 @@ describe('Multi-file editor library model', () => { ...@@ -96,7 +96,7 @@ describe('Multi-file editor library model', () => {
describe('dispose', () => { describe('dispose', () => {
it('calls disposable dispose', () => { it('calls disposable dispose', () => {
spyOn(model.disposable, 'dispose').and.callThrough(); jest.spyOn(model.disposable, 'dispose');
model.dispose(); model.dispose();
...@@ -114,18 +114,18 @@ describe('Multi-file editor library model', () => { ...@@ -114,18 +114,18 @@ describe('Multi-file editor library model', () => {
}); });
it('removes eventHub listener', () => { it('removes eventHub listener', () => {
spyOn(eventHub, '$off').and.callThrough(); jest.spyOn(eventHub, '$off');
model.dispose(); model.dispose();
expect(eventHub.$off).toHaveBeenCalledWith( expect(eventHub.$off).toHaveBeenCalledWith(
`editor.update.model.dispose.${model.file.key}`, `editor.update.model.dispose.${model.file.key}`,
jasmine.anything(), expect.anything(),
); );
}); });
it('calls onDispose callback', () => { it('calls onDispose callback', () => {
const disposeSpy = jasmine.createSpy(); const disposeSpy = jest.fn();
model.onDispose(disposeSpy); model.onDispose(disposeSpy);
......
...@@ -60,7 +60,7 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -60,7 +60,7 @@ describe('Multi-file editor library decorations controller', () => {
}); });
it('calls decorate method', () => { it('calls decorate method', () => {
spyOn(controller, 'decorate'); jest.spyOn(controller, 'decorate').mockImplementation(() => {});
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]);
...@@ -70,7 +70,7 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -70,7 +70,7 @@ describe('Multi-file editor library decorations controller', () => {
describe('decorate', () => { describe('decorate', () => {
it('sets decorations on editor instance', () => { it('sets decorations on editor instance', () => {
spyOn(controller.editor.instance, 'deltaDecorations'); jest.spyOn(controller.editor.instance, 'deltaDecorations').mockImplementation(() => {});
controller.decorate(model); controller.decorate(model);
...@@ -78,7 +78,7 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -78,7 +78,7 @@ describe('Multi-file editor library decorations controller', () => {
}); });
it('caches decorations', () => { it('caches decorations', () => {
spyOn(controller.editor.instance, 'deltaDecorations').and.returnValue([]); jest.spyOn(controller.editor.instance, 'deltaDecorations').mockReturnValue([]);
controller.decorate(model); controller.decorate(model);
...@@ -86,7 +86,7 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -86,7 +86,7 @@ describe('Multi-file editor library decorations controller', () => {
}); });
it('caches decorations by model URL', () => { it('caches decorations by model URL', () => {
spyOn(controller.editor.instance, 'deltaDecorations').and.returnValue([]); jest.spyOn(controller.editor.instance, 'deltaDecorations').mockReturnValue([]);
controller.decorate(model); controller.decorate(model);
......
...@@ -75,7 +75,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -75,7 +75,7 @@ describe('Multi-file editor library dirty diff controller', () => {
describe('attachModel', () => { describe('attachModel', () => {
it('adds change event callback', () => { it('adds change event callback', () => {
spyOn(model, 'onChange'); jest.spyOn(model, 'onChange').mockImplementation(() => {});
controller.attachModel(model); controller.attachModel(model);
...@@ -83,7 +83,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -83,7 +83,7 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
it('adds dispose event callback', () => { it('adds dispose event callback', () => {
spyOn(model, 'onDispose'); jest.spyOn(model, 'onDispose').mockImplementation(() => {});
controller.attachModel(model); controller.attachModel(model);
...@@ -91,7 +91,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -91,7 +91,7 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
it('calls throttledComputeDiff on change', () => { it('calls throttledComputeDiff on change', () => {
spyOn(controller, 'throttledComputeDiff'); jest.spyOn(controller, 'throttledComputeDiff').mockImplementation(() => {});
controller.attachModel(model); controller.attachModel(model);
...@@ -109,7 +109,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -109,7 +109,7 @@ describe('Multi-file editor library dirty diff controller', () => {
describe('computeDiff', () => { describe('computeDiff', () => {
it('posts to worker', () => { it('posts to worker', () => {
spyOn(controller.dirtyDiffWorker, 'postMessage'); jest.spyOn(controller.dirtyDiffWorker, 'postMessage').mockImplementation(() => {});
controller.computeDiff(model); controller.computeDiff(model);
...@@ -123,7 +123,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -123,7 +123,7 @@ describe('Multi-file editor library dirty diff controller', () => {
describe('reDecorate', () => { describe('reDecorate', () => {
it('calls computeDiff when no decorations are cached', () => { it('calls computeDiff when no decorations are cached', () => {
spyOn(controller, 'computeDiff'); jest.spyOn(controller, 'computeDiff').mockImplementation(() => {});
controller.reDecorate(model); controller.reDecorate(model);
...@@ -131,7 +131,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -131,7 +131,7 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
it('calls decorate when decorations are cached', () => { it('calls decorate when decorations are cached', () => {
spyOn(controller.decorationsController, 'decorate'); jest.spyOn(controller.decorationsController, 'decorate').mockImplementation(() => {});
controller.decorationsController.decorations.set(model.url, 'test'); controller.decorationsController.decorations.set(model.url, 'test');
...@@ -143,19 +143,19 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -143,19 +143,19 @@ describe('Multi-file editor library dirty diff controller', () => {
describe('decorate', () => { describe('decorate', () => {
it('adds decorations into decorations controller', () => { it('adds decorations into decorations controller', () => {
spyOn(controller.decorationsController, 'addDecorations'); jest.spyOn(controller.decorationsController, 'addDecorations').mockImplementation(() => {});
controller.decorate({ data: { changes: [], path: model.path } }); controller.decorate({ data: { changes: [], path: model.path } });
expect(controller.decorationsController.addDecorations).toHaveBeenCalledWith( expect(controller.decorationsController.addDecorations).toHaveBeenCalledWith(
model, model,
'dirtyDiff', 'dirtyDiff',
jasmine.anything(), expect.anything(),
); );
}); });
it('adds decorations into editor', () => { it('adds decorations into editor', () => {
const spy = spyOn(controller.decorationsController.editor.instance, 'deltaDecorations'); const spy = jest.spyOn(controller.decorationsController.editor.instance, 'deltaDecorations');
controller.decorate({ controller.decorate({
data: { changes: computeDiff('123', '1234'), path: model.path }, data: { changes: computeDiff('123', '1234'), path: model.path },
...@@ -178,7 +178,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -178,7 +178,7 @@ describe('Multi-file editor library dirty diff controller', () => {
describe('dispose', () => { describe('dispose', () => {
it('calls disposable dispose', () => { it('calls disposable dispose', () => {
spyOn(controller.disposable, 'dispose').and.callThrough(); jest.spyOn(controller.disposable, 'dispose');
controller.dispose(); controller.dispose();
...@@ -186,7 +186,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -186,7 +186,7 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
it('terminates worker', () => { it('terminates worker', () => {
spyOn(controller.dirtyDiffWorker, 'terminate').and.callThrough(); jest.spyOn(controller.dirtyDiffWorker, 'terminate');
controller.dispose(); controller.dispose();
...@@ -194,13 +194,13 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -194,13 +194,13 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
it('removes worker event listener', () => { it('removes worker event listener', () => {
spyOn(controller.dirtyDiffWorker, 'removeEventListener').and.callThrough(); jest.spyOn(controller.dirtyDiffWorker, 'removeEventListener');
controller.dispose(); controller.dispose();
expect(controller.dirtyDiffWorker.removeEventListener).toHaveBeenCalledWith( expect(controller.dirtyDiffWorker.removeEventListener).toHaveBeenCalledWith(
'message', 'message',
jasmine.anything(), expect.anything(),
); );
}); });
......
import { editor as monacoEditor } from 'monaco-editor'; import { editor as monacoEditor } from 'monaco-editor';
import Editor from '~/ide/lib/editor'; import Editor from '~/ide/lib/editor';
import { defaultEditorOptions } from '~/ide/lib/editor_options';
import { file } from '../helpers'; import { file } from '../helpers';
describe('Multi-file editor library', () => { describe('Multi-file editor library', () => {
...@@ -7,6 +8,14 @@ describe('Multi-file editor library', () => { ...@@ -7,6 +8,14 @@ describe('Multi-file editor library', () => {
let el; let el;
let holder; let holder;
const setNodeOffsetWidth = val => {
Object.defineProperty(instance.instance.getDomNode(), 'offsetWidth', {
get() {
return val;
},
});
};
beforeEach(() => { beforeEach(() => {
el = document.createElement('div'); el = document.createElement('div');
holder = document.createElement('div'); holder = document.createElement('div');
...@@ -18,7 +27,9 @@ describe('Multi-file editor library', () => { ...@@ -18,7 +27,9 @@ describe('Multi-file editor library', () => {
}); });
afterEach(() => { afterEach(() => {
instance.modelManager.dispose();
instance.dispose(); instance.dispose();
Editor.editorInstance = null;
el.remove(); el.remove();
}); });
...@@ -33,7 +44,7 @@ describe('Multi-file editor library', () => { ...@@ -33,7 +44,7 @@ describe('Multi-file editor library', () => {
describe('createInstance', () => { describe('createInstance', () => {
it('creates editor instance', () => { it('creates editor instance', () => {
spyOn(monacoEditor, 'create').and.callThrough(); jest.spyOn(monacoEditor, 'create');
instance.createInstance(holder); instance.createInstance(holder);
...@@ -55,33 +66,25 @@ describe('Multi-file editor library', () => { ...@@ -55,33 +66,25 @@ describe('Multi-file editor library', () => {
describe('createDiffInstance', () => { describe('createDiffInstance', () => {
it('creates editor instance', () => { it('creates editor instance', () => {
spyOn(monacoEditor, 'createDiffEditor').and.callThrough(); jest.spyOn(monacoEditor, 'createDiffEditor');
instance.createDiffInstance(holder); instance.createDiffInstance(holder);
expect(monacoEditor.createDiffEditor).toHaveBeenCalledWith(holder, { expect(monacoEditor.createDiffEditor).toHaveBeenCalledWith(holder, {
model: null, ...defaultEditorOptions,
contextmenu: true,
minimap: {
enabled: false,
},
readOnly: true,
scrollBeyondLastLine: false,
renderWhitespace: 'none',
quickSuggestions: false, quickSuggestions: false,
occurrencesHighlight: false, occurrencesHighlight: false,
wordWrap: 'on', renderSideBySide: false,
renderSideBySide: true, readOnly: true,
renderLineHighlight: 'all', renderLineHighlight: 'all',
hideCursorInOverviewRuler: false, hideCursorInOverviewRuler: false,
theme: 'vs white',
}); });
}); });
}); });
describe('createModel', () => { describe('createModel', () => {
it('calls model manager addModel', () => { it('calls model manager addModel', () => {
spyOn(instance.modelManager, 'addModel'); jest.spyOn(instance.modelManager, 'addModel').mockImplementation(() => {});
instance.createModel('FILE'); instance.createModel('FILE');
...@@ -105,7 +108,7 @@ describe('Multi-file editor library', () => { ...@@ -105,7 +108,7 @@ describe('Multi-file editor library', () => {
}); });
it('attaches the model to the current instance', () => { it('attaches the model to the current instance', () => {
spyOn(instance.instance, 'setModel'); jest.spyOn(instance.instance, 'setModel').mockImplementation(() => {});
instance.attachModel(model); instance.attachModel(model);
...@@ -113,8 +116,8 @@ describe('Multi-file editor library', () => { ...@@ -113,8 +116,8 @@ describe('Multi-file editor library', () => {
}); });
it('sets original & modified when diff editor', () => { it('sets original & modified when diff editor', () => {
spyOn(instance.instance, 'getEditorType').and.returnValue('vs.editor.IDiffEditor'); jest.spyOn(instance.instance, 'getEditorType').mockReturnValue('vs.editor.IDiffEditor');
spyOn(instance.instance, 'setModel'); jest.spyOn(instance.instance, 'setModel').mockImplementation(() => {});
instance.attachModel(model); instance.attachModel(model);
...@@ -125,7 +128,7 @@ describe('Multi-file editor library', () => { ...@@ -125,7 +128,7 @@ describe('Multi-file editor library', () => {
}); });
it('attaches the model to the dirty diff controller', () => { it('attaches the model to the dirty diff controller', () => {
spyOn(instance.dirtyDiffController, 'attachModel'); jest.spyOn(instance.dirtyDiffController, 'attachModel').mockImplementation(() => {});
instance.attachModel(model); instance.attachModel(model);
...@@ -133,7 +136,7 @@ describe('Multi-file editor library', () => { ...@@ -133,7 +136,7 @@ describe('Multi-file editor library', () => {
}); });
it('re-decorates with the dirty diff controller', () => { it('re-decorates with the dirty diff controller', () => {
spyOn(instance.dirtyDiffController, 'reDecorate'); jest.spyOn(instance.dirtyDiffController, 'reDecorate').mockImplementation(() => {});
instance.attachModel(model); instance.attachModel(model);
...@@ -155,7 +158,7 @@ describe('Multi-file editor library', () => { ...@@ -155,7 +158,7 @@ describe('Multi-file editor library', () => {
}); });
it('sets original & modified', () => { it('sets original & modified', () => {
spyOn(instance.instance, 'setModel'); jest.spyOn(instance.instance, 'setModel').mockImplementation(() => {});
instance.attachMergeRequestModel(model); instance.attachMergeRequestModel(model);
...@@ -170,7 +173,7 @@ describe('Multi-file editor library', () => { ...@@ -170,7 +173,7 @@ describe('Multi-file editor library', () => {
it('resets the editor model', () => { it('resets the editor model', () => {
instance.createInstance(document.createElement('div')); instance.createInstance(document.createElement('div'));
spyOn(instance.instance, 'setModel'); jest.spyOn(instance.instance, 'setModel').mockImplementation(() => {});
instance.clearEditor(); instance.clearEditor();
...@@ -180,7 +183,7 @@ describe('Multi-file editor library', () => { ...@@ -180,7 +183,7 @@ describe('Multi-file editor library', () => {
describe('dispose', () => { describe('dispose', () => {
it('calls disposble dispose method', () => { it('calls disposble dispose method', () => {
spyOn(instance.disposable, 'dispose').and.callThrough(); jest.spyOn(instance.disposable, 'dispose');
instance.dispose(); instance.dispose();
...@@ -198,7 +201,7 @@ describe('Multi-file editor library', () => { ...@@ -198,7 +201,7 @@ describe('Multi-file editor library', () => {
}); });
it('does not dispose modelManager', () => { it('does not dispose modelManager', () => {
spyOn(instance.modelManager, 'dispose'); jest.spyOn(instance.modelManager, 'dispose').mockImplementation(() => {});
instance.dispose(); instance.dispose();
...@@ -206,7 +209,7 @@ describe('Multi-file editor library', () => { ...@@ -206,7 +209,7 @@ describe('Multi-file editor library', () => {
}); });
it('does not dispose decorationsController', () => { it('does not dispose decorationsController', () => {
spyOn(instance.decorationsController, 'dispose'); jest.spyOn(instance.decorationsController, 'dispose').mockImplementation(() => {});
instance.dispose(); instance.dispose();
...@@ -219,7 +222,7 @@ describe('Multi-file editor library', () => { ...@@ -219,7 +222,7 @@ describe('Multi-file editor library', () => {
it('does not update options', () => { it('does not update options', () => {
instance.createInstance(holder); instance.createInstance(holder);
spyOn(instance.instance, 'updateOptions'); jest.spyOn(instance.instance, 'updateOptions').mockImplementation(() => {});
instance.updateDiffView(); instance.updateDiffView();
...@@ -231,11 +234,11 @@ describe('Multi-file editor library', () => { ...@@ -231,11 +234,11 @@ describe('Multi-file editor library', () => {
beforeEach(() => { beforeEach(() => {
instance.createDiffInstance(holder); instance.createDiffInstance(holder);
spyOn(instance.instance, 'updateOptions').and.callThrough(); jest.spyOn(instance.instance, 'updateOptions');
}); });
it('sets renderSideBySide to false if el is less than 700 pixels', () => { it('sets renderSideBySide to false if el is less than 700 pixels', () => {
spyOnProperty(instance.instance.getDomNode(), 'offsetWidth').and.returnValue(600); setNodeOffsetWidth(600);
expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({ expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({
renderSideBySide: false, renderSideBySide: false,
...@@ -243,7 +246,7 @@ describe('Multi-file editor library', () => { ...@@ -243,7 +246,7 @@ describe('Multi-file editor library', () => {
}); });
it('sets renderSideBySide to false if el is more than 700 pixels', () => { it('sets renderSideBySide to false if el is more than 700 pixels', () => {
spyOnProperty(instance.instance.getDomNode(), 'offsetWidth').and.returnValue(800); setNodeOffsetWidth(800);
expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({ expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({
renderSideBySide: true, renderSideBySide: true,
...@@ -269,7 +272,7 @@ describe('Multi-file editor library', () => { ...@@ -269,7 +272,7 @@ describe('Multi-file editor library', () => {
it('sets quickSuggestions to false when language is markdown', () => { it('sets quickSuggestions to false when language is markdown', () => {
instance.createInstance(holder); instance.createInstance(holder);
spyOn(instance.instance, 'updateOptions').and.callThrough(); jest.spyOn(instance.instance, 'updateOptions');
const model = instance.createModel({ const model = instance.createModel({
...file(), ...file(),
......
/* eslint-disable class-methods-use-this */ export { default } from 'helpers/web_worker_mock';
export default class TreeWorkerMock {
addEventListener() {}
terminate() {}
postMessage() {}
}
export { default } from 'helpers/web_worker_mock';
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();
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment