Commit 3f472c95 authored by Illya Klymov's avatar Illya Klymov

Merge branch '208800-step-1-break-store-and-router-cyclical-dependency' into 'master'

Step 1.2 - Break  IDE store and router cyclical dependency

Closes #28717

See merge request gitlab-org/gitlab!33366
parents 7b294d34 e7148253
...@@ -2,8 +2,8 @@ import Vue from 'vue'; ...@@ -2,8 +2,8 @@ import Vue from 'vue';
import IdeRouter from '~/ide/ide_router_extension'; import IdeRouter from '~/ide/ide_router_extension';
import { joinPaths } from '~/lib/utils/url_utility'; import { joinPaths } from '~/lib/utils/url_utility';
import flash from '~/flash'; import flash from '~/flash';
import store from './stores';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { syncRouterAndStore } from './sync_router_and_store';
Vue.use(IdeRouter); Vue.use(IdeRouter);
...@@ -33,80 +33,85 @@ const EmptyRouterComponent = { ...@@ -33,80 +33,85 @@ const EmptyRouterComponent = {
}, },
}; };
const router = new IdeRouter({ // eslint-disable-next-line import/prefer-default-export
mode: 'history', export const createRouter = store => {
base: joinPaths(gon.relative_url_root || '', '/-/ide/'), const router = new IdeRouter({
routes: [ mode: 'history',
{ base: joinPaths(gon.relative_url_root || '', '/-/ide/'),
path: '/project/:namespace+/:project', routes: [
component: EmptyRouterComponent, {
children: [ path: '/project/:namespace+/:project',
{ component: EmptyRouterComponent,
path: ':targetmode(edit|tree|blob)/:branchid+/-/*', children: [
component: EmptyRouterComponent, {
}, path: ':targetmode(edit|tree|blob)/:branchid+/-/*',
{ component: EmptyRouterComponent,
path: ':targetmode(edit|tree|blob)/:branchid+/', },
redirect: to => joinPaths(to.path, '/-/'), {
}, path: ':targetmode(edit|tree|blob)/:branchid+/',
{ redirect: to => joinPaths(to.path, '/-/'),
path: ':targetmode(edit|tree|blob)', },
redirect: to => joinPaths(to.path, '/master/-/'), {
}, path: ':targetmode(edit|tree|blob)',
{ redirect: to => joinPaths(to.path, '/master/-/'),
path: 'merge_requests/:mrid', },
component: EmptyRouterComponent, {
}, path: 'merge_requests/:mrid',
{ component: EmptyRouterComponent,
path: '', },
redirect: to => joinPaths(to.path, '/edit/master/-/'), {
}, path: '',
], redirect: to => joinPaths(to.path, '/edit/master/-/'),
}, },
], ],
}); },
],
});
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (to.params.namespace && to.params.project) { if (to.params.namespace && to.params.project) {
store store
.dispatch('getProjectData', { .dispatch('getProjectData', {
namespace: to.params.namespace, namespace: to.params.namespace,
projectId: to.params.project, projectId: to.params.project,
}) })
.then(() => { .then(() => {
const basePath = to.params.pathMatch || ''; const basePath = to.params.pathMatch || '';
const projectId = `${to.params.namespace}/${to.params.project}`; const projectId = `${to.params.namespace}/${to.params.project}`;
const branchId = to.params.branchid; const branchId = to.params.branchid;
const mergeRequestId = to.params.mrid; const mergeRequestId = to.params.mrid;
if (branchId) { if (branchId) {
store.dispatch('openBranch', { store.dispatch('openBranch', {
projectId, projectId,
branchId, branchId,
basePath, basePath,
}); });
} else if (mergeRequestId) { } else if (mergeRequestId) {
store.dispatch('openMergeRequest', { store.dispatch('openMergeRequest', {
projectId, projectId,
mergeRequestId, mergeRequestId,
targetProjectId: to.query.target_project, targetProjectId: to.query.target_project,
}); });
} }
}) })
.catch(e => { .catch(e => {
flash( flash(
__('Error while loading the project data. Please try again.'), __('Error while loading the project data. Please try again.'),
'alert', 'alert',
document, document,
null, null,
false, false,
true, true,
); );
throw e; throw e;
}); });
} }
next(); next();
}); });
export default router; syncRouterAndStore(router, store);
return router;
};
...@@ -4,7 +4,7 @@ import Translate from '~/vue_shared/translate'; ...@@ -4,7 +4,7 @@ import Translate from '~/vue_shared/translate';
import { identity } from 'lodash'; import { identity } from 'lodash';
import ide from './components/ide.vue'; import ide from './components/ide.vue';
import store from './stores'; import store from './stores';
import router from './ide_router'; import { createRouter } from './ide_router';
import { parseBoolean } from '../lib/utils/common_utils'; import { parseBoolean } from '../lib/utils/common_utils';
import { resetServiceWorkersPublicPath } from '../lib/utils/webpack'; import { resetServiceWorkersPublicPath } from '../lib/utils/webpack';
import { DEFAULT_THEME } from './lib/themes'; import { DEFAULT_THEME } from './lib/themes';
...@@ -32,6 +32,7 @@ export function initIde(el, options = {}) { ...@@ -32,6 +32,7 @@ export function initIde(el, options = {}) {
if (!el) return null; if (!el) return null;
const { rootComponent = ide, extendStore = identity } = options; const { rootComponent = ide, extendStore = identity } = options;
const router = createRouter(store);
return new Vue({ return new Vue({
el, el,
......
...@@ -7,7 +7,6 @@ import * as types from './mutation_types'; ...@@ -7,7 +7,6 @@ import * as types from './mutation_types';
import { decorateFiles } from '../lib/files'; import { decorateFiles } from '../lib/files';
import { stageKeys } from '../constants'; import { stageKeys } from '../constants';
import service from '../services'; import service from '../services';
import router from '../ide_router';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
export const redirectToUrl = (self, url) => visitUrl(url); export const redirectToUrl = (self, url) => visitUrl(url);
...@@ -262,7 +261,7 @@ export const renameEntry = ({ dispatch, commit, state, getters }, { path, name, ...@@ -262,7 +261,7 @@ export const renameEntry = ({ dispatch, commit, state, getters }, { path, name,
} }
if (newEntry.opened) { if (newEntry.opened) {
router.push(`/project${newEntry.url}`); dispatch('router/push', `/project${newEntry.url}`, { root: true });
} }
} }
......
...@@ -3,7 +3,6 @@ import { __ } from '~/locale'; ...@@ -3,7 +3,6 @@ import { __ } from '~/locale';
import eventHub from '../../eventhub'; import eventHub from '../../eventhub';
import service from '../../services'; import service from '../../services';
import * as types from '../mutation_types'; import * as types from '../mutation_types';
import router from '../../ide_router';
import { setPageTitleForFile } from '../utils'; import { setPageTitleForFile } from '../utils';
import { viewerTypes, stageKeys } from '../../constants'; import { viewerTypes, stageKeys } from '../../constants';
...@@ -30,10 +29,10 @@ export const closeFile = ({ commit, state, dispatch }, file) => { ...@@ -30,10 +29,10 @@ export const closeFile = ({ commit, state, dispatch }, file) => {
keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged', keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged',
}); });
} else { } else {
router.push(`/project${nextFileToOpen.url}`); dispatch('router/push', `/project${nextFileToOpen.url}`, { root: true });
} }
} else if (!state.openFiles.length) { } else if (!state.openFiles.length) {
router.push(`/project/${file.projectId}/tree/${file.branchId}/`); dispatch('router/push', `/project/${file.projectId}/tree/${file.branchId}/`, { root: true });
} }
eventHub.$emit(`editor.update.model.dispose.${file.key}`); eventHub.$emit(`editor.update.model.dispose.${file.key}`);
...@@ -226,7 +225,7 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) = ...@@ -226,7 +225,7 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) =
if (!isDestructiveDiscard && file.path === getters.activeFile?.path) { if (!isDestructiveDiscard && file.path === getters.activeFile?.path) {
dispatch('updateDelayViewerUpdated', true) dispatch('updateDelayViewerUpdated', true)
.then(() => { .then(() => {
router.push(`/project${file.url}`); dispatch('router/push', `/project${file.url}`, { root: true });
}) })
.catch(e => { .catch(e => {
throw e; throw e;
...@@ -275,14 +274,16 @@ export const unstageChange = ({ commit, dispatch, getters }, path) => { ...@@ -275,14 +274,16 @@ export const unstageChange = ({ commit, dispatch, getters }, path) => {
} }
}; };
export const openPendingTab = ({ commit, getters, state }, { file, keyPrefix }) => { export const openPendingTab = ({ commit, dispatch, getters, state }, { file, keyPrefix }) => {
if (getters.activeFile && getters.activeFile.key === `${keyPrefix}-${file.key}`) return false; if (getters.activeFile && getters.activeFile.key === `${keyPrefix}-${file.key}`) return false;
state.openFiles.forEach(f => eventHub.$emit(`editor.update.model.dispose.${f.key}`)); state.openFiles.forEach(f => eventHub.$emit(`editor.update.model.dispose.${f.key}`));
commit(types.ADD_PENDING_TAB, { file, keyPrefix }); commit(types.ADD_PENDING_TAB, { file, keyPrefix });
router.push(`/project/${file.projectId}/tree/${state.currentBranchId}/`); dispatch('router/push', `/project/${file.projectId}/tree/${state.currentBranchId}/`, {
root: true,
});
return true; return true;
}; };
......
...@@ -4,7 +4,6 @@ import { __, sprintf } from '~/locale'; ...@@ -4,7 +4,6 @@ import { __, sprintf } from '~/locale';
import service from '../../services'; import service from '../../services';
import api from '../../../api'; import api from '../../../api';
import * as types from '../mutation_types'; import * as types from '../mutation_types';
import router from '../../ide_router';
export const getProjectData = ({ commit, state }, { namespace, projectId, force = false } = {}) => export const getProjectData = ({ commit, state }, { namespace, projectId, force = false } = {}) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
...@@ -57,7 +56,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch) ...@@ -57,7 +56,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch)
}) })
.then(() => { .then(() => {
dispatch('setErrorMessage', null); dispatch('setErrorMessage', null);
router.push(`${router.currentRoute.path}?${Date.now()}`); window.location.reload();
}) })
.catch(() => { .catch(() => {
dispatch('setErrorMessage', { dispatch('setErrorMessage', {
......
...@@ -11,6 +11,7 @@ import branches from './modules/branches'; ...@@ -11,6 +11,7 @@ import branches from './modules/branches';
import fileTemplates from './modules/file_templates'; import fileTemplates from './modules/file_templates';
import paneModule from './modules/pane'; import paneModule from './modules/pane';
import clientsideModule from './modules/clientside'; import clientsideModule from './modules/clientside';
import routerModule from './modules/router';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -28,6 +29,7 @@ export const createStore = () => ...@@ -28,6 +29,7 @@ export const createStore = () =>
fileTemplates: fileTemplates(), fileTemplates: fileTemplates(),
rightPane: paneModule(), rightPane: paneModule(),
clientside: clientsideModule(), clientside: clientsideModule(),
router: routerModule,
}, },
}); });
......
...@@ -4,7 +4,7 @@ import mutations from './mutations'; ...@@ -4,7 +4,7 @@ import mutations from './mutations';
export default { export default {
namespaced: true, namespaced: true,
state: state(), state,
actions, actions,
mutations, mutations,
}; };
...@@ -3,7 +3,6 @@ import flash from '~/flash'; ...@@ -3,7 +3,6 @@ import flash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
import * as rootTypes from '../../mutation_types'; import * as rootTypes from '../../mutation_types';
import { createCommitPayload, createNewMergeRequestUrl } from '../../utils'; import { createCommitPayload, createNewMergeRequestUrl } from '../../utils';
import router from '../../../ide_router';
import service from '../../../services'; import service from '../../../services';
import * as types from './mutation_types'; import * as types from './mutation_types';
import consts from './constants'; import consts from './constants';
...@@ -196,8 +195,10 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ...@@ -196,8 +195,10 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
dispatch('updateViewer', 'editor', { root: true }); dispatch('updateViewer', 'editor', { root: true });
if (rootGetters.activeFile) { if (rootGetters.activeFile) {
router.push( dispatch(
'router/push',
`/project/${rootState.currentProjectId}/blob/${branchName}/-/${rootGetters.activeFile.path}`, `/project/${rootState.currentProjectId}/blob/${branchName}/-/${rootGetters.activeFile.path}`,
{ root: true },
); );
} }
} }
......
...@@ -5,7 +5,7 @@ import * as getters from './getters'; ...@@ -5,7 +5,7 @@ import * as getters from './getters';
export default { export default {
namespaced: true, namespaced: true,
state: state(), state,
mutations, mutations,
actions, actions,
getters, getters,
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import router from '~/ide/ide_router'; import { createStore } from '~/ide/stores';
import { createRouter } from '~/ide/ide_router';
import Item from '~/ide/components/branches/item.vue'; import Item from '~/ide/components/branches/item.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import Timeago from '~/vue_shared/components/time_ago_tooltip.vue'; import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
...@@ -13,6 +14,8 @@ const TEST_PROJECT_ID = projectData.name_with_namespace; ...@@ -13,6 +14,8 @@ const TEST_PROJECT_ID = projectData.name_with_namespace;
describe('IDE branch item', () => { describe('IDE branch item', () => {
let wrapper; let wrapper;
let store;
let router;
function createComponent(props = {}) { function createComponent(props = {}) {
wrapper = shallowMount(Item, { wrapper = shallowMount(Item, {
...@@ -26,6 +29,11 @@ describe('IDE branch item', () => { ...@@ -26,6 +29,11 @@ describe('IDE branch item', () => {
}); });
} }
beforeEach(() => {
store = createStore();
router = createRouter(store);
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import store from '~/ide/stores'; import { createStore } from '~/ide/stores';
import listItem from '~/ide/components/commit_sidebar/list_item.vue'; import listItem from '~/ide/components/commit_sidebar/list_item.vue';
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import { file, resetStore } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor commit sidebar list item', () => { describe('Multi-file editor commit sidebar list item', () => {
let vm; let vm;
let f; let f;
let findPathEl; let findPathEl;
let store;
let router;
beforeEach(() => { beforeEach(() => {
store = createStore();
router = createRouter(store);
const Component = Vue.extend(listItem); const Component = Vue.extend(listItem);
f = file('test-file'); f = file('test-file');
...@@ -28,8 +33,6 @@ describe('Multi-file editor commit sidebar list item', () => { ...@@ -28,8 +33,6 @@ describe('Multi-file editor commit sidebar list item', () => {
afterEach(() => { afterEach(() => {
vm.$destroy(); vm.$destroy();
resetStore(store);
}); });
const findPathText = () => trimText(findPathEl.textContent); const findPathText = () => trimText(findPathEl.textContent);
......
import { mount } from '@vue/test-utils'; import Vuex from 'vuex';
import router from '~/ide/ide_router'; import { mount, createLocalVue } from '@vue/test-utils';
import { createStore } from '~/ide/stores';
import { createRouter } from '~/ide/ide_router';
import Item from '~/ide/components/merge_requests/item.vue'; import Item from '~/ide/components/merge_requests/item.vue';
const TEST_ITEM = { const TEST_ITEM = {
...@@ -9,7 +11,12 @@ const TEST_ITEM = { ...@@ -9,7 +11,12 @@ const TEST_ITEM = {
}; };
describe('IDE merge request item', () => { describe('IDE merge request item', () => {
const localVue = createLocalVue();
localVue.use(Vuex);
let wrapper; let wrapper;
let store;
let router;
const createComponent = (props = {}) => { const createComponent = (props = {}) => {
wrapper = mount(Item, { wrapper = mount(Item, {
...@@ -21,11 +28,18 @@ describe('IDE merge request item', () => { ...@@ -21,11 +28,18 @@ describe('IDE merge request item', () => {
currentProjectId: TEST_ITEM.projectPathWithNamespace, currentProjectId: TEST_ITEM.projectPathWithNamespace,
...props, ...props,
}, },
localVue,
router, router,
store,
}); });
}; };
const findIcon = () => wrapper.find('.ic-mobile-issue-close'); const findIcon = () => wrapper.find('.ic-mobile-issue-close');
beforeEach(() => {
store = createStore();
router = createRouter(store);
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null; wrapper = null;
......
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import RepoCommitSection from '~/ide/components/repo_commit_section.vue'; import RepoCommitSection from '~/ide/components/repo_commit_section.vue';
import EmptyState from '~/ide/components/commit_sidebar/empty_state.vue'; import EmptyState from '~/ide/components/commit_sidebar/empty_state.vue';
import { stageKeys } from '~/ide/constants'; import { stageKeys } from '~/ide/constants';
...@@ -10,6 +10,7 @@ const TEST_NO_CHANGES_SVG = 'nochangessvg'; ...@@ -10,6 +10,7 @@ const TEST_NO_CHANGES_SVG = 'nochangessvg';
describe('RepoCommitSection', () => { describe('RepoCommitSection', () => {
let wrapper; let wrapper;
let router;
let store; let store;
function createComponent() { function createComponent() {
...@@ -55,6 +56,7 @@ describe('RepoCommitSection', () => { ...@@ -55,6 +56,7 @@ describe('RepoCommitSection', () => {
beforeEach(() => { beforeEach(() => {
store = createStore(); store = createStore();
router = createRouter(store);
jest.spyOn(store, 'dispatch'); jest.spyOn(store, 'dispatch');
jest.spyOn(router, 'push').mockImplementation(); jest.spyOn(router, 'push').mockImplementation();
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import { createStore } from '~/ide/stores';
import repoTab from '~/ide/components/repo_tab.vue'; import repoTab from '~/ide/components/repo_tab.vue';
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import { file, resetStore } from '../helpers'; import { file } from '../helpers';
describe('RepoTab', () => { describe('RepoTab', () => {
let vm; let vm;
let store;
let router;
function createComponent(propsData) { function createComponent(propsData) {
const RepoTab = Vue.extend(repoTab); const RepoTab = Vue.extend(repoTab);
...@@ -17,13 +19,13 @@ describe('RepoTab', () => { ...@@ -17,13 +19,13 @@ describe('RepoTab', () => {
} }
beforeEach(() => { beforeEach(() => {
store = createStore();
router = createRouter(store);
jest.spyOn(router, 'push').mockImplementation(() => {}); jest.spyOn(router, 'push').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); vm.$destroy();
resetStore(vm.$store);
}); });
it('renders a close link and a name link', () => { it('renders a close link and a name link', () => {
......
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import store from '~/ide/stores'; import { createStore } from '~/ide/stores';
import waitForPromises from 'helpers/wait_for_promises';
describe('IDE router', () => { describe('IDE router', () => {
const PROJECT_NAMESPACE = 'my-group/sub-group'; const PROJECT_NAMESPACE = 'my-group/sub-group';
const PROJECT_NAME = 'my-project'; const PROJECT_NAME = 'my-project';
const TEST_PATH = `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/merge_requests/2`;
afterEach(() => { let store;
router.push('/'); let router;
});
afterAll(() => { beforeEach(() => {
// VueRouter leaves this window.history at the "base" url. We need to clean this up.
window.history.replaceState({}, '', '/'); window.history.replaceState({}, '', '/');
store = createStore();
router = createRouter(store);
jest.spyOn(store, 'dispatch').mockReturnValue(new Promise(() => {}));
}); });
[ [
...@@ -31,8 +34,6 @@ describe('IDE router', () => { ...@@ -31,8 +34,6 @@ describe('IDE router', () => {
`/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}`, `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}`,
].forEach(route => { ].forEach(route => {
it(`finds project path when route is "${route}"`, () => { it(`finds project path when route is "${route}"`, () => {
jest.spyOn(store, 'dispatch').mockReturnValue(new Promise(() => {}));
router.push(route); router.push(route);
expect(store.dispatch).toHaveBeenCalledWith('getProjectData', { expect(store.dispatch).toHaveBeenCalledWith('getProjectData', {
...@@ -41,4 +42,22 @@ describe('IDE router', () => { ...@@ -41,4 +42,22 @@ describe('IDE router', () => {
}); });
}); });
}); });
it('keeps router in sync when store changes', async () => {
expect(router.currentRoute.fullPath).toBe('/');
store.state.router.fullPath = TEST_PATH;
await waitForPromises();
expect(router.currentRoute.fullPath).toBe(TEST_PATH);
});
it('keeps store in sync when router changes', () => {
expect(store.dispatch).not.toHaveBeenCalled();
router.push(TEST_PATH);
expect(store.dispatch).toHaveBeenCalledWith('router/push', TEST_PATH, { root: true });
});
}); });
...@@ -5,7 +5,7 @@ import { createStore } from '~/ide/stores'; ...@@ -5,7 +5,7 @@ import { createStore } from '~/ide/stores';
import * as actions from '~/ide/stores/actions/file'; import * as actions from '~/ide/stores/actions/file';
import * as types from '~/ide/stores/mutation_types'; import * as types from '~/ide/stores/mutation_types';
import service from '~/ide/services'; import service from '~/ide/services';
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import eventHub from '~/ide/eventhub'; import eventHub from '~/ide/eventhub';
import { file } from '../../helpers'; import { file } from '../../helpers';
...@@ -16,6 +16,7 @@ describe('IDE store file actions', () => { ...@@ -16,6 +16,7 @@ describe('IDE store file actions', () => {
let mock; let mock;
let originalGon; let originalGon;
let store; let store;
let router;
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
...@@ -26,6 +27,7 @@ describe('IDE store file actions', () => { ...@@ -26,6 +27,7 @@ describe('IDE store file actions', () => {
}; };
store = createStore(); store = createStore();
router = createRouter(store);
jest.spyOn(store, 'commit'); jest.spyOn(store, 'commit');
jest.spyOn(store, 'dispatch'); jest.spyOn(store, 'dispatch');
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
import router from '~/ide/ide_router';
import { import {
refreshLastCommitData, refreshLastCommitData,
showBranchNotFoundError, showBranchNotFoundError,
...@@ -13,7 +12,6 @@ import { ...@@ -13,7 +12,6 @@ import {
} from '~/ide/stores/actions'; } from '~/ide/stores/actions';
import service from '~/ide/services'; import service from '~/ide/services';
import api from '~/api'; import api from '~/api';
import { resetStore } from '../../helpers';
import testAction from '../../../helpers/vuex_action_helper'; import testAction from '../../../helpers/vuex_action_helper';
const TEST_PROJECT_ID = 'abc/def'; const TEST_PROJECT_ID = 'abc/def';
...@@ -33,8 +31,6 @@ describe('IDE store project actions', () => { ...@@ -33,8 +31,6 @@ describe('IDE store project actions', () => {
afterEach(() => { afterEach(() => {
mock.restore(); mock.restore();
resetStore(store);
}); });
describe('refreshLastCommitData', () => { describe('refreshLastCommitData', () => {
...@@ -122,7 +118,6 @@ describe('IDE store project actions', () => { ...@@ -122,7 +118,6 @@ describe('IDE store project actions', () => {
describe('createNewBranchFromDefault', () => { describe('createNewBranchFromDefault', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(api, 'createBranch').mockResolvedValue(); jest.spyOn(api, 'createBranch').mockResolvedValue();
jest.spyOn(router, 'push').mockImplementation();
}); });
it('calls API', done => { it('calls API', done => {
...@@ -175,6 +170,8 @@ describe('IDE store project actions', () => { ...@@ -175,6 +170,8 @@ describe('IDE store project actions', () => {
}); });
it('reloads window', done => { it('reloads window', done => {
jest.spyOn(window.location, 'reload').mockImplementation();
createNewBranchFromDefault( createNewBranchFromDefault(
{ {
state: { state: {
...@@ -190,7 +187,7 @@ describe('IDE store project actions', () => { ...@@ -190,7 +187,7 @@ describe('IDE store project actions', () => {
'new-branch-name', 'new-branch-name',
) )
.then(() => { .then(() => {
expect(router.push).toHaveBeenCalled(); expect(window.location.reload).toHaveBeenCalled();
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
......
...@@ -3,14 +3,16 @@ import testAction from 'helpers/vuex_action_helper'; ...@@ -3,14 +3,16 @@ import testAction from 'helpers/vuex_action_helper';
import { showTreeEntry, getFiles, setDirectoryData } from '~/ide/stores/actions/tree'; import { showTreeEntry, getFiles, setDirectoryData } from '~/ide/stores/actions/tree';
import * as types from '~/ide/stores/mutation_types'; import * as types from '~/ide/stores/mutation_types';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores'; import { createStore } from '~/ide/stores';
import service from '~/ide/services'; import service from '~/ide/services';
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import { file, resetStore, createEntriesFromPaths } from '../../helpers'; import { file, createEntriesFromPaths } from '../../helpers';
describe('Multi-file store tree actions', () => { describe('Multi-file store tree actions', () => {
let projectTree; let projectTree;
let mock; let mock;
let store;
let router;
const basicCallParameters = { const basicCallParameters = {
endpoint: 'rootEndpoint', endpoint: 'rootEndpoint',
...@@ -21,6 +23,8 @@ describe('Multi-file store tree actions', () => { ...@@ -21,6 +23,8 @@ describe('Multi-file store tree actions', () => {
}; };
beforeEach(() => { beforeEach(() => {
store = createStore();
router = createRouter(store);
jest.spyOn(router, 'push').mockImplementation(); jest.spyOn(router, 'push').mockImplementation();
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
...@@ -35,7 +39,6 @@ describe('Multi-file store tree actions', () => { ...@@ -35,7 +39,6 @@ describe('Multi-file store tree actions', () => {
afterEach(() => { afterEach(() => {
mock.restore(); mock.restore();
resetStore(store);
}); });
describe('getFiles', () => { describe('getFiles', () => {
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import { import {
stageAllChanges, stageAllChanges,
unstageAllChanges, unstageAllChanges,
...@@ -30,9 +30,11 @@ jest.mock('~/lib/utils/url_utility', () => ({ ...@@ -30,9 +30,11 @@ jest.mock('~/lib/utils/url_utility', () => ({
describe('Multi-file store actions', () => { describe('Multi-file store actions', () => {
let store; let store;
let router;
beforeEach(() => { beforeEach(() => {
store = createStore(); store = createStore();
router = createRouter(store);
jest.spyOn(store, 'commit'); jest.spyOn(store, 'commit');
jest.spyOn(store, 'dispatch'); jest.spyOn(store, 'dispatch');
...@@ -339,10 +341,12 @@ describe('Multi-file store actions', () => { ...@@ -339,10 +341,12 @@ describe('Multi-file store actions', () => {
it('adds all files from changedFiles to stagedFiles', () => { it('adds all files from changedFiles to stagedFiles', () => {
stageAllChanges(store); stageAllChanges(store);
expect(store.commit.mock.calls).toEqual([ expect(store.commit.mock.calls).toEqual(
[types.SET_LAST_COMMIT_MSG, ''], expect.arrayContaining([
[types.STAGE_CHANGE, expect.objectContaining({ path: file1.path })], [types.SET_LAST_COMMIT_MSG, ''],
]); [types.STAGE_CHANGE, expect.objectContaining({ path: file1.path })],
]),
);
}); });
it('opens pending tab if a change exists in that file', () => { it('opens pending tab if a change exists in that file', () => {
...@@ -371,9 +375,11 @@ describe('Multi-file store actions', () => { ...@@ -371,9 +375,11 @@ describe('Multi-file store actions', () => {
it('removes all files from stagedFiles after unstaging', () => { it('removes all files from stagedFiles after unstaging', () => {
unstageAllChanges(store); unstageAllChanges(store);
expect(store.commit.mock.calls).toEqual([ expect(store.commit.mock.calls).toEqual(
[types.UNSTAGE_CHANGE, expect.objectContaining({ path: file2.path })], expect.arrayContaining([
]); [types.UNSTAGE_CHANGE, expect.objectContaining({ path: file2.path })],
]),
);
}); });
it('opens pending tab if a change exists in that file', () => { it('opens pending tab if a change exists in that file', () => {
......
import { resetStore, file } from 'jest/ide/helpers'; import { file } from 'jest/ide/helpers';
import axios from 'axios'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
import service from '~/ide/services'; import service from '~/ide/services';
import router from '~/ide/ide_router'; import { createRouter } from '~/ide/ide_router';
import eventHub from '~/ide/eventhub'; import eventHub from '~/ide/eventhub';
import consts from '~/ide/stores/modules/commit/constants'; import consts from '~/ide/stores/modules/commit/constants';
import * as mutationTypes from '~/ide/stores/modules/commit/mutation_types'; import * as mutationTypes from '~/ide/stores/modules/commit/mutation_types';
...@@ -18,12 +18,15 @@ jest.mock('~/lib/utils/url_utility', () => ({ ...@@ -18,12 +18,15 @@ jest.mock('~/lib/utils/url_utility', () => ({
})); }));
const TEST_COMMIT_SHA = '123456789'; const TEST_COMMIT_SHA = '123456789';
const store = createStore();
describe('IDE commit module actions', () => { describe('IDE commit module actions', () => {
let mock; let mock;
let store;
let router;
beforeEach(() => { beforeEach(() => {
store = createStore();
router = createRouter(store);
gon.api_version = 'v1'; gon.api_version = 'v1';
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
jest.spyOn(router, 'push').mockImplementation(); jest.spyOn(router, 'push').mockImplementation();
...@@ -34,7 +37,6 @@ describe('IDE commit module actions', () => { ...@@ -34,7 +37,6 @@ describe('IDE commit module actions', () => {
afterEach(() => { afterEach(() => {
delete gon.api_version; delete gon.api_version;
mock.restore(); mock.restore();
resetStore(store);
}); });
describe('updateCommitMessage', () => { describe('updateCommitMessage', () => {
......
import Vue from 'vue';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
import Vuex from 'vuex'; import { createStore } from '~/ide/stores';
import routerModule from '~/ide/stores/modules/router';
import { syncRouterAndStore } from '~/ide/sync_router_and_store'; import { syncRouterAndStore } from '~/ide/sync_router_and_store';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
const TEST_ROUTE = '/test/lorem/ipsum'; const TEST_ROUTE = '/test/lorem/ipsum';
Vue.use(Vuex);
describe('~/ide/sync_router_and_store', () => { describe('~/ide/sync_router_and_store', () => {
let unsync; let unsync;
let router; let router;
...@@ -32,11 +28,7 @@ describe('~/ide/sync_router_and_store', () => { ...@@ -32,11 +28,7 @@ describe('~/ide/sync_router_and_store', () => {
beforeEach(() => { beforeEach(() => {
router = new VueRouter(); router = new VueRouter();
store = new Vuex.Store({ store = createStore();
modules: {
router: routerModule,
},
});
jest.spyOn(store, 'dispatch'); jest.spyOn(store, 'dispatch');
onRouterChange = jest.fn(); onRouterChange = jest.fn();
......
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