Skip to content
Snippets Groups Projects
Commit 0d7afb95 authored by Denys Mishunov's avatar Denys Mishunov Committed by Fatih Acet
Browse files

Updated heading for default state in Web IDE

parent 4ca791e6
No related branches found
No related tags found
No related merge requests found
Showing
with 561 additions and 244 deletions
<script>
import Vue from 'vue';
import { mapActions, mapState, mapGetters } from 'vuex';
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale';
import FindFile from '~/vue_shared/components/file_finder/index.vue';
import NewModal from './new_dropdown/modal.vue';
Loading
Loading
@@ -22,6 +23,8 @@ export default {
FindFile,
ErrorMessage,
CommitEditorHeader,
GlButton,
GlLoadingIcon,
},
props: {
rightPaneComponent: {
Loading
Loading
@@ -47,13 +50,15 @@ export default {
'someUncommittedChanges',
'isCommitModeActive',
'allBlobs',
'emptyRepo',
'currentTree',
]),
},
mounted() {
window.onbeforeunload = e => this.onBeforeUnload(e);
},
methods: {
...mapActions(['toggleFileFinder']),
...mapActions(['toggleFileFinder', 'openNewEntryModal']),
onBeforeUnload(e = {}) {
const returnValue = __('Are you sure you want to lose unsaved changes?');
 
Loading
Loading
@@ -98,17 +103,40 @@ export default {
<repo-editor :file="activeFile" class="multi-file-edit-pane-content" />
</template>
<template v-else>
<div v-once class="ide-empty-state">
<div class="ide-empty-state">
<div class="row js-empty-state">
<div class="col-12">
<div class="svg-content svg-250"><img :src="emptyStateSvgPath" /></div>
</div>
<div class="col-12">
<div class="text-content text-center">
<h4>Welcome to the GitLab IDE</h4>
<p>
Select a file from the left sidebar to begin editing. Afterwards, you'll be able
to commit your changes.
<h4>
{{ __('Make and review changes in the browser with the Web IDE') }}
</h4>
<template v-if="emptyRepo">
<p>
{{
__(
"Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes.",
)
}}
</p>
<gl-button
variant="success"
:title="__('New file')"
:aria-label="__('New file')"
@click="openNewEntryModal({ type: 'blob' })"
>
{{ __('New file') }}
</gl-button>
</template>
<gl-loading-icon v-else-if="!currentTree || currentTree.loading" size="md" />
<p v-else>
{{
__(
"Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes.",
)
}}
</p>
</div>
</div>
Loading
Loading
Loading
Loading
@@ -54,14 +54,17 @@ export default {
<slot name="header"></slot>
</header>
<div class="ide-tree-body h-100">
<file-row
v-for="file in currentTree.tree"
:key="file.key"
:file="file"
:level="0"
:extra-component="$options.FileRowExtra"
@toggleTreeOpen="toggleTreeOpen"
/>
<template v-if="currentTree.tree.length">
<file-row
v-for="file in currentTree.tree"
:key="file.key"
:file="file"
:level="0"
:extra-component="$options.FileRowExtra"
@toggleTreeOpen="toggleTreeOpen"
/>
</template>
<div v-else class="file-row">{{ __('No files') }}</div>
</div>
</template>
</div>
Loading
Loading
import $ from 'jquery';
import Vue from 'vue';
import { __, sprintf } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility';
import flash from '~/flash';
import _ from 'underscore';
import * as types from './mutation_types';
import { decorateFiles } from '../lib/files';
import { stageKeys } from '../constants';
import service from '../services';
 
export const redirectToUrl = (_, url) => visitUrl(url);
export const redirectToUrl = (self, url) => visitUrl(url);
 
export const setInitialData = ({ commit }, data) => commit(types.SET_INITIAL_DATA, data);
 
Loading
Loading
@@ -239,6 +242,53 @@ export const renameEntry = (
}
};
 
export const getBranchData = ({ commit, state }, { projectId, branchId, force = false } = {}) =>
new Promise((resolve, reject) => {
const currentProject = state.projects[projectId];
if (!currentProject || !currentProject.branches[branchId] || force) {
service
.getBranchData(projectId, branchId)
.then(({ data }) => {
const { id } = data.commit;
commit(types.SET_BRANCH, {
projectPath: projectId,
branchName: branchId,
branch: data,
});
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
resolve(data);
})
.catch(e => {
if (e.response.status === 404) {
reject(e);
} else {
flash(
__('Error loading branch data. Please try again.'),
'alert',
document,
null,
false,
true,
);
reject(
new Error(
sprintf(
__('Branch not loaded - %{branchId}'),
{
branchId: `<strong>${_.escape(projectId)}/${_.escape(branchId)}</strong>`,
},
false,
),
),
);
}
});
} else {
resolve(currentProject.branches[branchId]);
}
});
export * from './actions/tree';
export * from './actions/file';
export * from './actions/project';
Loading
Loading
Loading
Loading
@@ -35,48 +35,6 @@ export const getProjectData = ({ commit, state }, { namespace, projectId, force
}
});
 
export const getBranchData = (
{ commit, dispatch, state },
{ projectId, branchId, force = false } = {},
) =>
new Promise((resolve, reject) => {
if (
typeof state.projects[`${projectId}`] === 'undefined' ||
!state.projects[`${projectId}`].branches[branchId] ||
force
) {
service
.getBranchData(`${projectId}`, branchId)
.then(({ data }) => {
const { id } = data.commit;
commit(types.SET_BRANCH, {
projectPath: `${projectId}`,
branchName: branchId,
branch: data,
});
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
resolve(data);
})
.catch(e => {
if (e.response.status === 404) {
dispatch('showBranchNotFoundError', branchId);
} else {
flash(
__('Error loading branch data. Please try again.'),
'alert',
document,
null,
false,
true,
);
}
reject(new Error(`Branch not loaded - ${projectId}/${branchId}`));
});
} else {
resolve(state.projects[`${projectId}`].branches[branchId]);
}
});
export const refreshLastCommitData = ({ commit }, { projectId, branchId } = {}) =>
service
.getBranchData(projectId, branchId)
Loading
Loading
@@ -125,40 +83,66 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
});
};
 
export const openBranch = ({ dispatch, state }, { projectId, branchId, basePath }) => {
dispatch('setCurrentBranchId', branchId);
dispatch('getBranchData', {
projectId,
branchId,
export const showEmptyState = ({ commit, state }, { projectId, branchId }) => {
const treePath = `${projectId}/${branchId}`;
commit(types.CREATE_TREE, { treePath });
commit(types.TOGGLE_LOADING, {
entry: state.trees[treePath],
forceValue: false,
});
};
 
return dispatch('getFiles', {
export const openBranch = ({ dispatch, state, getters }, { projectId, branchId, basePath }) => {
dispatch('setCurrentBranchId', branchId);
if (getters.emptyRepo) {
return dispatch('showEmptyState', { projectId, branchId });
}
return dispatch('getBranchData', {
projectId,
branchId,
})
.then(() => {
if (basePath) {
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
const treeEntryKey = Object.keys(state.entries).find(
key => key === path && !state.entries[key].pending,
);
const treeEntry = state.entries[treeEntryKey];
if (treeEntry) {
dispatch('handleTreeEntryAction', treeEntry);
} else {
dispatch('createTempEntry', {
name: path,
type: 'blob',
});
}
}
})
.then(() => {
dispatch('getMergeRequestsForBranch', {
projectId,
branchId,
});
dispatch('getFiles', {
projectId,
branchId,
})
.then(() => {
if (basePath) {
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
const treeEntryKey = Object.keys(state.entries).find(
key => key === path && !state.entries[key].pending,
);
const treeEntry = state.entries[treeEntryKey];
if (treeEntry) {
dispatch('handleTreeEntryAction', treeEntry);
} else {
dispatch('createTempEntry', {
name: path,
type: 'blob',
});
}
}
})
.catch(
() =>
new Error(
sprintf(
__('An error occurred whilst getting files for - %{branchId}'),
{
branchId: `<strong>${_.escape(projectId)}/${_.escape(branchId)}</strong>`,
},
false,
),
),
);
})
.catch(() => {
dispatch('showBranchNotFoundError', branchId);
});
};
Loading
Loading
@@ -74,17 +74,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
resolve();
})
.catch(e => {
if (e.response.status === 404) {
dispatch('showBranchNotFoundError', branchId);
} else {
dispatch('setErrorMessage', {
text: __('An error occurred whilst loading all the files.'),
action: payload =>
dispatch('getFiles', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
actionPayload: { projectId, branchId },
});
}
dispatch('setErrorMessage', {
text: __('An error occurred whilst loading all the files.'),
action: payload =>
dispatch('getFiles', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
actionPayload: { projectId, branchId },
});
reject(e);
});
} else {
Loading
Loading
Loading
Loading
@@ -36,6 +36,9 @@ export const currentMergeRequest = state => {
 
export const currentProject = state => state.projects[state.currentProjectId];
 
export const emptyRepo = state =>
state.projects[state.currentProjectId] && state.projects[state.currentProjectId].empty_repo;
export const currentTree = state =>
state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
 
Loading
Loading
Loading
Loading
@@ -135,6 +135,17 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
return null;
}
 
if (!data.parent_ids.length) {
commit(
rootTypes.TOGGLE_EMPTY_STATE,
{
projectPath: rootState.currentProjectId,
value: false,
},
{ root: true },
);
}
dispatch('setLastCommitMessage', data);
dispatch('updateCommitMessage', '');
return dispatch('updateFilesAfterCommit', {
Loading
Loading
Loading
Loading
@@ -12,6 +12,7 @@ export const SET_LINKS = 'SET_LINKS';
export const SET_PROJECT = 'SET_PROJECT';
export const SET_CURRENT_PROJECT = 'SET_CURRENT_PROJECT';
export const TOGGLE_PROJECT_OPEN = 'TOGGLE_PROJECT_OPEN';
export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE';
 
// Merge Request Mutation Types
export const SET_MERGE_REQUEST = 'SET_MERGE_REQUEST';
Loading
Loading
Loading
Loading
@@ -19,6 +19,12 @@ export default {
});
},
[types.SET_BRANCH_WORKING_REFERENCE](state, { projectId, branchId, reference }) {
if (!state.projects[projectId].branches[branchId]) {
Object.assign(state.projects[projectId].branches, {
[branchId]: {},
});
}
Object.assign(state.projects[projectId].branches[branchId], {
workingReference: reference,
});
Loading
Loading
Loading
Loading
@@ -21,4 +21,9 @@ export default {
}),
});
},
[types.TOGGLE_EMPTY_STATE](state, { projectPath, value }) {
Object.assign(state.projects[projectPath], {
empty_repo: value,
});
},
};
---
title: Empty project state for Web IDE
merge_request: 26556
author:
type: added
Loading
Loading
@@ -239,6 +239,7 @@ module API
end
end
 
expose :empty_repo?, as: :empty_repo
expose :archived?, as: :archived
expose :visibility
expose :owner, using: Entities::UserBasic, unless: ->(project, options) { project.group }
Loading
Loading
Loading
Loading
@@ -952,6 +952,9 @@ msgstr ""
msgid "An error occurred whilst fetching the latest pipeline."
msgstr ""
 
msgid "An error occurred whilst getting files for - %{branchId}"
msgstr ""
msgid "An error occurred whilst loading all the files."
msgstr ""
 
Loading
Loading
@@ -1482,6 +1485,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
 
msgid "Branch not loaded - %{branchId}"
msgstr ""
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr ""
 
Loading
Loading
@@ -2993,6 +2999,9 @@ msgstr ""
msgid "Create a new branch"
msgstr ""
 
msgid "Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes."
msgstr ""
msgid "Create a new issue"
msgstr ""
 
Loading
Loading
@@ -5796,6 +5805,9 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
 
msgid "Make and review changes in the browser with the Web IDE"
msgstr ""
msgid "Make issue confidential."
msgstr ""
 
Loading
Loading
@@ -6452,6 +6464,9 @@ msgstr ""
msgid "No file selected"
msgstr ""
 
msgid "No files"
msgstr ""
msgid "No files found."
msgstr ""
 
Loading
Loading
@@ -8615,6 +8630,9 @@ msgstr ""
msgid "Select Archive Format"
msgstr ""
 
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
msgstr ""
msgid "Select a group to invite"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -37,4 +37,39 @@ describe('Multi-file store branch mutations', () => {
expect(localState.projects.Example.branches.master.commit.title).toBe('Example commit');
});
});
describe('SET_BRANCH_WORKING_REFERENCE', () => {
beforeEach(() => {
localState.projects = {
Foo: {
branches: {
bar: {},
},
},
};
});
it('sets workingReference for existing branch', () => {
mutations.SET_BRANCH_WORKING_REFERENCE(localState, {
projectId: 'Foo',
branchId: 'bar',
reference: 'foo-bar-ref',
});
expect(localState.projects.Foo.branches.bar.workingReference).toBe('foo-bar-ref');
});
it('does not fail on non-existent just yet branch', () => {
expect(localState.projects.Foo.branches.unknown).toBeUndefined();
mutations.SET_BRANCH_WORKING_REFERENCE(localState, {
projectId: 'Foo',
branchId: 'unknown',
reference: 'fun-fun-ref',
});
expect(localState.projects.Foo.branches.unknown).not.toBeUndefined();
expect(localState.projects.Foo.branches.unknown.workingReference).toBe('fun-fun-ref');
});
});
});
import mutations from '~/ide/stores/mutations/project';
import state from '~/ide/stores/state';
describe('Multi-file store branch mutations', () => {
let localState;
beforeEach(() => {
localState = state();
localState.projects = { abcproject: { empty_repo: true } };
});
describe('TOGGLE_EMPTY_STATE', () => {
it('sets empty_repo for project to passed value', () => {
mutations.TOGGLE_EMPTY_STATE(localState, { projectPath: 'abcproject', value: false });
expect(localState.projects.abcproject.empty_repo).toBe(false);
mutations.TOGGLE_EMPTY_STATE(localState, { projectPath: 'abcproject', value: true });
expect(localState.projects.abcproject.empty_repo).toBe(true);
});
});
});
Loading
Loading
@@ -5,21 +5,53 @@ import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helpe
import { file, resetStore } from '../helpers';
import { projectData } from '../mock_data';
 
describe('ide component', () => {
function bootstrap(projData) {
const Component = Vue.extend(ide);
store.state.currentProjectId = 'abcproject';
store.state.currentBranchId = 'master';
store.state.projects.abcproject = Object.assign({}, projData);
Vue.set(store.state.trees, 'abcproject/master', {
tree: [],
loading: false,
});
return createComponentWithStore(Component, store, {
emptyStateSvgPath: 'svg',
noChangesStateSvgPath: 'svg',
committedStateSvgPath: 'svg',
});
}
describe('ide component, empty repo', () => {
let vm;
 
beforeEach(() => {
const Component = Vue.extend(ide);
const emptyProjData = Object.assign({}, projectData, { empty_repo: true, branches: {} });
vm = bootstrap(emptyProjData);
vm.$mount();
});
 
store.state.currentProjectId = 'abcproject';
store.state.currentBranchId = 'master';
store.state.projects.abcproject = Object.assign({}, projectData);
afterEach(() => {
vm.$destroy();
resetStore(vm.$store);
});
 
vm = createComponentWithStore(Component, store, {
emptyStateSvgPath: 'svg',
noChangesStateSvgPath: 'svg',
committedStateSvgPath: 'svg',
}).$mount();
it('renders "New file" button in empty repo', done => {
vm.$nextTick(() => {
expect(vm.$el.querySelector('.ide-empty-state button[title="New file"]')).not.toBeNull();
done();
});
});
});
describe('ide component, non-empty repo', () => {
let vm;
beforeEach(() => {
vm = bootstrap(projectData);
vm.$mount();
});
 
afterEach(() => {
Loading
Loading
@@ -28,17 +60,15 @@ describe('ide component', () => {
resetStore(vm.$store);
});
 
it('does not render right when no files open', () => {
expect(vm.$el.querySelector('.panel-right')).toBeNull();
});
it('shows error message when set', done => {
expect(vm.$el.querySelector('.flash-container')).toBe(null);
 
it('renders right panel when files are open', done => {
vm.$store.state.trees['abcproject/mybranch'] = {
tree: [file()],
vm.$store.state.errorMessage = {
text: 'error',
};
 
Vue.nextTick(() => {
expect(vm.$el.querySelector('.panel-right')).toBeNull();
vm.$nextTick(() => {
expect(vm.$el.querySelector('.flash-container')).not.toBe(null);
 
done();
});
Loading
Loading
@@ -71,17 +101,25 @@ describe('ide component', () => {
});
});
 
it('shows error message when set', done => {
expect(vm.$el.querySelector('.flash-container')).toBe(null);
vm.$store.state.errorMessage = {
text: 'error',
};
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();
});
});
});
 
vm.$nextTick(() => {
expect(vm.$el.querySelector('.flash-container')).not.toBe(null);
describe('branch with files', () => {
beforeEach(() => {
store.state.trees['abcproject/master'].tree = [file()];
});
 
done();
it('does not render "New file" button', done => {
vm.$nextTick(() => {
expect(vm.$el.querySelector('.ide-empty-state button[title="New file"]')).toBeNull();
done();
});
});
});
});
Loading
Loading
@@ -7,25 +7,23 @@ import { projectData } from '../mock_data';
 
describe('IDE tree list', () => {
const Component = Vue.extend(IdeTreeList);
const normalBranchTree = [file('fileName')];
const emptyBranchTree = [];
let vm;
 
beforeEach(() => {
const bootstrapWithTree = (tree = normalBranchTree) => {
store.state.currentProjectId = 'abcproject';
store.state.currentBranchId = 'master';
store.state.projects.abcproject = Object.assign({}, projectData);
Vue.set(store.state.trees, 'abcproject/master', {
tree: [file('fileName')],
tree,
loading: false,
});
 
vm = createComponentWithStore(Component, store, {
viewerType: 'edit',
});
spyOn(vm, 'updateViewer').and.callThrough();
vm.$mount();
});
};
 
afterEach(() => {
vm.$destroy();
Loading
Loading
@@ -33,22 +31,47 @@ describe('IDE tree list', () => {
resetStore(vm.$store);
});
 
it('updates viewer on mount', () => {
expect(vm.updateViewer).toHaveBeenCalledWith('edit');
});
describe('normal branch', () => {
beforeEach(() => {
bootstrapWithTree();
spyOn(vm, 'updateViewer').and.callThrough();
vm.$mount();
});
it('updates viewer on mount', () => {
expect(vm.updateViewer).toHaveBeenCalledWith('edit');
});
it('renders loading indicator', done => {
store.state.trees['abcproject/master'].loading = true;
 
it('renders loading indicator', done => {
store.state.trees['abcproject/master'].loading = true;
vm.$nextTick(() => {
expect(vm.$el.querySelector('.multi-file-loading-container')).not.toBeNull();
expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toBe(3);
 
vm.$nextTick(() => {
expect(vm.$el.querySelector('.multi-file-loading-container')).not.toBeNull();
expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toBe(3);
done();
});
});
 
done();
it('renders list of files', () => {
expect(vm.$el.textContent).toContain('fileName');
});
});
 
it('renders list of files', () => {
expect(vm.$el.textContent).toContain('fileName');
describe('empty-branch state', () => {
beforeEach(() => {
bootstrapWithTree(emptyBranchTree);
spyOn(vm, 'updateViewer').and.callThrough();
vm.$mount();
});
it('does not load files if the branch is empty', () => {
expect(vm.$el.textContent).not.toContain('fileName');
expect(vm.$el.textContent).toContain('No files');
});
});
});
Loading
Loading
@@ -4,7 +4,7 @@ import {
refreshLastCommitData,
showBranchNotFoundError,
createNewBranchFromDefault,
getBranchData,
showEmptyState,
openBranch,
} from '~/ide/stores/actions';
import store from '~/ide/stores';
Loading
Loading
@@ -196,39 +196,44 @@ describe('IDE store project actions', () => {
});
});
 
describe('getBranchData', () => {
describe('error', () => {
it('dispatches branch not found action when response is 404', done => {
const dispatch = jasmine.createSpy('dispatchSpy');
mock.onGet(/(.*)/).replyOnce(404);
getBranchData(
describe('showEmptyState', () => {
it('commits proper mutations when supplied error is 404', done => {
testAction(
showEmptyState,
{
err: {
response: {
status: 404,
},
},
projectId: 'abc/def',
branchId: 'master',
},
store.state,
[
{
commit() {},
dispatch,
state: store.state,
type: 'CREATE_TREE',
payload: {
treePath: 'abc/def/master',
},
},
{
projectId: 'abc/def',
branchId: 'master-testing',
type: 'TOGGLE_LOADING',
payload: {
entry: store.state.trees['abc/def/master'],
forceValue: false,
},
},
)
.then(done.fail)
.catch(() => {
expect(dispatch.calls.argsFor(0)).toEqual([
'showBranchNotFoundError',
'master-testing',
]);
done();
});
});
],
[],
done,
);
});
});
 
describe('openBranch', () => {
const branch = {
projectId: 'feature/lorem-ipsum',
projectId: 'abc/def',
branchId: '123-lorem',
};
 
Loading
Loading
@@ -238,63 +243,113 @@ describe('IDE store project actions', () => {
'foo/bar-pending': { pending: true },
'foo/bar': { pending: false },
};
spyOn(store, 'dispatch').and.returnValue(Promise.resolve());
});
 
it('dispatches branch actions', done => {
openBranch(store, branch)
.then(() => {
expect(store.dispatch.calls.allArgs()).toEqual([
['setCurrentBranchId', branch.branchId],
['getBranchData', branch],
['getFiles', branch],
['getMergeRequestsForBranch', branch],
]);
})
.then(done)
.catch(done.fail);
});
describe('empty repo', () => {
beforeEach(() => {
spyOn(store, 'dispatch').and.returnValue(Promise.resolve());
 
it('handles tree entry action, if basePath is given', done => {
openBranch(store, { ...branch, basePath: 'foo/bar/' })
.then(() => {
expect(store.dispatch).toHaveBeenCalledWith(
'handleTreeEntryAction',
store.state.entries['foo/bar'],
);
})
.then(done)
.catch(done.fail);
store.state.currentProjectId = 'abc/def';
store.state.projects['abc/def'] = {
empty_repo: true,
};
});
afterEach(() => {
resetStore(store);
});
it('dispatches showEmptyState action right away', done => {
openBranch(store, branch)
.then(() => {
expect(store.dispatch.calls.allArgs()).toEqual([
['setCurrentBranchId', branch.branchId],
['showEmptyState', branch],
]);
done();
})
.catch(done.fail);
});
});
 
it('does not handle tree entry action, if entry is pending', done => {
openBranch(store, { ...branch, basePath: 'foo/bar-pending' })
.then(() => {
expect(store.dispatch).not.toHaveBeenCalledWith(
'handleTreeEntryAction',
jasmine.anything(),
);
})
.then(done)
.catch(done.fail);
describe('existing branch', () => {
beforeEach(() => {
spyOn(store, 'dispatch').and.returnValue(Promise.resolve());
});
it('dispatches branch actions', done => {
openBranch(store, branch)
.then(() => {
expect(store.dispatch.calls.allArgs()).toEqual([
['setCurrentBranchId', branch.branchId],
['getBranchData', branch],
['getMergeRequestsForBranch', branch],
['getFiles', branch],
]);
})
.then(done)
.catch(done.fail);
});
it('handles tree entry action, if basePath is given', done => {
openBranch(store, { ...branch, basePath: 'foo/bar/' })
.then(() => {
expect(store.dispatch).toHaveBeenCalledWith(
'handleTreeEntryAction',
store.state.entries['foo/bar'],
);
})
.then(done)
.catch(done.fail);
});
it('does not handle tree entry action, if entry is pending', done => {
openBranch(store, { ...branch, basePath: 'foo/bar-pending' })
.then(() => {
expect(store.dispatch).not.toHaveBeenCalledWith(
'handleTreeEntryAction',
jasmine.anything(),
);
})
.then(done)
.catch(done.fail);
});
it('creates a new file supplied via URL if the file does not exist yet', done => {
openBranch(store, { ...branch, basePath: 'not-existent.md' })
.then(() => {
expect(store.dispatch).not.toHaveBeenCalledWith(
'handleTreeEntryAction',
jasmine.anything(),
);
expect(store.dispatch).toHaveBeenCalledWith('createTempEntry', {
name: 'not-existent.md',
type: 'blob',
});
})
.then(done)
.catch(done.fail);
});
});
 
it('creates a new file supplied via URL if the file does not exist yet', done => {
openBranch(store, { ...branch, basePath: 'not-existent.md' })
.then(() => {
expect(store.dispatch).not.toHaveBeenCalledWith(
'handleTreeEntryAction',
jasmine.anything(),
);
describe('non-existent branch', () => {
beforeEach(() => {
spyOn(store, 'dispatch').and.returnValue(Promise.reject());
});
 
expect(store.dispatch).toHaveBeenCalledWith('createTempEntry', {
name: 'not-existent.md',
type: 'blob',
});
})
.then(done)
.catch(done.fail);
it('dispatches correct branch actions', done => {
openBranch(store, branch)
.then(() => {
expect(store.dispatch.calls.allArgs()).toEqual([
['setCurrentBranchId', branch.branchId],
['getBranchData', branch],
['showBranchNotFoundError', branch.branchId],
]);
})
.then(done)
.catch(done.fail);
});
});
});
});
Loading
Loading
@@ -93,38 +93,6 @@ describe('Multi-file store tree actions', () => {
});
 
describe('error', () => {
it('dispatches branch not found actions when response is 404', done => {
const dispatch = jasmine.createSpy('dispatchSpy');
store.state.projects = {
'abc/def': {
web_url: `${gl.TEST_HOST}/files`,
},
};
mock.onGet(/(.*)/).replyOnce(404);
getFiles(
{
commit() {},
dispatch,
state: store.state,
},
{
projectId: 'abc/def',
branchId: 'master-testing',
},
)
.then(done.fail)
.catch(() => {
expect(dispatch.calls.argsFor(0)).toEqual([
'showBranchNotFoundError',
'master-testing',
]);
done();
});
});
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatchSpy');
 
Loading
Loading
Loading
Loading
@@ -9,12 +9,15 @@ import actions, {
setErrorMessage,
deleteEntry,
renameEntry,
getBranchData,
} from '~/ide/stores/actions';
import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores';
import * as types from '~/ide/stores/mutation_types';
import router from '~/ide/ide_router';
import { resetStore, file } from '../helpers';
import testAction from '../../helpers/vuex_action_helper';
import MockAdapter from 'axios-mock-adapter';
 
describe('Multi-file store actions', () => {
beforeEach(() => {
Loading
Loading
@@ -560,4 +563,65 @@ describe('Multi-file store actions', () => {
);
});
});
describe('getBranchData', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('error', () => {
let dispatch;
const callParams = [
{
commit() {},
state: store.state,
},
{
projectId: 'abc/def',
branchId: 'master-testing',
},
];
beforeEach(() => {
dispatch = jasmine.createSpy('dispatchSpy');
document.body.innerHTML += '<div class="flash-container"></div>';
});
afterEach(() => {
document.querySelector('.flash-container').remove();
});
it('passes the error further unchanged without dispatching any action when response is 404', done => {
mock.onGet(/(.*)/).replyOnce(404);
getBranchData(...callParams)
.then(done.fail)
.catch(e => {
expect(dispatch.calls.count()).toEqual(0);
expect(e.response.status).toEqual(404);
expect(document.querySelector('.flash-alert')).toBeNull();
done();
});
});
it('does not pass the error further and flashes an alert if error is not 404', done => {
mock.onGet(/(.*)/).replyOnce(418);
getBranchData(...callParams)
.then(done.fail)
.catch(e => {
expect(dispatch.calls.count()).toEqual(0);
expect(e.response).toBeUndefined();
expect(document.querySelector('.flash-alert')).not.toBeNull();
done();
});
});
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment