Commit a0ff7724 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'ide-more-error-improvements' into 'master'

Improve error messaging across various IDE actions

See merge request gitlab-org/gitlab-ce!20241
parents 2c22c17b 04f7e9aa
...@@ -24,8 +24,8 @@ export default { ...@@ -24,8 +24,8 @@ export default {
this.isLoading = true; this.isLoading = true;
this.$store this.message
.dispatch(this.message.action, this.message.actionPayload) .action(this.message.actionPayload)
.then(() => { .then(() => {
this.isLoading = false; this.isLoading = false;
}) })
......
import Vue from 'vue';
import VueResource from 'vue-resource';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import Api from '~/api'; import Api from '~/api';
Vue.use(VueResource);
export default { export default {
getTreeData(endpoint) {
return Vue.http.get(endpoint, { params: { format: 'json' } });
},
getFileData(endpoint) { getFileData(endpoint) {
return Vue.http.get(endpoint, { params: { format: 'json', viewer: 'none' } }); return axios.get(endpoint, {
params: { format: 'json', viewer: 'none' },
});
}, },
getRawFileData(file) { getRawFileData(file) {
if (file.tempFile) { if (file.tempFile) {
...@@ -21,7 +16,11 @@ export default { ...@@ -21,7 +16,11 @@ export default {
return Promise.resolve(file.raw); return Promise.resolve(file.raw);
} }
return Vue.http.get(file.rawPath, { params: { format: 'json' } }).then(res => res.text()); return axios
.get(file.rawPath, {
params: { format: 'json' },
})
.then(({ data }) => data);
}, },
getBaseRawFileData(file, sha) { getBaseRawFileData(file, sha) {
if (file.tempFile) { if (file.tempFile) {
...@@ -32,11 +31,11 @@ export default { ...@@ -32,11 +31,11 @@ export default {
return Promise.resolve(file.baseRaw); return Promise.resolve(file.baseRaw);
} }
return Vue.http return axios
.get(file.rawPath.replace(`/raw/${file.branchId}/${file.path}`, `/raw/${sha}/${file.path}`), { .get(file.rawPath.replace(`/raw/${file.branchId}/${file.path}`, `/raw/${sha}/${file.path}`), {
params: { format: 'json' }, params: { format: 'json' },
}) })
.then(res => res.text()); .then(({ data }) => data);
}, },
getProjectData(namespace, project) { getProjectData(namespace, project) {
return Api.project(`${namespace}/${project}`); return Api.project(`${namespace}/${project}`);
...@@ -53,21 +52,9 @@ export default { ...@@ -53,21 +52,9 @@ export default {
getBranchData(projectId, currentBranchId) { getBranchData(projectId, currentBranchId) {
return Api.branchSingle(projectId, currentBranchId); return Api.branchSingle(projectId, currentBranchId);
}, },
createBranch(projectId, payload) {
const url = Api.buildUrl(Api.createBranchPath).replace(':id', projectId);
return Vue.http.post(url, payload);
},
commit(projectId, payload) { commit(projectId, payload) {
return Api.commitMultiple(projectId, payload); return Api.commitMultiple(projectId, payload);
}, },
getTreeLastCommit(endpoint) {
return Vue.http.get(endpoint, {
params: {
format: 'json',
},
});
},
getFiles(projectUrl, branchId) { getFiles(projectUrl, branchId) {
const url = `${projectUrl}/files/${branchId}`; const url = `${projectUrl}/files/${branchId}`;
return axios.get(url, { params: { format: 'json' } }); return axios.get(url, { params: { format: 'json' } });
......
import { normalizeHeaders } from '~/lib/utils/common_utils'; import { __ } from '../../../locale';
import flash from '~/flash'; import { normalizeHeaders } from '../../../lib/utils/common_utils';
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';
...@@ -66,13 +66,10 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive ...@@ -66,13 +66,10 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive
.getFileData( .getFileData(
`${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`, `${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`,
) )
.then(res => { .then(({ data, headers }) => {
const pageTitle = decodeURI(normalizeHeaders(res.headers)['PAGE-TITLE']); const normalizedHeaders = normalizeHeaders(headers);
setPageTitle(pageTitle); setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE']));
return res.json();
})
.then(data => {
commit(types.SET_FILE_DATA, { data, file }); commit(types.SET_FILE_DATA, { data, file });
commit(types.TOGGLE_FILE_OPEN, path); commit(types.TOGGLE_FILE_OPEN, path);
if (makeFileActive) dispatch('setFileActive', path); if (makeFileActive) dispatch('setFileActive', path);
...@@ -80,7 +77,13 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive ...@@ -80,7 +77,13 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive
}) })
.catch(() => { .catch(() => {
commit(types.TOGGLE_LOADING, { entry: file }); commit(types.TOGGLE_LOADING, { entry: file });
flash('Error loading file data. Please try again.', 'alert', document, null, false, true); dispatch('setErrorMessage', {
text: __('An error occured whilst loading the file.'),
action: payload =>
dispatch('getFileData', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
actionPayload: { path, makeFileActive },
});
}); });
}; };
...@@ -88,7 +91,7 @@ export const setFileMrChange = ({ commit }, { file, mrChange }) => { ...@@ -88,7 +91,7 @@ export const setFileMrChange = ({ commit }, { file, mrChange }) => {
commit(types.SET_FILE_MERGE_REQUEST_CHANGE, { file, mrChange }); commit(types.SET_FILE_MERGE_REQUEST_CHANGE, { file, mrChange });
}; };
export const getRawFileData = ({ state, commit }, { path, baseSha }) => { export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) => {
const file = state.entries[path]; const file = state.entries[path];
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
service service
...@@ -113,7 +116,13 @@ export const getRawFileData = ({ state, commit }, { path, baseSha }) => { ...@@ -113,7 +116,13 @@ export const getRawFileData = ({ state, commit }, { path, baseSha }) => {
} }
}) })
.catch(() => { .catch(() => {
flash('Error loading file content. Please try again.'); dispatch('setErrorMessage', {
text: __('An error occured whilst loading the file content.'),
action: payload =>
dispatch('getRawFileData', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
actionPayload: { path, baseSha },
});
reject(); reject();
}); });
}); });
......
import flash from '~/flash'; import { __ } from '../../../locale';
import service from '../../services'; import service from '../../services';
import * as types from '../mutation_types'; import * as types from '../mutation_types';
export const getMergeRequestData = ( export const getMergeRequestData = (
{ commit, state }, { commit, dispatch, state },
{ projectId, mergeRequestId, force = false } = {}, { projectId, mergeRequestId, force = false } = {},
) => ) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
if (!state.projects[projectId].mergeRequests[mergeRequestId] || force) { if (!state.projects[projectId].mergeRequests[mergeRequestId] || force) {
service service
.getProjectMergeRequestData(projectId, mergeRequestId) .getProjectMergeRequestData(projectId, mergeRequestId)
.then(res => res.data) .then(({ data }) => {
.then(data => {
commit(types.SET_MERGE_REQUEST, { commit(types.SET_MERGE_REQUEST, {
projectPath: projectId, projectPath: projectId,
mergeRequestId, mergeRequestId,
...@@ -21,7 +20,15 @@ export const getMergeRequestData = ( ...@@ -21,7 +20,15 @@ export const getMergeRequestData = (
resolve(data); resolve(data);
}) })
.catch(() => { .catch(() => {
flash('Error loading merge request data. Please try again.'); dispatch('setErrorMessage', {
text: __('An error occured whilst loading the merge request.'),
action: payload =>
dispatch('getMergeRequestData', payload).then(() =>
dispatch('setErrorMessage', null),
),
actionText: __('Please try again'),
actionPayload: { projectId, mergeRequestId, force },
});
reject(new Error(`Merge Request not loaded ${projectId}`)); reject(new Error(`Merge Request not loaded ${projectId}`));
}); });
} else { } else {
...@@ -30,15 +37,14 @@ export const getMergeRequestData = ( ...@@ -30,15 +37,14 @@ export const getMergeRequestData = (
}); });
export const getMergeRequestChanges = ( export const getMergeRequestChanges = (
{ commit, state }, { commit, dispatch, state },
{ projectId, mergeRequestId, force = false } = {}, { projectId, mergeRequestId, force = false } = {},
) => ) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
if (!state.projects[projectId].mergeRequests[mergeRequestId].changes.length || force) { if (!state.projects[projectId].mergeRequests[mergeRequestId].changes.length || force) {
service service
.getProjectMergeRequestChanges(projectId, mergeRequestId) .getProjectMergeRequestChanges(projectId, mergeRequestId)
.then(res => res.data) .then(({ data }) => {
.then(data => {
commit(types.SET_MERGE_REQUEST_CHANGES, { commit(types.SET_MERGE_REQUEST_CHANGES, {
projectPath: projectId, projectPath: projectId,
mergeRequestId, mergeRequestId,
...@@ -47,7 +53,15 @@ export const getMergeRequestChanges = ( ...@@ -47,7 +53,15 @@ export const getMergeRequestChanges = (
resolve(data); resolve(data);
}) })
.catch(() => { .catch(() => {
flash('Error loading merge request changes. Please try again.'); dispatch('setErrorMessage', {
text: __('An error occured whilst loading the merge request changes.'),
action: payload =>
dispatch('getMergeRequestChanges', payload).then(() =>
dispatch('setErrorMessage', null),
),
actionText: __('Please try again'),
actionPayload: { projectId, mergeRequestId, force },
});
reject(new Error(`Merge Request Changes not loaded ${projectId}`)); reject(new Error(`Merge Request Changes not loaded ${projectId}`));
}); });
} else { } else {
...@@ -56,7 +70,7 @@ export const getMergeRequestChanges = ( ...@@ -56,7 +70,7 @@ export const getMergeRequestChanges = (
}); });
export const getMergeRequestVersions = ( export const getMergeRequestVersions = (
{ commit, state }, { commit, dispatch, state },
{ projectId, mergeRequestId, force = false } = {}, { projectId, mergeRequestId, force = false } = {},
) => ) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
...@@ -73,7 +87,15 @@ export const getMergeRequestVersions = ( ...@@ -73,7 +87,15 @@ export const getMergeRequestVersions = (
resolve(data); resolve(data);
}) })
.catch(() => { .catch(() => {
flash('Error loading merge request versions. Please try again.'); dispatch('setErrorMessage', {
text: __('An error occured whilst loading the merge request version data.'),
action: payload =>
dispatch('getMergeRequestVersions', payload).then(() =>
dispatch('setErrorMessage', null),
),
actionText: __('Please try again'),
actionPayload: { projectId, mergeRequestId, force },
});
reject(new Error(`Merge Request Versions not loaded ${projectId}`)); reject(new Error(`Merge Request Versions not loaded ${projectId}`));
}); });
} else { } else {
......
...@@ -104,7 +104,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch) ...@@ -104,7 +104,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch)
.catch(() => { .catch(() => {
dispatch('setErrorMessage', { dispatch('setErrorMessage', {
text: __('An error occured creating the new branch.'), text: __('An error occured creating the new branch.'),
action: 'createNewBranchFromDefault', action: payload => dispatch('createNewBranchFromDefault', payload),
actionText: __('Please try again'), actionText: __('Please try again'),
actionPayload: branch, actionPayload: branch,
}); });
...@@ -119,7 +119,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => { ...@@ -119,7 +119,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
}, },
false, false,
), ),
action: 'createNewBranchFromDefault', action: payload => dispatch('createNewBranchFromDefault', payload),
actionText: __('Create branch'), actionText: __('Create branch'),
actionPayload: branchId, actionPayload: branchId,
}); });
......
import { normalizeHeaders } from '~/lib/utils/common_utils';
import flash from '~/flash';
import { __ } from '../../../locale'; import { __ } from '../../../locale';
import service from '../../services'; import service from '../../services';
import * as types from '../mutation_types'; import * as types from '../mutation_types';
import { findEntry } from '../utils';
import FilesDecoratorWorker from '../workers/files_decorator_worker'; import FilesDecoratorWorker from '../workers/files_decorator_worker';
export const toggleTreeOpen = ({ commit }, path) => { export const toggleTreeOpen = ({ commit }, path) => {
...@@ -37,32 +34,6 @@ export const handleTreeEntryAction = ({ commit, dispatch }, row) => { ...@@ -37,32 +34,6 @@ export const handleTreeEntryAction = ({ commit, dispatch }, row) => {
dispatch('showTreeEntry', row.path); dispatch('showTreeEntry', row.path);
}; };
export const getLastCommitData = ({ state, commit, dispatch }, tree = state) => {
if (!tree || tree.lastCommitPath === null || !tree.lastCommitPath) return;
service
.getTreeLastCommit(tree.lastCommitPath)
.then(res => {
const lastCommitPath = normalizeHeaders(res.headers)['MORE-LOGS-URL'] || null;
commit(types.SET_LAST_COMMIT_URL, { tree, url: lastCommitPath });
return res.json();
})
.then(data => {
data.forEach(lastCommit => {
const entry = findEntry(tree.tree, lastCommit.type, lastCommit.file_name);
if (entry) {
commit(types.SET_LAST_COMMIT_DATA, { entry, lastCommit });
}
});
dispatch('getLastCommitData', tree);
})
.catch(() => flash('Error fetching log data.', 'alert', document, null, false, true));
};
export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } = {}) => export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } = {}) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
if ( if (
...@@ -106,14 +77,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } = ...@@ -106,14 +77,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
if (e.response.status === 404) { if (e.response.status === 404) {
dispatch('showBranchNotFoundError', branchId); dispatch('showBranchNotFoundError', branchId);
} else { } else {
flash( dispatch('setErrorMessage', {
__('Error loading tree data. Please try again.'), text: __('An error occured whilst loading all the files.'),
'alert', action: payload =>
document, dispatch('getFiles', payload).then(() => dispatch('setErrorMessage', null)),
null, actionText: __('Please try again'),
false, actionPayload: { projectId, branchId },
true, });
);
} }
reject(e); reject(e);
}); });
......
...@@ -36,13 +36,15 @@ describe('IDE error message component', () => { ...@@ -36,13 +36,15 @@ describe('IDE error message component', () => {
}); });
describe('with action', () => { describe('with action', () => {
let actionSpy;
beforeEach(done => { beforeEach(done => {
vm.message.action = 'testAction'; actionSpy = jasmine.createSpy('action').and.returnValue(Promise.resolve());
vm.message.action = actionSpy;
vm.message.actionText = 'test action'; vm.message.actionText = 'test action';
vm.message.actionPayload = 'testActionPayload'; vm.message.actionPayload = 'testActionPayload';
spyOn(vm.$store, 'dispatch').and.returnValue(Promise.resolve());
vm.$nextTick(done); vm.$nextTick(done);
}); });
...@@ -63,7 +65,7 @@ describe('IDE error message component', () => { ...@@ -63,7 +65,7 @@ describe('IDE error message component', () => {
vm.$el.querySelector('.flash-action').click(); vm.$el.querySelector('.flash-action').click();
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$store.dispatch).toHaveBeenCalledWith('testAction', 'testActionPayload'); expect(actionSpy).toHaveBeenCalledWith('testActionPayload');
done(); done();
}); });
...@@ -74,7 +76,7 @@ describe('IDE error message component', () => { ...@@ -74,7 +76,7 @@ describe('IDE error message component', () => {
vm.$el.querySelector('.flash-action').click(); vm.$el.querySelector('.flash-action').click();
expect(vm.$store.dispatch).not.toHaveBeenCalledWith(); expect(actionSpy).not.toHaveBeenCalledWith();
}); });
it('resets isLoading after click', done => { it('resets isLoading after click', done => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import service from '~/ide/services';
import router from '~/ide/ide_router'; import router from '~/ide/ide_router';
import repoCommitSection from '~/ide/components/repo_commit_section.vue'; import repoCommitSection from '~/ide/components/repo_commit_section.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
...@@ -68,23 +67,6 @@ describe('RepoCommitSection', () => { ...@@ -68,23 +67,6 @@ describe('RepoCommitSection', () => {
vm.$mount(); vm.$mount();
spyOn(service, 'getTreeData').and.returnValue(
Promise.resolve({
headers: {
'page-title': 'test',
},
json: () =>
Promise.resolve({
last_commit_path: 'last_commit_path',
parent_tree_url: 'parent_tree_url',
path: '/',
trees: [{ name: 'tree' }],
blobs: [{ name: 'blob' }],
submodules: [{ name: 'submodule' }],
}),
}),
);
Vue.nextTick(done); Vue.nextTick(done);
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores'; import store 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';
...@@ -9,11 +11,16 @@ import { file, resetStore } from '../../helpers'; ...@@ -9,11 +11,16 @@ import { file, resetStore } from '../../helpers';
import testAction from '../../../helpers/vuex_action_helper'; import testAction from '../../../helpers/vuex_action_helper';
describe('IDE store file actions', () => { describe('IDE store file actions', () => {
let mock;
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios);
spyOn(router, 'push'); spyOn(router, 'push');
}); });
afterEach(() => { afterEach(() => {
mock.restore();
resetStore(store); resetStore(store);
}); });
...@@ -183,13 +190,18 @@ describe('IDE store file actions', () => { ...@@ -183,13 +190,18 @@ describe('IDE store file actions', () => {
let localFile; let localFile;
beforeEach(() => { beforeEach(() => {
spyOn(service, 'getFileData').and.returnValue( spyOn(service, 'getFileData').and.callThrough();
Promise.resolve({
headers: { localFile = file(`newCreate-${Math.random()}`);
'page-title': 'testing getFileData', localFile.url = `${gl.TEST_HOST}/getFileDataURL`;
}, store.state.entries[localFile.path] = localFile;
json: () => });
Promise.resolve({
describe('success', () => {
beforeEach(() => {
mock.onGet(`${gl.TEST_HOST}/getFileDataURL`).replyOnce(
200,
{
blame_path: 'blame_path', blame_path: 'blame_path',
commits_path: 'commits_path', commits_path: 'commits_path',
permalink: 'permalink', permalink: 'permalink',
...@@ -197,20 +209,18 @@ describe('IDE store file actions', () => { ...@@ -197,20 +209,18 @@ describe('IDE store file actions', () => {
binary: false, binary: false,
html: '123', html: '123',
render_error: '', render_error: '',
}), },
}), {
'page-title': 'testing getFileData',
},
); );
localFile = file(`newCreate-${Math.random()}`);
localFile.url = 'getFileDataURL';
store.state.entries[localFile.path] = localFile;
}); });
it('calls the service', done => { it('calls the service', done => {
store store
.dispatch('getFileData', { path: localFile.path }) .dispatch('getFileData', { path: localFile.path })
.then(() => { .then(() => {
expect(service.getFileData).toHaveBeenCalledWith('getFileDataURL'); expect(service.getFileData).toHaveBeenCalledWith(`${gl.TEST_HOST}/getFileDataURL`);
done(); done();
}) })
...@@ -274,16 +284,49 @@ describe('IDE store file actions', () => { ...@@ -274,16 +284,49 @@ describe('IDE store file actions', () => {
}); });
}); });
describe('error', () => {
beforeEach(() => {
mock.onGet(`${gl.TEST_HOST}/getFileDataURL`).networkError();
});
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatch');
actions
.getFileData({ state: store.state, commit() {}, dispatch }, { path: localFile.path })
.then(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the file.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
path: localFile.path,
makeFileActive: true,
},
});
done();
})
.catch(done.fail);
});
});
});
describe('getRawFileData', () => { describe('getRawFileData', () => {
let tmpFile; let tmpFile;
beforeEach(() => { beforeEach(() => {
spyOn(service, 'getRawFileData').and.returnValue(Promise.resolve('raw')); spyOn(service, 'getRawFileData').and.callThrough();
tmpFile = file('tmpFile'); tmpFile = file('tmpFile');
store.state.entries[tmpFile.path] = tmpFile; store.state.entries[tmpFile.path] = tmpFile;
}); });
describe('success', () => {
beforeEach(() => {
mock.onGet(/(.*)/).replyOnce(200, 'raw');
});
it('calls getRawFileData service method', done => { it('calls getRawFileData service method', done => {
store store
.dispatch('getRawFileData', { path: tmpFile.path }) .dispatch('getRawFileData', { path: tmpFile.path })
...@@ -323,6 +366,37 @@ describe('IDE store file actions', () => { ...@@ -323,6 +366,37 @@ describe('IDE store file actions', () => {
}); });
}); });
describe('error', () => {
beforeEach(() => {
mock.onGet(/(.*)/).networkError();
});
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatch');
actions
.getRawFileData(
{ state: store.state, commit() {}, dispatch },
{ path: tmpFile.path, baseSha: tmpFile.baseSha },
)
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the file content.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
path: tmpFile.path,
baseSha: tmpFile.baseSha,
},
});
done();
});
});
});
});
describe('changeFileContent', () => { describe('changeFileContent', () => {
let tmpFile; let tmpFile;
......
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores'; import store from '~/ide/stores';
import {
getMergeRequestData,
getMergeRequestChanges,
getMergeRequestVersions,
} from '~/ide/stores/actions/merge_request';
import service from '~/ide/services'; import service from '~/ide/services';
import { resetStore } from '../../helpers'; import { resetStore } from '../../helpers';
describe('IDE store merge request actions', () => { describe('IDE store merge request actions', () => {
let mock;
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios);
store.state.projects.abcproject = { store.state.projects.abcproject = {
mergeRequests: {}, mergeRequests: {},
}; };
}); });
afterEach(() => { afterEach(() => {
mock.restore();
resetStore(store); resetStore(store);
}); });
describe('getMergeRequestData', () => { describe('getMergeRequestData', () => {
describe('success', () => {
beforeEach(() => { beforeEach(() => {
spyOn(service, 'getProjectMergeRequestData').and.returnValue( spyOn(service, 'getProjectMergeRequestData').and.callThrough();
Promise.resolve({ data: { title: 'mergerequest' } }),
); mock
.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1/)
.reply(200, { title: 'mergerequest' });
}); });
it('calls getProjectMergeRequestData service method', done => { it('calls getProjectMergeRequestData service method', done => {
...@@ -44,15 +59,55 @@ describe('IDE store merge request actions', () => { ...@@ -44,15 +59,55 @@ describe('IDE store merge request actions', () => {
}); });
}); });
describe('getMergeRequestChanges', () => { describe('error', () => {
beforeEach(() => { beforeEach(() => {
spyOn(service, 'getProjectMergeRequestChanges').and.returnValue( mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1/).networkError();
Promise.resolve({ data: { title: 'mergerequest' } }), });
);
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatch');
getMergeRequestData(
{
commit() {},
dispatch,
state: store.state,
},
{ projectId: 'abcproject', mergeRequestId: 1 },
)
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the merge request.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
projectId: 'abcproject',
mergeRequestId: 1,
force: false,
},
});
done();
});
});
});
});
describe('getMergeRequestChanges', () => {
beforeEach(() => {
store.state.projects.abcproject.mergeRequests['1'] = { changes: [] }; store.state.projects.abcproject.mergeRequests['1'] = { changes: [] };
}); });
describe('success', () => {
beforeEach(() => {
spyOn(service, 'getProjectMergeRequestChanges').and.callThrough();
mock
.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/changes/)
.reply(200, { title: 'mergerequest' });
});
it('calls getProjectMergeRequestChanges service method', done => { it('calls getProjectMergeRequestChanges service method', done => {
store store
.dispatch('getMergeRequestChanges', { projectId: 'abcproject', mergeRequestId: 1 }) .dispatch('getMergeRequestChanges', { projectId: 'abcproject', mergeRequestId: 1 })
...@@ -77,15 +132,54 @@ describe('IDE store merge request actions', () => { ...@@ -77,15 +132,54 @@ describe('IDE store merge request actions', () => {
}); });
}); });
describe('getMergeRequestVersions', () => { describe('error', () => {
beforeEach(() => { beforeEach(() => {
spyOn(service, 'getProjectMergeRequestVersions').and.returnValue( mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/changes/).networkError();
Promise.resolve({ data: [{ id: 789 }] }), });
);
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatch');
getMergeRequestChanges(
{
commit() {},
dispatch,
state: store.state,
},
{ projectId: 'abcproject', mergeRequestId: 1 },
)
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the merge request changes.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
projectId: 'abcproject',
mergeRequestId: 1,
force: false,
},
});
done();
});
});
});
});
describe('getMergeRequestVersions', () => {
beforeEach(() => {
store.state.projects.abcproject.mergeRequests['1'] = { versions: [] }; store.state.projects.abcproject.mergeRequests['1'] = { versions: [] };
}); });
describe('success', () => {
beforeEach(() => {
mock
.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/versions/)
.reply(200, [{ id: 789 }]);
spyOn(service, 'getProjectMergeRequestVersions').and.callThrough();
});
it('calls getProjectMergeRequestVersions service method', done => { it('calls getProjectMergeRequestVersions service method', done => {
store store
.dispatch('getMergeRequestVersions', { projectId: 'abcproject', mergeRequestId: 1 }) .dispatch('getMergeRequestVersions', { projectId: 'abcproject', mergeRequestId: 1 })
...@@ -107,4 +201,39 @@ describe('IDE store merge request actions', () => { ...@@ -107,4 +201,39 @@ describe('IDE store merge request actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
}); });
describe('error', () => {
beforeEach(() => {
mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/versions/).networkError();
});
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatch');
getMergeRequestVersions(
{
commit() {},
dispatch,
state: store.state,
},
{ projectId: 'abcproject', mergeRequestId: 1 },
)
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the merge request version data.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
projectId: 'abcproject',
mergeRequestId: 1,
force: false,
},
});
done();
});
});
});
});
}); });
...@@ -110,7 +110,7 @@ describe('IDE store project actions', () => { ...@@ -110,7 +110,7 @@ describe('IDE store project actions', () => {
type: 'setErrorMessage', type: 'setErrorMessage',
payload: { payload: {
text: "Branch <strong>master</strong> was not found in this project's repository.", text: "Branch <strong>master</strong> was not found in this project's repository.",
action: 'createNewBranchFromDefault', action: jasmine.any(Function),
actionText: 'Create branch', actionText: 'Create branch',
actionPayload: 'master', actionPayload: 'master',
}, },
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import Vue from 'vue';
import testAction from 'spec/helpers/vuex_action_helper'; import testAction from 'spec/helpers/vuex_action_helper';
import { showTreeEntry, getFiles } from '~/ide/stores/actions/tree'; import { showTreeEntry, getFiles } from '~/ide/stores/actions/tree';
import * as types from '~/ide/stores/mutation_types'; import * as types from '~/ide/stores/mutation_types';
...@@ -117,6 +116,40 @@ describe('Multi-file store tree actions', () => { ...@@ -117,6 +116,40 @@ describe('Multi-file store tree actions', () => {
done(); done();
}); });
}); });
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatchSpy');
store.state.projects = {
'abc/def': {
web_url: `${gl.TEST_HOST}/files`,
},
};
mock.onGet(/(.*)/).replyOnce(500);
getFiles(
{
commit() {},
dispatch,
state: store.state,
},
{
projectId: 'abc/def',
branchId: 'master-testing',
},
)
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading all the files.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: { projectId: 'abc/def', branchId: 'master-testing' },
});
done();
});
});
}); });
}); });
...@@ -168,72 +201,4 @@ describe('Multi-file store tree actions', () => { ...@@ -168,72 +201,4 @@ describe('Multi-file store tree actions', () => {
); );
}); });
}); });
describe('getLastCommitData', () => {
beforeEach(() => {
spyOn(service, 'getTreeLastCommit').and.returnValue(
Promise.resolve({
headers: {
'more-logs-url': null,
},
json: () =>
Promise.resolve([
{
type: 'tree',
file_name: 'testing',
commit: {
message: 'commit message',
authored_date: '123',
},
},
]),
}),
);
store.state.trees['abcproject/mybranch'] = {
tree: [],
};
projectTree = store.state.trees['abcproject/mybranch'];
projectTree.tree.push(file('testing', '1', 'tree'));
projectTree.lastCommitPath = 'lastcommitpath';
});
it('calls service with lastCommitPath', done => {
store
.dispatch('getLastCommitData', projectTree)
.then(() => {
expect(service.getTreeLastCommit).toHaveBeenCalledWith('lastcommitpath');
done();
})
.catch(done.fail);
});
it('updates trees last commit data', done => {
store
.dispatch('getLastCommitData', projectTree)
.then(Vue.nextTick)
.then(() => {
expect(projectTree.tree[0].lastCommit.message).toBe('commit message');
done();
})
.catch(done.fail);
});
it('does not update entry if not found', done => {
projectTree.tree[0].name = 'a';
store
.dispatch('getLastCommitData', projectTree)
.then(Vue.nextTick)
.then(() => {
expect(projectTree.tree[0].lastCommit.message).not.toBe('commit message');
done();
})
.catch(done.fail);
});
});
}); });
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