import actions, {
stageAllChanges,
unstageAllChanges,
toggleFileFinder,
setCurrentBranchId,
setEmptyStateSvgs,
updateActivityBarView,
updateTempFlagForEntry,
setErrorMessage,
deleteEntry,
renameEntry,
getBranchData,
createTempEntry,
} 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(() => {
spyOn(router, 'push');
});
afterEach(() => {
resetStore(store);
});
describe('redirectToUrl', () => {
it('calls visitUrl', done => {
const visitUrl = spyOnDependency(actions, 'visitUrl');
store
.dispatch('redirectToUrl', 'test')
.then(() => {
expect(visitUrl).toHaveBeenCalledWith('test');
done();
})
.catch(done.fail);
});
});
describe('setInitialData', () => {
it('commits initial data', done => {
store
.dispatch('setInitialData', { canCommit: true })
.then(() => {
expect(store.state.canCommit).toBeTruthy();
done();
})
.catch(done.fail);
});
});
describe('discardAllChanges', () => {
beforeEach(() => {
const f = file('discardAll');
f.changed = true;
store.state.openFiles.push(f);
store.state.changedFiles.push(f);
store.state.entries[f.path] = f;
});
it('discards changes in file', done => {
store
.dispatch('discardAllChanges')
.then(() => {
expect(store.state.openFiles.changed).toBeFalsy();
})
.then(done)
.catch(done.fail);
});
it('removes all files from changedFiles state', done => {
store
.dispatch('discardAllChanges')
.then(() => {
expect(store.state.changedFiles.length).toBe(0);
expect(store.state.openFiles.length).toBe(1);
})
.then(done)
.catch(done.fail);
});
});
describe('closeAllFiles', () => {
beforeEach(() => {
const f = file('closeAll');
store.state.openFiles.push(f);
store.state.openFiles[0].opened = true;
store.state.entries[f.path] = f;
});
it('closes all open files', done => {
store
.dispatch('closeAllFiles')
.then(() => {
expect(store.state.openFiles.length).toBe(0);
done();
})
.catch(done.fail);
});
});
describe('createTempEntry', () => {
beforeEach(() => {
document.body.innerHTML += '
';
store.state.currentProjectId = 'abcproject';
store.state.currentBranchId = 'mybranch';
store.state.trees['abcproject/mybranch'] = {
tree: [],
};
store.state.projects.abcproject = {
web_url: '',
};
});
afterEach(() => {
document.querySelector('.flash-container').remove();
});
describe('tree', () => {
it('creates temp tree', done => {
store
.dispatch('createTempEntry', {
branchId: store.state.currentBranchId,
name: 'test',
type: 'tree',
})
.then(() => {
const entry = store.state.entries.test;
expect(entry).not.toBeNull();
expect(entry.type).toBe('tree');
done();
})
.catch(done.fail);
});
it('creates new folder inside another tree', done => {
const tree = {
type: 'tree',
name: 'testing',
path: 'testing',
tree: [],
};
store.state.entries[tree.path] = tree;
store
.dispatch('createTempEntry', {
branchId: store.state.currentBranchId,
name: 'testing/test',
type: 'tree',
})
.then(() => {
expect(tree.tree[0].tempFile).toBeTruthy();
expect(tree.tree[0].name).toBe('test');
expect(tree.tree[0].type).toBe('tree');
done();
})
.catch(done.fail);
});
it('does not create new tree if already exists', done => {
const tree = {
type: 'tree',
path: 'testing',
tempFile: false,
tree: [],
};
store.state.entries[tree.path] = tree;
store
.dispatch('createTempEntry', {
branchId: store.state.currentBranchId,
name: 'testing',
type: 'tree',
})
.then(() => {
expect(store.state.entries[tree.path].tempFile).toEqual(false);
expect(document.querySelector('.flash-alert')).not.toBeNull();
done();
})
.catch(done.fail);
});
});
describe('blob', () => {
it('creates temp file', done => {
store
.dispatch('createTempEntry', {
name: 'test',
branchId: 'mybranch',
type: 'blob',
})
.then(f => {
expect(f.tempFile).toBeTruthy();
expect(store.state.trees['abcproject/mybranch'].tree.length).toBe(1);
done();
})
.catch(done.fail);
});
it('adds tmp file to open files', done => {
store
.dispatch('createTempEntry', {
name: 'test',
branchId: 'mybranch',
type: 'blob',
})
.then(f => {
expect(store.state.openFiles.length).toBe(1);
expect(store.state.openFiles[0].name).toBe(f.name);
done();
})
.catch(done.fail);
});
it('adds tmp file to changed files', done => {
store
.dispatch('createTempEntry', {
name: 'test',
branchId: 'mybranch',
type: 'blob',
})
.then(f => {
expect(store.state.changedFiles.length).toBe(1);
expect(store.state.changedFiles[0].name).toBe(f.name);
done();
})
.catch(done.fail);
});
it('sets tmp file as active', done => {
testAction(
createTempEntry,
{
name: 'test',
branchId: 'mybranch',
type: 'blob',
},
store.state,
[
{ type: types.CREATE_TMP_ENTRY, payload: jasmine.any(Object) },
{ type: types.TOGGLE_FILE_OPEN, payload: 'test' },
{ type: types.ADD_FILE_TO_CHANGED, payload: 'test' },
],
[
{
type: 'setFileActive',
payload: 'test',
},
{
type: 'triggerFilesChange',
},
],
done,
);
});
it('creates flash message if file already exists', done => {
const f = file('test', '1', 'blob');
store.state.trees['abcproject/mybranch'].tree = [f];
store.state.entries[f.path] = f;
store
.dispatch('createTempEntry', {
name: 'test',
branchId: 'mybranch',
type: 'blob',
})
.then(() => {
expect(document.querySelector('.flash-alert')).not.toBeNull();
done();
})
.catch(done.fail);
});
});
});
describe('scrollToTab', () => {
it('focuses the current active element', done => {
document.body.innerHTML +=
'';
const el = document.querySelector('.repo-tab');
spyOn(el, 'focus');
store
.dispatch('scrollToTab')
.then(() => {
setTimeout(() => {
expect(el.focus).toHaveBeenCalled();
document.getElementById('tabs').remove();
done();
});
})
.catch(done.fail);
});
});
describe('stageAllChanges', () => {
it('adds all files from changedFiles to stagedFiles', done => {
const openFile = { ...file(), path: 'test' };
store.state.openFiles.push(openFile);
store.state.stagedFiles.push(openFile);
store.state.changedFiles.push(openFile, file('new'));
testAction(
stageAllChanges,
null,
store.state,
[
{ type: types.SET_LAST_COMMIT_MSG, payload: '' },
{ type: types.STAGE_CHANGE, payload: store.state.changedFiles[0].path },
{ type: types.STAGE_CHANGE, payload: store.state.changedFiles[1].path },
],
[
{
type: 'openPendingTab',
payload: { file: openFile, keyPrefix: 'staged' },
},
],
done,
);
});
});
describe('unstageAllChanges', () => {
it('removes all files from stagedFiles after unstaging', done => {
const openFile = { ...file(), path: 'test' };
store.state.openFiles.push(openFile);
store.state.changedFiles.push(openFile);
store.state.stagedFiles.push(openFile, file('new'));
testAction(
unstageAllChanges,
null,
store.state,
[
{ type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[0].path },
{ type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[1].path },
],
[
{
type: 'openPendingTab',
payload: { file: openFile, keyPrefix: 'unstaged' },
},
],
done,
);
});
});
describe('updateViewer', () => {
it('updates viewer state', done => {
store
.dispatch('updateViewer', 'diff')
.then(() => {
expect(store.state.viewer).toBe('diff');
})
.then(done)
.catch(done.fail);
});
});
describe('updateActivityBarView', () => {
it('commits UPDATE_ACTIVITY_BAR_VIEW', done => {
testAction(
updateActivityBarView,
'test',
{},
[{ type: 'UPDATE_ACTIVITY_BAR_VIEW', payload: 'test' }],
[],
done,
);
});
});
describe('setEmptyStateSvgs', () => {
it('commits setEmptyStateSvgs', done => {
testAction(
setEmptyStateSvgs,
'svg',
{},
[{ type: 'SET_EMPTY_STATE_SVGS', payload: 'svg' }],
[],
done,
);
});
});
describe('updateTempFlagForEntry', () => {
it('commits UPDATE_TEMP_FLAG', done => {
const f = {
...file(),
path: 'test',
tempFile: true,
};
store.state.entries[f.path] = f;
testAction(
updateTempFlagForEntry,
{ file: f, tempFile: false },
store.state,
[{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
[],
done,
);
});
it('commits UPDATE_TEMP_FLAG and dispatches for parent', done => {
const parent = {
...file(),
path: 'testing',
};
const f = {
...file(),
path: 'test',
parentPath: 'testing',
};
store.state.entries[parent.path] = parent;
store.state.entries[f.path] = f;
testAction(
updateTempFlagForEntry,
{ file: f, tempFile: false },
store.state,
[{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
[{ type: 'updateTempFlagForEntry', payload: { file: parent, tempFile: false } }],
done,
);
});
});
describe('setCurrentBranchId', () => {
it('commits setCurrentBranchId', done => {
testAction(
setCurrentBranchId,
'branchId',
{},
[{ type: 'SET_CURRENT_BRANCH', payload: 'branchId' }],
[],
done,
);
});
});
describe('toggleFileFinder', () => {
it('commits TOGGLE_FILE_FINDER', done => {
testAction(
toggleFileFinder,
true,
null,
[{ type: 'TOGGLE_FILE_FINDER', payload: true }],
[],
done,
);
});
});
describe('setErrorMessage', () => {
it('commis error messsage', done => {
testAction(
setErrorMessage,
'error',
null,
[{ type: types.SET_ERROR_MESSAGE, payload: 'error' }],
[],
done,
);
});
});
describe('deleteEntry', () => {
it('commits entry deletion', done => {
store.state.entries.path = 'testing';
testAction(
deleteEntry,
'path',
store.state,
[{ type: types.DELETE_ENTRY, payload: 'path' }],
[
{ type: 'burstUnusedSeal' },
{ type: 'stageChange', payload: 'path' },
{ type: 'triggerFilesChange' },
],
done,
);
});
it('does not delete a folder after it is emptied', done => {
const testFolder = {
type: 'tree',
tree: [],
};
const testEntry = {
path: 'testFolder/entry-to-delete',
parentPath: 'testFolder',
opened: false,
tree: [],
};
testFolder.tree.push(testEntry);
store.state.entries = {
testFolder,
'testFolder/entry-to-delete': testEntry,
};
testAction(
deleteEntry,
'testFolder/entry-to-delete',
store.state,
[{ type: types.DELETE_ENTRY, payload: 'testFolder/entry-to-delete' }],
[
{ type: 'burstUnusedSeal' },
{ type: 'stageChange', payload: 'testFolder/entry-to-delete' },
{ type: 'triggerFilesChange' },
],
done,
);
});
});
describe('renameEntry', () => {
it('renames entry', done => {
store.state.entries.test = {
tree: [],
};
testAction(
renameEntry,
{ path: 'test', name: 'new-name', entryPath: null, parentPath: 'parent-path' },
store.state,
[
{
type: types.RENAME_ENTRY,
payload: { path: 'test', name: 'new-name', entryPath: null, parentPath: 'parent-path' },
},
{
type: types.TOGGLE_FILE_CHANGED,
payload: {
file: store.state.entries['parent-path/new-name'],
changed: true,
},
},
],
[{ type: 'triggerFilesChange' }],
done,
);
});
it('renames all entries in tree', done => {
store.state.entries.test = {
type: 'tree',
tree: [
{
path: 'tree-1',
},
{
path: 'tree-2',
},
],
};
testAction(
renameEntry,
{ path: 'test', name: 'new-name', parentPath: 'parent-path' },
store.state,
[
{
type: types.RENAME_ENTRY,
payload: { path: 'test', name: 'new-name', entryPath: null, parentPath: 'parent-path' },
},
],
[
{
type: 'renameEntry',
payload: {
path: 'test',
name: 'new-name',
entryPath: 'tree-1',
parentPath: 'parent-path/new-name',
},
},
{
type: 'renameEntry',
payload: {
path: 'test',
name: 'new-name',
entryPath: 'tree-2',
parentPath: 'parent-path/new-name',
},
},
{ type: 'triggerFilesChange' },
],
done,
);
});
});
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 += '';
});
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();
});
});
});
});
});