debian-mirror-gitlab/spec/javascripts/ide/stores/actions/file_spec.js
2019-12-26 22:10:19 +05:30

805 lines
20 KiB
JavaScript

import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores';
import * as actions from '~/ide/stores/actions/file';
import * as types from '~/ide/stores/mutation_types';
import service from '~/ide/services';
import router from '~/ide/ide_router';
import eventHub from '~/ide/eventhub';
import { file, resetStore } from '../../helpers';
import testAction from '../../../helpers/vuex_action_helper';
const RELATIVE_URL_ROOT = '/gitlab';
describe('IDE store file actions', () => {
let mock;
let originalGon;
beforeEach(() => {
mock = new MockAdapter(axios);
originalGon = window.gon;
window.gon = {
...window.gon,
relative_url_root: RELATIVE_URL_ROOT,
};
spyOn(router, 'push');
});
afterEach(() => {
mock.restore();
resetStore(store);
window.gon = originalGon;
});
describe('closeFile', () => {
let localFile;
beforeEach(() => {
localFile = file('testFile');
localFile.active = true;
localFile.opened = true;
localFile.parentTreeUrl = 'parentTreeUrl';
store.state.openFiles.push(localFile);
store.state.entries[localFile.path] = localFile;
});
it('closes open files', done => {
store
.dispatch('closeFile', localFile)
.then(() => {
expect(localFile.opened).toBeFalsy();
expect(localFile.active).toBeFalsy();
expect(store.state.openFiles.length).toBe(0);
done();
})
.catch(done.fail);
});
it('closes file even if file has changes', done => {
store.state.changedFiles.push(localFile);
store
.dispatch('closeFile', localFile)
.then(Vue.nextTick)
.then(() => {
expect(store.state.openFiles.length).toBe(0);
expect(store.state.changedFiles.length).toBe(1);
done();
})
.catch(done.fail);
});
it('closes file & opens next available file', done => {
const f = {
...file('newOpenFile'),
url: '/newOpenFile',
};
store.state.openFiles.push(f);
store.state.entries[f.path] = f;
store
.dispatch('closeFile', localFile)
.then(Vue.nextTick)
.then(() => {
expect(router.push).toHaveBeenCalledWith(`/project${f.url}`);
done();
})
.catch(done.fail);
});
it('removes file if it pending', done => {
store.state.openFiles.push({
...localFile,
pending: true,
});
store
.dispatch('closeFile', localFile)
.then(() => {
expect(store.state.openFiles.length).toBe(0);
done();
})
.catch(done.fail);
});
});
describe('setFileActive', () => {
let localFile;
let scrollToTabSpy;
let oldScrollToTab;
beforeEach(() => {
scrollToTabSpy = jasmine.createSpy('scrollToTab');
oldScrollToTab = store._actions.scrollToTab; // eslint-disable-line
store._actions.scrollToTab = [scrollToTabSpy]; // eslint-disable-line
localFile = file('setThisActive');
store.state.entries[localFile.path] = localFile;
});
afterEach(() => {
store._actions.scrollToTab = oldScrollToTab; // eslint-disable-line
});
it('calls scrollToTab', () => {
const dispatch = jasmine.createSpy();
actions.setFileActive(
{ commit() {}, state: store.state, getters: store.getters, dispatch },
localFile.path,
);
expect(dispatch).toHaveBeenCalledWith('scrollToTab');
});
it('commits SET_FILE_ACTIVE', () => {
const commit = jasmine.createSpy();
actions.setFileActive(
{ commit, state: store.state, getters: store.getters, dispatch() {} },
localFile.path,
);
expect(commit).toHaveBeenCalledWith('SET_FILE_ACTIVE', {
path: localFile.path,
active: true,
});
});
it('sets current active file to not active', () => {
const f = file('newActive');
store.state.entries[f.path] = f;
localFile.active = true;
store.state.openFiles.push(localFile);
const commit = jasmine.createSpy();
actions.setFileActive(
{ commit, state: store.state, getters: store.getters, dispatch() {} },
f.path,
);
expect(commit).toHaveBeenCalledWith('SET_FILE_ACTIVE', {
path: localFile.path,
active: false,
});
});
});
describe('getFileData', () => {
let localFile;
beforeEach(() => {
spyOn(service, 'getFileData').and.callThrough();
localFile = file(`newCreate-${Math.random()}`);
store.state.entries[localFile.path] = localFile;
store.state.currentProjectId = 'test/test';
store.state.currentBranchId = 'master';
store.state.projects['test/test'] = {
branches: {
master: {
commit: {
id: '7297abc',
},
},
},
};
});
describe('success', () => {
beforeEach(() => {
mock.onGet(`${RELATIVE_URL_ROOT}/test/test/7297abc/${localFile.path}`).replyOnce(
200,
{
blame_path: 'blame_path',
commits_path: 'commits_path',
permalink: 'permalink',
raw_path: 'raw_path',
binary: false,
html: '123',
render_error: '',
},
{
'page-title': 'testing getFileData',
},
);
});
it('calls the service', done => {
store
.dispatch('getFileData', { path: localFile.path })
.then(() => {
expect(service.getFileData).toHaveBeenCalledWith(
`${RELATIVE_URL_ROOT}/test/test/7297abc/${localFile.path}`,
);
done();
})
.catch(done.fail);
});
it('sets the file data', done => {
store
.dispatch('getFileData', { path: localFile.path })
.then(() => {
expect(localFile.blamePath).toBe('blame_path');
done();
})
.catch(done.fail);
});
it('sets document title with the branchId', done => {
store
.dispatch('getFileData', { path: localFile.path })
.then(() => {
expect(document.title).toBe(`${localFile.path} · master · test/test · GitLab`);
done();
})
.catch(done.fail);
});
it('sets the file as active', done => {
store
.dispatch('getFileData', { path: localFile.path })
.then(() => {
expect(localFile.active).toBeTruthy();
done();
})
.catch(done.fail);
});
it('sets the file not as active if we pass makeFileActive false', done => {
store
.dispatch('getFileData', { path: localFile.path, makeFileActive: false })
.then(() => {
expect(localFile.active).toBeFalsy();
done();
})
.catch(done.fail);
});
it('adds the file to open files', done => {
store
.dispatch('getFileData', { path: localFile.path })
.then(() => {
expect(store.state.openFiles.length).toBe(1);
expect(store.state.openFiles[0].name).toBe(localFile.name);
done();
})
.catch(done.fail);
});
});
describe('Re-named success', () => {
beforeEach(() => {
localFile = file(`newCreate-${Math.random()}`);
localFile.url = `project/getFileDataURL`;
localFile.prevPath = 'old-dull-file';
localFile.path = 'new-shiny-file';
store.state.entries[localFile.path] = localFile;
mock.onGet(`${RELATIVE_URL_ROOT}/test/test/7297abc/old-dull-file`).replyOnce(
200,
{
blame_path: 'blame_path',
commits_path: 'commits_path',
permalink: 'permalink',
raw_path: 'raw_path',
binary: false,
html: '123',
render_error: '',
},
{
'page-title': 'testing old-dull-file',
},
);
});
it('sets document title considering `prevPath` on a file', done => {
store
.dispatch('getFileData', { path: localFile.path })
.then(() => {
expect(document.title).toBe(`new-shiny-file · master · test/test · GitLab`);
done();
})
.catch(done.fail);
});
});
describe('error', () => {
beforeEach(() => {
mock.onGet(`${RELATIVE_URL_ROOT}/test/test/7297abc/${localFile.path}`).networkError();
});
it('dispatches error action', done => {
const dispatch = jasmine.createSpy('dispatch');
actions
.getFileData(
{ state: store.state, commit() {}, dispatch, getters: store.getters },
{ path: localFile.path },
)
.then(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occurred whilst loading the file.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
path: localFile.path,
makeFileActive: true,
},
});
done();
})
.catch(done.fail);
});
});
});
describe('getRawFileData', () => {
let tmpFile;
beforeEach(() => {
spyOn(service, 'getRawFileData').and.callThrough();
tmpFile = file('tmpFile');
store.state.entries[tmpFile.path] = tmpFile;
});
describe('success', () => {
beforeEach(() => {
mock.onGet(/(.*)/).replyOnce(200, 'raw');
});
it('calls getRawFileData service method', done => {
store
.dispatch('getRawFileData', { path: tmpFile.path })
.then(() => {
expect(service.getRawFileData).toHaveBeenCalledWith(tmpFile);
done();
})
.catch(done.fail);
});
it('updates file raw data', done => {
store
.dispatch('getRawFileData', { path: tmpFile.path })
.then(() => {
expect(tmpFile.raw).toBe('raw');
done();
})
.catch(done.fail);
});
it('calls also getBaseRawFileData service method', done => {
spyOn(service, 'getBaseRawFileData').and.returnValue(Promise.resolve('baseraw'));
store.state.currentProjectId = 'gitlab-org/gitlab-ce';
store.state.currentMergeRequestId = '1';
store.state.projects = {
'gitlab-org/gitlab-ce': {
mergeRequests: {
1: {
baseCommitSha: 'SHA',
},
},
},
};
tmpFile.mrChange = { new_file: false };
store
.dispatch('getRawFileData', { path: tmpFile.path })
.then(() => {
expect(service.getBaseRawFileData).toHaveBeenCalledWith(tmpFile, 'SHA');
expect(tmpFile.baseRaw).toBe('baseraw');
done();
})
.catch(done.fail);
});
});
describe('return JSON', () => {
beforeEach(() => {
mock.onGet(/(.*)/).replyOnce(200, JSON.stringify({ test: '123' }));
});
it('does not parse returned JSON', done => {
store
.dispatch('getRawFileData', { path: tmpFile.path })
.then(() => {
expect(tmpFile.raw).toEqual('{"test":"123"}');
done();
})
.catch(done.fail);
});
});
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 })
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occurred whilst loading the file content.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
path: tmpFile.path,
},
});
done();
});
});
});
});
describe('changeFileContent', () => {
let tmpFile;
beforeEach(() => {
tmpFile = file('tmpFile');
tmpFile.content = '\n';
tmpFile.raw = '\n';
store.state.entries[tmpFile.path] = tmpFile;
});
it('updates file content', done => {
store
.dispatch('changeFileContent', {
path: tmpFile.path,
content: 'content\n',
})
.then(() => {
expect(tmpFile.content).toBe('content\n');
done();
})
.catch(done.fail);
});
it('adds a newline to the end of the file if it doesnt already exist', done => {
store
.dispatch('changeFileContent', {
path: tmpFile.path,
content: 'content',
})
.then(() => {
expect(tmpFile.content).toBe('content\n');
done();
})
.catch(done.fail);
});
it('adds file into changedFiles array', done => {
store
.dispatch('changeFileContent', {
path: tmpFile.path,
content: 'content',
})
.then(() => {
expect(store.state.changedFiles.length).toBe(1);
done();
})
.catch(done.fail);
});
it('adds file once into changedFiles array', done => {
store
.dispatch('changeFileContent', {
path: tmpFile.path,
content: 'content',
})
.then(() =>
store.dispatch('changeFileContent', {
path: tmpFile.path,
content: 'content 123',
}),
)
.then(() => {
expect(store.state.changedFiles.length).toBe(1);
done();
})
.catch(done.fail);
});
it('removes file from changedFiles array if not changed', done => {
store
.dispatch('changeFileContent', {
path: tmpFile.path,
content: 'content\n',
})
.then(() =>
store.dispatch('changeFileContent', {
path: tmpFile.path,
content: '\n',
}),
)
.then(() => {
expect(store.state.changedFiles.length).toBe(0);
done();
})
.catch(done.fail);
});
it('bursts unused seal', done => {
store
.dispatch('changeFileContent', {
path: tmpFile.path,
content: 'content',
})
.then(() => {
expect(store.state.unusedSeal).toBe(false);
done();
})
.catch(done.fail);
});
});
describe('discardFileChanges', () => {
let tmpFile;
beforeEach(() => {
spyOn(eventHub, '$on');
spyOn(eventHub, '$emit');
tmpFile = file();
tmpFile.content = 'testing';
store.state.changedFiles.push(tmpFile);
store.state.entries[tmpFile.path] = tmpFile;
});
it('resets file content', done => {
store
.dispatch('discardFileChanges', tmpFile.path)
.then(() => {
expect(tmpFile.content).not.toBe('testing');
done();
})
.catch(done.fail);
});
it('removes file from changedFiles array', done => {
store
.dispatch('discardFileChanges', tmpFile.path)
.then(() => {
expect(store.state.changedFiles.length).toBe(0);
done();
})
.catch(done.fail);
});
it('closes temp file', done => {
tmpFile.tempFile = true;
tmpFile.opened = true;
store
.dispatch('discardFileChanges', tmpFile.path)
.then(() => {
expect(tmpFile.opened).toBeFalsy();
done();
})
.catch(done.fail);
});
it('does not re-open a closed temp file', done => {
tmpFile.tempFile = true;
expect(tmpFile.opened).toBeFalsy();
store
.dispatch('discardFileChanges', tmpFile.path)
.then(() => {
expect(tmpFile.opened).toBeFalsy();
done();
})
.catch(done.fail);
});
it('pushes route for active file', done => {
tmpFile.active = true;
store.state.openFiles.push(tmpFile);
store
.dispatch('discardFileChanges', tmpFile.path)
.then(() => {
expect(router.push).toHaveBeenCalledWith(`/project${tmpFile.url}`);
done();
})
.catch(done.fail);
});
it('emits eventHub event to dispose cached model', done => {
store
.dispatch('discardFileChanges', tmpFile.path)
.then(() => {
expect(eventHub.$emit).toHaveBeenCalled();
done();
})
.catch(done.fail);
});
});
describe('stageChange', () => {
it('calls STAGE_CHANGE with file path', done => {
testAction(
actions.stageChange,
'path',
store.state,
[
{ type: types.STAGE_CHANGE, payload: 'path' },
{ type: types.SET_LAST_COMMIT_MSG, payload: '' },
],
[],
done,
);
});
});
describe('unstageChange', () => {
it('calls UNSTAGE_CHANGE with file path', done => {
testAction(
actions.unstageChange,
'path',
store.state,
[{ type: types.UNSTAGE_CHANGE, payload: 'path' }],
[],
done,
);
});
});
describe('openPendingTab', () => {
let f;
beforeEach(() => {
f = {
...file(),
projectId: '123',
};
store.state.entries[f.path] = f;
});
it('makes file pending in openFiles', done => {
store
.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' })
.then(() => {
expect(store.state.openFiles[0].pending).toBe(true);
})
.then(done)
.catch(done.fail);
});
it('returns true when opened', done => {
store
.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' })
.then(added => {
expect(added).toBe(true);
})
.then(done)
.catch(done.fail);
});
it('returns false when already opened', done => {
store.state.openFiles.push({
...f,
active: true,
key: `pending-${f.key}`,
});
store
.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' })
.then(added => {
expect(added).toBe(false);
})
.then(done)
.catch(done.fail);
});
it('pushes router URL when added', done => {
store.state.currentBranchId = 'master';
store
.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' })
.then(() => {
expect(router.push).toHaveBeenCalledWith('/project/123/tree/master/');
})
.then(done)
.catch(done.fail);
});
});
describe('removePendingTab', () => {
let f;
beforeEach(() => {
spyOn(eventHub, '$emit');
f = {
...file('pendingFile'),
pending: true,
};
});
it('removes pending file from open files', done => {
store.state.openFiles.push(f);
store
.dispatch('removePendingTab', f)
.then(() => {
expect(store.state.openFiles.length).toBe(0);
})
.then(done)
.catch(done.fail);
});
it('emits event to dispose model', done => {
store
.dispatch('removePendingTab', f)
.then(() => {
expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.dispose.${f.key}`);
})
.then(done)
.catch(done.fail);
});
});
describe('triggerFilesChange', () => {
beforeEach(() => {
spyOn(eventHub, '$emit');
});
it('emits event that files have changed', done => {
store
.dispatch('triggerFilesChange')
.then(() => {
expect(eventHub.$emit).toHaveBeenCalledWith('ide.files.change');
})
.then(done)
.catch(done.fail);
});
});
});