summaryrefslogtreecommitdiff
path: root/spec/frontend/ide
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/ide')
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js75
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_spec.js1
-rw-r--r--spec/frontend/ide/components/ide_side_bar_spec.js44
-rw-r--r--spec/frontend/ide/components/ide_spec.js214
-rw-r--r--spec/frontend/ide/components/ide_status_list_spec.js27
-rw-r--r--spec/frontend/ide/components/pipelines/list_spec.js7
-rw-r--r--spec/frontend/ide/components/repo_editor_spec.js7
-rw-r--r--spec/frontend/ide/components/repo_tab_spec.js16
-rw-r--r--spec/frontend/ide/components/terminal/empty_state_spec.js21
-rw-r--r--spec/frontend/ide/helpers.js15
-rw-r--r--spec/frontend/ide/stores/actions/file_spec.js14
-rw-r--r--spec/frontend/ide/stores/actions_spec.js12
-rw-r--r--spec/frontend/ide/stores/modules/editor/actions_spec.js36
-rw-r--r--spec/frontend/ide/stores/modules/editor/getters_spec.js31
-rw-r--r--spec/frontend/ide/stores/modules/editor/mutations_spec.js78
-rw-r--r--spec/frontend/ide/stores/modules/editor/setup_spec.js44
-rw-r--r--spec/frontend/ide/stores/mutations/file_spec.js12
17 files changed, 431 insertions, 223 deletions
diff --git a/spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js b/spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js
deleted file mode 100644
index 42e0a20bc7b..00000000000
--- a/spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import Vue from 'vue';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
-import { createStore } from '~/ide/stores';
-import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue';
-import { file } from '../../helpers';
-import { removeWhitespace } from '../../../helpers/text_helper';
-
-describe('Multi-file editor commit sidebar list collapsed', () => {
- let vm;
- let store;
-
- beforeEach(() => {
- store = createStore();
-
- const Component = Vue.extend(listCollapsed);
-
- vm = createComponentWithStore(Component, store, {
- files: [
- {
- ...file('file1'),
- tempFile: true,
- },
- file('file2'),
- ],
- iconName: 'staged',
- title: 'Staged',
- });
-
- vm.$mount();
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders added & modified files count', () => {
- expect(removeWhitespace(vm.$el.textContent).trim()).toBe('1 1');
- });
-
- describe('addedFilesLength', () => {
- it('returns an length of temp files', () => {
- expect(vm.addedFilesLength).toBe(1);
- });
- });
-
- describe('modifiedFilesLength', () => {
- it('returns an length of modified files', () => {
- expect(vm.modifiedFilesLength).toBe(1);
- });
- });
-
- describe('addedFilesIconClass', () => {
- it('includes multi-file-addition when addedFiles is not empty', () => {
- expect(vm.addedFilesIconClass).toContain('multi-file-addition');
- });
-
- it('excludes multi-file-addition when addedFiles is empty', () => {
- vm.files = [];
-
- expect(vm.addedFilesIconClass).not.toContain('multi-file-addition');
- });
- });
-
- describe('modifiedFilesClass', () => {
- it('includes multi-file-modified when addedFiles is not empty', () => {
- expect(vm.modifiedFilesClass).toContain('multi-file-modified');
- });
-
- it('excludes multi-file-modified when addedFiles is empty', () => {
- vm.files = [];
-
- expect(vm.modifiedFilesClass).not.toContain('multi-file-modified');
- });
- });
-});
diff --git a/spec/frontend/ide/components/commit_sidebar/list_spec.js b/spec/frontend/ide/components/commit_sidebar/list_spec.js
index 2107ff96e95..636dfbf0b2a 100644
--- a/spec/frontend/ide/components/commit_sidebar/list_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/list_spec.js
@@ -16,7 +16,6 @@ describe('Multi-file editor commit sidebar list', () => {
vm = createComponentWithStore(Component, store, {
title: 'Staged',
fileList: [],
- iconName: 'staged',
action: 'stageAllChanges',
actionBtnText: 'stage all',
actionBtnIcon: 'history',
diff --git a/spec/frontend/ide/components/ide_side_bar_spec.js b/spec/frontend/ide/components/ide_side_bar_spec.js
index 86e4e8d8f89..72e9463945b 100644
--- a/spec/frontend/ide/components/ide_side_bar_spec.js
+++ b/spec/frontend/ide/components/ide_side_bar_spec.js
@@ -1,10 +1,12 @@
import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { GlSkeletonLoading } from '@gitlab/ui';
+import waitForPromises from 'helpers/wait_for_promises';
import { createStore } from '~/ide/stores';
import IdeSidebar from '~/ide/components/ide_side_bar.vue';
import IdeTree from '~/ide/components/ide_tree.vue';
import RepoCommitSection from '~/ide/components/repo_commit_section.vue';
+import IdeReview from '~/ide/components/ide_review.vue';
import { leftSidebarViews } from '~/ide/constants';
import { projectData } from '../mock_data';
@@ -15,11 +17,12 @@ describe('IdeSidebar', () => {
let wrapper;
let store;
- function createComponent() {
+ function createComponent({ view = leftSidebarViews.edit.name } = {}) {
store = createStore();
store.state.currentProjectId = 'abcproject';
store.state.projects.abcproject = projectData;
+ store.state.currentActivityView = view;
return mount(IdeSidebar, {
store,
@@ -48,22 +51,46 @@ describe('IdeSidebar', () => {
expect(wrapper.findAll(GlSkeletonLoading)).toHaveLength(3);
});
- describe('activityBarComponent', () => {
- it('renders tree component', () => {
+ describe('deferred rendering components', () => {
+ it('fetches components on demand', async () => {
wrapper = createComponent();
expect(wrapper.find(IdeTree).exists()).toBe(true);
- });
+ expect(wrapper.find(IdeReview).exists()).toBe(false);
+ expect(wrapper.find(RepoCommitSection).exists()).toBe(false);
- it('renders commit component', async () => {
- wrapper = createComponent();
+ store.state.currentActivityView = leftSidebarViews.review.name;
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
- store.state.currentActivityView = leftSidebarViews.commit.name;
+ expect(wrapper.find(IdeTree).exists()).toBe(false);
+ expect(wrapper.find(IdeReview).exists()).toBe(true);
+ expect(wrapper.find(RepoCommitSection).exists()).toBe(false);
+ store.state.currentActivityView = leftSidebarViews.commit.name;
+ await waitForPromises();
await wrapper.vm.$nextTick();
+ expect(wrapper.find(IdeTree).exists()).toBe(false);
+ expect(wrapper.find(IdeReview).exists()).toBe(false);
expect(wrapper.find(RepoCommitSection).exists()).toBe(true);
});
+ it.each`
+ view | tree | review | commit
+ ${leftSidebarViews.edit.name} | ${true} | ${false} | ${false}
+ ${leftSidebarViews.review.name} | ${false} | ${true} | ${false}
+ ${leftSidebarViews.commit.name} | ${false} | ${false} | ${true}
+ `('renders correct panels for $view', async ({ view, tree, review, commit } = {}) => {
+ wrapper = createComponent({
+ view,
+ });
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find(IdeTree).exists()).toBe(tree);
+ expect(wrapper.find(IdeReview).exists()).toBe(review);
+ expect(wrapper.find(RepoCommitSection).exists()).toBe(commit);
+ });
});
it('keeps the current activity view components alive', async () => {
@@ -72,7 +99,7 @@ describe('IdeSidebar', () => {
const ideTreeComponent = wrapper.find(IdeTree).element;
store.state.currentActivityView = leftSidebarViews.commit.name;
-
+ await waitForPromises();
await wrapper.vm.$nextTick();
expect(wrapper.find(IdeTree).exists()).toBe(false);
@@ -80,6 +107,7 @@ describe('IdeSidebar', () => {
store.state.currentActivityView = leftSidebarViews.edit.name;
+ await waitForPromises();
await wrapper.vm.$nextTick();
// reference to the elements remains the same, meaning the components were kept alive
diff --git a/spec/frontend/ide/components/ide_spec.js b/spec/frontend/ide/components/ide_spec.js
index a7b07a9f0e2..ff3852b6775 100644
--- a/spec/frontend/ide/components/ide_spec.js
+++ b/spec/frontend/ide/components/ide_spec.js
@@ -1,127 +1,165 @@
-import Vue from 'vue';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import Vuex from 'vuex';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { createStore } from '~/ide/stores';
+import ErrorMessage from '~/ide/components/error_message.vue';
+import FindFile from '~/vue_shared/components/file_finder/index.vue';
+import CommitEditorHeader from '~/ide/components/commit_sidebar/editor_header.vue';
+import RepoTabs from '~/ide/components/repo_tabs.vue';
+import IdeStatusBar from '~/ide/components/ide_status_bar.vue';
+import RightPane from '~/ide/components/panes/right.vue';
+import NewModal from '~/ide/components/new_dropdown/modal.vue';
+
import ide from '~/ide/components/ide.vue';
import { file } from '../helpers';
import { projectData } from '../mock_data';
-import extendStore from '~/ide/stores/extend';
-
-let store;
-function bootstrap(projData) {
- store = createStore();
+const localVue = createLocalVue();
+localVue.use(Vuex);
- extendStore(store, document.createElement('div'));
+describe('WebIDE', () => {
+ const emptyProjData = { ...projectData, empty_repo: true, branches: {} };
- const Component = Vue.extend(ide);
+ let wrapper;
- store.state.currentProjectId = 'abcproject';
- store.state.currentBranchId = 'master';
- store.state.projects.abcproject = { ...projData };
- Vue.set(store.state.trees, 'abcproject/master', {
- tree: [],
- loading: false,
- });
-
- return createComponentWithStore(Component, store, {
- emptyStateSvgPath: 'svg',
- noChangesStateSvgPath: 'svg',
- committedStateSvgPath: 'svg',
- });
-}
+ function createComponent({ projData = emptyProjData, state = {} } = {}) {
+ const store = createStore();
-describe('ide component, empty repo', () => {
- let vm;
+ store.state.currentProjectId = 'abcproject';
+ store.state.currentBranchId = 'master';
+ store.state.projects.abcproject = { ...projData };
+ store.state.trees['abcproject/master'] = {
+ tree: [],
+ loading: false,
+ };
+ Object.keys(state).forEach(key => {
+ store.state[key] = state[key];
+ });
- beforeEach(() => {
- const emptyProjData = { ...projectData, empty_repo: true, branches: {} };
- vm = bootstrap(emptyProjData);
- vm.$mount();
- });
+ return shallowMount(ide, {
+ store,
+ localVue,
+ stubs: {
+ ErrorMessage,
+ GlButton,
+ GlLoadingIcon,
+ CommitEditorHeader,
+ RepoTabs,
+ IdeStatusBar,
+ FindFile,
+ RightPane,
+ NewModal,
+ },
+ });
+ }
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
+ wrapper = null;
});
- 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, empty repo', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ projData: {
+ empty_repo: true,
+ },
+ });
});
- });
-});
-
-describe('ide component, non-empty repo', () => {
- let vm;
- beforeEach(() => {
- vm = bootstrap(projectData);
- vm.$mount();
- });
-
- afterEach(() => {
- vm.$destroy();
+ it('renders "New file" button in empty repo', async () => {
+ expect(wrapper.find('[title="New file"]').exists()).toBe(true);
+ });
});
- it('shows error message when set', done => {
- expect(vm.$el.querySelector('.gl-alert')).toBe(null);
+ describe('ide component, non-empty repo', () => {
+ describe('error message', () => {
+ it('does not show error message when it is not set', () => {
+ wrapper = createComponent({
+ state: {
+ errorMessage: null,
+ },
+ });
- vm.$store.state.errorMessage = {
- text: 'error',
- };
+ expect(wrapper.find(ErrorMessage).exists()).toBe(false);
+ });
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.gl-alert')).not.toBe(null);
+ it('shows error message when set', () => {
+ wrapper = createComponent({
+ state: {
+ errorMessage: {
+ text: 'error',
+ },
+ },
+ });
- done();
+ expect(wrapper.find(ErrorMessage).exists()).toBe(true);
+ });
});
- });
- describe('onBeforeUnload', () => {
- it('returns undefined when no staged files or changed files', () => {
- expect(vm.onBeforeUnload()).toBe(undefined);
- });
+ describe('onBeforeUnload', () => {
+ it('returns undefined when no staged files or changed files', () => {
+ wrapper = createComponent();
+ expect(wrapper.vm.onBeforeUnload()).toBe(undefined);
+ });
- it('returns warning text when their are changed files', () => {
- vm.$store.state.changedFiles.push(file());
+ it('returns warning text when their are changed files', () => {
+ wrapper = createComponent({
+ state: {
+ changedFiles: [file()],
+ },
+ });
- expect(vm.onBeforeUnload()).toBe('Are you sure you want to lose unsaved changes?');
- });
+ expect(wrapper.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());
+ it('returns warning text when their are staged files', () => {
+ wrapper = createComponent({
+ state: {
+ stagedFiles: [file()],
+ },
+ });
- expect(vm.onBeforeUnload()).toBe('Are you sure you want to lose unsaved changes?');
- });
+ expect(wrapper.vm.onBeforeUnload()).toBe('Are you sure you want to lose unsaved changes?');
+ });
- it('updates event object', () => {
- const event = {};
- vm.$store.state.stagedFiles.push(file());
+ it('updates event object', () => {
+ const event = {};
+ wrapper = createComponent({
+ state: {
+ stagedFiles: [file()],
+ },
+ });
- vm.onBeforeUnload(event);
+ wrapper.vm.onBeforeUnload(event);
- expect(event.returnValue).toBe('Are you sure you want to lose unsaved changes?');
+ 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('non-existent branch', () => {
+ it('does not render "New file" button for non-existent branch when repo is not empty', () => {
+ wrapper = createComponent({
+ state: {
+ projects: {},
+ },
+ });
+
+ expect(wrapper.find('[title="New file"]').exists()).toBe(false);
});
});
- });
- describe('branch with files', () => {
- beforeEach(() => {
- store.state.trees['abcproject/master'].tree = [file()];
- });
+ describe('branch with files', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ projData: {
+ empty_repo: false,
+ },
+ });
+ });
- it('does not render "New file" button', done => {
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.ide-empty-state button[title="New file"]')).toBeNull();
- done();
+ it('does not render "New file" button', () => {
+ expect(wrapper.find('[title="New file"]').exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/ide/components/ide_status_list_spec.js b/spec/frontend/ide/components/ide_status_list_spec.js
index bb8165d1a52..02b5dc19bd8 100644
--- a/spec/frontend/ide/components/ide_status_list_spec.js
+++ b/spec/frontend/ide/components/ide_status_list_spec.js
@@ -6,17 +6,21 @@ import TerminalSyncStatusSafe from '~/ide/components/terminal_sync/terminal_sync
const TEST_FILE = {
name: 'lorem.md',
- editorRow: 3,
- editorColumn: 23,
- fileLanguage: 'markdown',
content: 'abc\nndef',
permalink: '/lorem.md',
};
+const TEST_FILE_EDITOR = {
+ fileLanguage: 'markdown',
+ editorRow: 3,
+ editorColumn: 23,
+};
+const TEST_EDITOR_POSITION = `${TEST_FILE_EDITOR.editorRow}:${TEST_FILE_EDITOR.editorColumn}`;
const localVue = createLocalVue();
localVue.use(Vuex);
describe('ide/components/ide_status_list', () => {
+ let activeFileEditor;
let activeFile;
let store;
let wrapper;
@@ -27,6 +31,14 @@ describe('ide/components/ide_status_list', () => {
getters: {
activeFile: () => activeFile,
},
+ modules: {
+ editor: {
+ namespaced: true,
+ getters: {
+ activeFileEditor: () => activeFileEditor,
+ },
+ },
+ },
});
wrapper = shallowMount(IdeStatusList, {
@@ -38,6 +50,7 @@ describe('ide/components/ide_status_list', () => {
beforeEach(() => {
activeFile = TEST_FILE;
+ activeFileEditor = TEST_FILE_EDITOR;
});
afterEach(() => {
@@ -47,8 +60,6 @@ describe('ide/components/ide_status_list', () => {
wrapper = null;
});
- const getEditorPosition = file => `${file.editorRow}:${file.editorColumn}`;
-
describe('with regular file', () => {
beforeEach(() => {
createComponent();
@@ -65,11 +76,11 @@ describe('ide/components/ide_status_list', () => {
});
it('shows file editor position', () => {
- expect(wrapper.text()).toContain(getEditorPosition(TEST_FILE));
+ expect(wrapper.text()).toContain(TEST_EDITOR_POSITION);
});
it('shows file language', () => {
- expect(wrapper.text()).toContain(TEST_FILE.fileLanguage);
+ expect(wrapper.text()).toContain(TEST_FILE_EDITOR.fileLanguage);
});
});
@@ -81,7 +92,7 @@ describe('ide/components/ide_status_list', () => {
});
it('does not show file editor position', () => {
- expect(wrapper.text()).not.toContain(getEditorPosition(TEST_FILE));
+ expect(wrapper.text()).not.toContain(TEST_EDITOR_POSITION);
});
});
diff --git a/spec/frontend/ide/components/pipelines/list_spec.js b/spec/frontend/ide/components/pipelines/list_spec.js
index 7f083fa7c25..c1744fefe20 100644
--- a/spec/frontend/ide/components/pipelines/list_spec.js
+++ b/spec/frontend/ide/components/pipelines/list_spec.js
@@ -1,11 +1,10 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlTab } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import { pipelines } from 'jest/ide/mock_data';
import List from '~/ide/components/pipelines/list.vue';
import JobsList from '~/ide/components/jobs/list.vue';
-import Tab from '~/vue_shared/components/tabs/tab.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import IDEServices from '~/ide/services';
@@ -167,7 +166,7 @@ describe('IDE pipelines list', () => {
createComponent({}, { ...withLatestPipelineState, stages, isLoadingJobs });
const jobProps = wrapper
- .findAll(Tab)
+ .findAll(GlTab)
.at(0)
.find(JobsList)
.props();
@@ -182,7 +181,7 @@ describe('IDE pipelines list', () => {
createComponent({}, { ...withLatestPipelineState, isLoadingJobs });
const jobProps = wrapper
- .findAll(Tab)
+ .findAll(GlTab)
.at(1)
.find(JobsList)
.props();
diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js
index 9f4c9c1622a..71a4f08cfb4 100644
--- a/spec/frontend/ide/components/repo_editor_spec.js
+++ b/spec/frontend/ide/components/repo_editor_spec.js
@@ -55,7 +55,6 @@ describe('RepoEditor', () => {
beforeEach(() => {
const f = {
...file('file.txt'),
- viewMode: FILE_VIEW_MODE_EDITOR,
content: 'hello world',
};
@@ -92,6 +91,8 @@ describe('RepoEditor', () => {
});
const findEditor = () => vm.$el.querySelector('.multi-file-editor-holder');
+ const changeViewMode = viewMode =>
+ store.dispatch('editor/updateFileEditor', { path: vm.file.path, data: { viewMode } });
describe('default', () => {
beforeEach(() => {
@@ -409,7 +410,7 @@ describe('RepoEditor', () => {
describe('when files view mode is preview', () => {
beforeEach(done => {
jest.spyOn(vm.editor, 'updateDimensions').mockImplementation();
- vm.file.viewMode = FILE_VIEW_MODE_PREVIEW;
+ changeViewMode(FILE_VIEW_MODE_PREVIEW);
vm.file.name = 'myfile.md';
vm.file.content = 'hello world';
@@ -423,7 +424,7 @@ describe('RepoEditor', () => {
describe('when file view mode changes to editor', () => {
it('should update dimensions', () => {
- vm.file.viewMode = FILE_VIEW_MODE_EDITOR;
+ changeViewMode(FILE_VIEW_MODE_EDITOR);
return vm.$nextTick().then(() => {
expect(vm.editor.updateDimensions).toHaveBeenCalled();
diff --git a/spec/frontend/ide/components/repo_tab_spec.js b/spec/frontend/ide/components/repo_tab_spec.js
index f35726de27c..a44c8b4d5ee 100644
--- a/spec/frontend/ide/components/repo_tab_spec.js
+++ b/spec/frontend/ide/components/repo_tab_spec.js
@@ -100,6 +100,18 @@ describe('RepoTab', () => {
expect(wrapper.find('.file-modified').exists()).toBe(true);
});
+ it.each`
+ tabProps | closeLabel
+ ${{}} | ${'Close foo.txt'}
+ ${{ changed: true }} | ${'foo.txt changed'}
+ `('close button has label ($closeLabel) with tab ($tabProps)', ({ tabProps, closeLabel }) => {
+ const tab = { ...file('foo.txt'), ...tabProps };
+
+ createComponent({ tab });
+
+ expect(wrapper.find('button').attributes('aria-label')).toBe(closeLabel);
+ });
+
describe('locked file', () => {
let f;
@@ -122,9 +134,7 @@ describe('RepoTab', () => {
});
it('renders a tooltip', () => {
- expect(wrapper.find('span:nth-child(2)').attributes('data-original-title')).toContain(
- 'Locked by testuser',
- );
+ expect(wrapper.find('span:nth-child(2)').attributes('title')).toBe('Locked by testuser');
});
});
diff --git a/spec/frontend/ide/components/terminal/empty_state_spec.js b/spec/frontend/ide/components/terminal/empty_state_spec.js
index a3f2089608d..b62470f67b6 100644
--- a/spec/frontend/ide/components/terminal/empty_state_spec.js
+++ b/spec/frontend/ide/components/terminal/empty_state_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui';
import { TEST_HOST } from 'spec/test_constants';
import TerminalEmptyState from '~/ide/components/terminal/empty_state.vue';
@@ -36,7 +36,7 @@ describe('IDE TerminalEmptyState', () => {
const img = wrapper.find('.svg-content img');
expect(img.exists()).toBe(true);
- expect(img.attributes('src')).toEqual(TEST_PATH);
+ expect(img.attributes('src')).toBe(TEST_PATH);
});
it('when loading, shows loading icon', () => {
@@ -71,24 +71,23 @@ describe('IDE TerminalEmptyState', () => {
},
});
- button = wrapper.find('button');
+ button = wrapper.find(GlButton);
});
it('shows button', () => {
- expect(button.text()).toEqual('Start Web Terminal');
- expect(button.attributes('disabled')).toBeFalsy();
+ expect(button.text()).toBe('Start Web Terminal');
+ expect(button.props('disabled')).toBe(false);
});
it('emits start when button is clicked', () => {
- expect(wrapper.emitted().start).toBeFalsy();
-
- button.trigger('click');
+ expect(wrapper.emitted().start).toBeUndefined();
+ button.vm.$emit('click');
expect(wrapper.emitted().start).toHaveLength(1);
});
it('shows help path link', () => {
- expect(wrapper.find('a').attributes('href')).toEqual(TEST_HELP_PATH);
+ expect(wrapper.find('a').attributes('href')).toBe(TEST_HELP_PATH);
});
});
@@ -101,7 +100,7 @@ describe('IDE TerminalEmptyState', () => {
},
});
- expect(wrapper.find('button').attributes('disabled')).not.toBe(null);
- expect(wrapper.find('.bs-callout').element.innerHTML).toEqual(TEST_HTML_MESSAGE);
+ expect(wrapper.find(GlButton).props('disabled')).toBe(true);
+ expect(wrapper.find(GlAlert).html()).toContain(TEST_HTML_MESSAGE);
});
});
diff --git a/spec/frontend/ide/helpers.js b/spec/frontend/ide/helpers.js
index 0e85b523cbd..6b65dd96ef4 100644
--- a/spec/frontend/ide/helpers.js
+++ b/spec/frontend/ide/helpers.js
@@ -1,5 +1,6 @@
import * as pathUtils from 'path';
import { decorateData } from '~/ide/stores/utils';
+import { commitActionTypes } from '~/ide/constants';
export const file = (name = 'name', id = name, type = '', parent = null) =>
decorateData({
@@ -28,3 +29,17 @@ export const createEntriesFromPaths = paths =>
...entries,
};
}, {});
+
+export const createTriggerChangeAction = payload => ({
+ type: 'triggerFilesChange',
+ ...(payload ? { payload } : {}),
+});
+
+export const createTriggerRenamePayload = (path, newPath) => ({
+ type: commitActionTypes.move,
+ path,
+ newPath,
+});
+
+export const createTriggerRenameAction = (path, newPath) =>
+ createTriggerChangeAction(createTriggerRenamePayload(path, newPath));
diff --git a/spec/frontend/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js
index 8f7fcc25cf0..cc290fc526e 100644
--- a/spec/frontend/ide/stores/actions/file_spec.js
+++ b/spec/frontend/ide/stores/actions/file_spec.js
@@ -7,7 +7,7 @@ import * as types from '~/ide/stores/mutation_types';
import service from '~/ide/services';
import { createRouter } from '~/ide/ide_router';
import eventHub from '~/ide/eventhub';
-import { file } from '../../helpers';
+import { file, createTriggerRenameAction } from '../../helpers';
const ORIGINAL_CONTENT = 'original content';
const RELATIVE_URL_ROOT = '/gitlab';
@@ -785,13 +785,19 @@ describe('IDE store file actions', () => {
});
describe('triggerFilesChange', () => {
+ const { payload: renamePayload } = createTriggerRenameAction('test', '123');
+
beforeEach(() => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
});
- it('emits event that files have changed', () => {
- return store.dispatch('triggerFilesChange').then(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('ide.files.change');
+ it.each`
+ args | payload
+ ${[]} | ${{}}
+ ${[renamePayload]} | ${renamePayload}
+ `('emits event that files have changed (args=$args)', ({ args, payload }) => {
+ return store.dispatch('triggerFilesChange', ...args).then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('ide.files.change', payload);
});
});
});
diff --git a/spec/frontend/ide/stores/actions_spec.js b/spec/frontend/ide/stores/actions_spec.js
index ebf39df2f6f..04128c27e70 100644
--- a/spec/frontend/ide/stores/actions_spec.js
+++ b/spec/frontend/ide/stores/actions_spec.js
@@ -19,7 +19,7 @@ import {
} from '~/ide/stores/actions';
import axios from '~/lib/utils/axios_utils';
import * as types from '~/ide/stores/mutation_types';
-import { file } from '../helpers';
+import { file, createTriggerRenameAction, createTriggerChangeAction } from '../helpers';
import testAction from '../../helpers/vuex_action_helper';
import eventHub from '~/ide/eventhub';
@@ -522,7 +522,7 @@ describe('Multi-file store actions', () => {
'path',
store.state,
[{ type: types.DELETE_ENTRY, payload: 'path' }],
- [{ type: 'stageChange', payload: 'path' }, { type: 'triggerFilesChange' }],
+ [{ type: 'stageChange', payload: 'path' }, createTriggerChangeAction()],
done,
);
});
@@ -551,7 +551,7 @@ describe('Multi-file store actions', () => {
[{ type: types.DELETE_ENTRY, payload: 'testFolder/entry-to-delete' }],
[
{ type: 'stageChange', payload: 'testFolder/entry-to-delete' },
- { type: 'triggerFilesChange' },
+ createTriggerChangeAction(),
],
done,
);
@@ -614,7 +614,7 @@ describe('Multi-file store actions', () => {
testEntry.path,
store.state,
[{ type: types.DELETE_ENTRY, payload: testEntry.path }],
- [{ type: 'stageChange', payload: testEntry.path }, { type: 'triggerFilesChange' }],
+ [{ type: 'stageChange', payload: testEntry.path }, createTriggerChangeAction()],
done,
);
});
@@ -754,7 +754,7 @@ describe('Multi-file store actions', () => {
payload: origEntry,
},
],
- [{ type: 'triggerFilesChange' }],
+ [createTriggerRenameAction('renamed', 'orig')],
done,
);
});
@@ -767,7 +767,7 @@ describe('Multi-file store actions', () => {
{ path: 'orig', name: 'renamed' },
store.state,
[expect.objectContaining({ type: types.RENAME_ENTRY })],
- [{ type: 'triggerFilesChange' }],
+ [createTriggerRenameAction('orig', 'renamed')],
done,
);
});
diff --git a/spec/frontend/ide/stores/modules/editor/actions_spec.js b/spec/frontend/ide/stores/modules/editor/actions_spec.js
new file mode 100644
index 00000000000..6a420ac32de
--- /dev/null
+++ b/spec/frontend/ide/stores/modules/editor/actions_spec.js
@@ -0,0 +1,36 @@
+import testAction from 'helpers/vuex_action_helper';
+import * as types from '~/ide/stores/modules/editor/mutation_types';
+import * as actions from '~/ide/stores/modules/editor/actions';
+import { createTriggerRenamePayload } from '../../../helpers';
+
+describe('~/ide/stores/modules/editor/actions', () => {
+ describe('updateFileEditor', () => {
+ it('commits with payload', () => {
+ const payload = {};
+
+ testAction(actions.updateFileEditor, payload, {}, [
+ { type: types.UPDATE_FILE_EDITOR, payload },
+ ]);
+ });
+ });
+
+ describe('removeFileEditor', () => {
+ it('commits with payload', () => {
+ const payload = 'path/to/file.txt';
+
+ testAction(actions.removeFileEditor, payload, {}, [
+ { type: types.REMOVE_FILE_EDITOR, payload },
+ ]);
+ });
+ });
+
+ describe('renameFileEditor', () => {
+ it('commits with payload', () => {
+ const payload = createTriggerRenamePayload('test', 'test123');
+
+ testAction(actions.renameFileEditor, payload, {}, [
+ { type: types.RENAME_FILE_EDITOR, payload },
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/ide/stores/modules/editor/getters_spec.js b/spec/frontend/ide/stores/modules/editor/getters_spec.js
new file mode 100644
index 00000000000..55e1e31f66f
--- /dev/null
+++ b/spec/frontend/ide/stores/modules/editor/getters_spec.js
@@ -0,0 +1,31 @@
+import { createDefaultFileEditor } from '~/ide/stores/modules/editor/utils';
+import * as getters from '~/ide/stores/modules/editor/getters';
+
+const TEST_PATH = 'test/path.md';
+const TEST_FILE_EDITOR = {
+ ...createDefaultFileEditor(),
+ editorRow: 7,
+ editorColumn: 8,
+ fileLanguage: 'markdown',
+};
+
+describe('~/ide/stores/modules/editor/getters', () => {
+ describe('activeFileEditor', () => {
+ it.each`
+ activeFile | fileEditors | expected
+ ${null} | ${{}} | ${null}
+ ${{}} | ${{}} | ${createDefaultFileEditor()}
+ ${{ path: TEST_PATH }} | ${{}} | ${createDefaultFileEditor()}
+ ${{ path: TEST_PATH }} | ${{ bogus: createDefaultFileEditor(), [TEST_PATH]: TEST_FILE_EDITOR }} | ${TEST_FILE_EDITOR}
+ `(
+ 'with activeFile=$activeFile and fileEditors=$fileEditors',
+ ({ activeFile, fileEditors, expected }) => {
+ const rootGetters = { activeFile };
+ const state = { fileEditors };
+ const result = getters.activeFileEditor(state, {}, {}, rootGetters);
+
+ expect(result).toEqual(expected);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/ide/stores/modules/editor/mutations_spec.js b/spec/frontend/ide/stores/modules/editor/mutations_spec.js
new file mode 100644
index 00000000000..e4b330b3174
--- /dev/null
+++ b/spec/frontend/ide/stores/modules/editor/mutations_spec.js
@@ -0,0 +1,78 @@
+import { createDefaultFileEditor } from '~/ide/stores/modules/editor/utils';
+import * as types from '~/ide/stores/modules/editor/mutation_types';
+import mutations from '~/ide/stores/modules/editor/mutations';
+import { createTriggerRenamePayload } from '../../../helpers';
+
+const TEST_PATH = 'test/path.md';
+
+describe('~/ide/stores/modules/editor/mutations', () => {
+ describe(types.UPDATE_FILE_EDITOR, () => {
+ it('with path that does not exist, should initialize with default values', () => {
+ const state = { fileEditors: {} };
+ const data = { fileLanguage: 'markdown' };
+
+ mutations[types.UPDATE_FILE_EDITOR](state, { path: TEST_PATH, data });
+
+ expect(state.fileEditors).toEqual({
+ [TEST_PATH]: {
+ ...createDefaultFileEditor(),
+ ...data,
+ },
+ });
+ });
+
+ it('with existing path, should overwrite values', () => {
+ const state = {
+ fileEditors: {
+ foo: {},
+ [TEST_PATH]: { ...createDefaultFileEditor(), editorRow: 7, editorColumn: 7 },
+ },
+ };
+
+ mutations[types.UPDATE_FILE_EDITOR](state, {
+ path: TEST_PATH,
+ data: { fileLanguage: 'markdown' },
+ });
+
+ expect(state).toEqual({
+ fileEditors: {
+ foo: {},
+ [TEST_PATH]: {
+ ...createDefaultFileEditor(),
+ editorRow: 7,
+ editorColumn: 7,
+ fileLanguage: 'markdown',
+ },
+ },
+ });
+ });
+ });
+
+ describe(types.REMOVE_FILE_EDITOR, () => {
+ it.each`
+ fileEditors | path | expected
+ ${{}} | ${'does/not/exist.txt'} | ${{}}
+ ${{ foo: {}, [TEST_PATH]: {} }} | ${TEST_PATH} | ${{ foo: {} }}
+ `('removes file $path', ({ fileEditors, path, expected }) => {
+ const state = { fileEditors };
+
+ mutations[types.REMOVE_FILE_EDITOR](state, path);
+
+ expect(state).toEqual({ fileEditors: expected });
+ });
+ });
+
+ describe(types.RENAME_FILE_EDITOR, () => {
+ it.each`
+ fileEditors | payload | expected
+ ${{ foo: {} }} | ${createTriggerRenamePayload('does/not/exist', 'abc')} | ${{ foo: {} }}
+ ${{ foo: { a: 1 }, bar: {} }} | ${createTriggerRenamePayload('foo', 'abc/def')} | ${{ 'abc/def': { a: 1 }, bar: {} }}
+ `('renames fileEditor at $payload', ({ fileEditors, payload, expected }) => {
+ const state = { fileEditors };
+
+ mutations[types.RENAME_FILE_EDITOR](state, payload);
+
+ expect(state).toEqual({ fileEditors: expected });
+ });
+ });
+});
diff --git a/spec/frontend/ide/stores/modules/editor/setup_spec.js b/spec/frontend/ide/stores/modules/editor/setup_spec.js
new file mode 100644
index 00000000000..71b5d7590c5
--- /dev/null
+++ b/spec/frontend/ide/stores/modules/editor/setup_spec.js
@@ -0,0 +1,44 @@
+import Vuex from 'vuex';
+import eventHub from '~/ide/eventhub';
+import { createStoreOptions } from '~/ide/stores';
+import { setupFileEditorsSync } from '~/ide/stores/modules/editor/setup';
+import { createTriggerRenamePayload } from '../../../helpers';
+
+describe('~/ide/stores/modules/editor/setup', () => {
+ let store;
+
+ beforeEach(() => {
+ store = new Vuex.Store(createStoreOptions());
+ store.state.entries = {
+ foo: {},
+ bar: {},
+ };
+ store.state.editor.fileEditors = {
+ foo: {},
+ bizz: {},
+ };
+
+ setupFileEditorsSync(store);
+ });
+
+ it('when files change is emitted, removes unused fileEditors', () => {
+ eventHub.$emit('ide.files.change');
+
+ expect(store.state.entries).toEqual({
+ foo: {},
+ bar: {},
+ });
+ expect(store.state.editor.fileEditors).toEqual({
+ foo: {},
+ });
+ });
+
+ it('when files rename is emitted, renames fileEditor', () => {
+ eventHub.$emit('ide.files.change', createTriggerRenamePayload('foo', 'foo_new'));
+
+ expect(store.state.editor.fileEditors).toEqual({
+ foo_new: {},
+ bizz: {},
+ });
+ });
+});
diff --git a/spec/frontend/ide/stores/mutations/file_spec.js b/spec/frontend/ide/stores/mutations/file_spec.js
index d303de6e9ef..fd39cf21635 100644
--- a/spec/frontend/ide/stores/mutations/file_spec.js
+++ b/spec/frontend/ide/stores/mutations/file_spec.js
@@ -1,6 +1,5 @@
import mutations from '~/ide/stores/mutations/file';
import { createStore } from '~/ide/stores';
-import { FILE_VIEW_MODE_PREVIEW } from '~/ide/constants';
import { file } from '../../helpers';
describe('IDE store file mutations', () => {
@@ -532,17 +531,6 @@ describe('IDE store file mutations', () => {
});
});
- describe('SET_FILE_VIEWMODE', () => {
- it('updates file view mode', () => {
- mutations.SET_FILE_VIEWMODE(localState, {
- file: localFile,
- viewMode: FILE_VIEW_MODE_PREVIEW,
- });
-
- expect(localFile.viewMode).toBe(FILE_VIEW_MODE_PREVIEW);
- });
- });
-
describe('ADD_PENDING_TAB', () => {
beforeEach(() => {
const f = { ...file('openFile'), path: 'openFile', active: true, opened: true };