Commit 8cdd6dcc authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '39498-part-4' into 'master'

!21542 Part 4: Check for file deleted and readded when getting file data

See merge request gitlab-org/gitlab!21680
parents 15889e4a 727d9973
...@@ -61,8 +61,10 @@ export const getFileData = ( ...@@ -61,8 +61,10 @@ export const getFileData = (
{ path, makeFileActive = true, openFile = makeFileActive }, { path, makeFileActive = true, openFile = makeFileActive },
) => { ) => {
const file = state.entries[path]; const file = state.entries[path];
const fileDeletedAndReadded = getters.isFileDeletedAndReadded(path);
if (file.raw || (file.tempFile && !file.prevPath)) return Promise.resolve(); if (file.raw || (file.tempFile && !file.prevPath && !fileDeletedAndReadded))
return Promise.resolve();
commit(types.TOGGLE_LOADING, { entry: file }); commit(types.TOGGLE_LOADING, { entry: file });
...@@ -102,11 +104,16 @@ export const setFileMrChange = ({ commit }, { file, mrChange }) => { ...@@ -102,11 +104,16 @@ export const setFileMrChange = ({ commit }, { file, mrChange }) => {
export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) => { export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) => {
const file = state.entries[path]; const file = state.entries[path];
const stagedFile = state.stagedFiles.find(f => f.path === path);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const fileDeletedAndReadded = getters.isFileDeletedAndReadded(path);
service service
.getRawFileData(file) .getRawFileData(fileDeletedAndReadded ? stagedFile : file)
.then(raw => { .then(raw => {
if (!(file.tempFile && !file.prevPath)) commit(types.SET_FILE_RAW_DATA, { file, raw }); if (!(file.tempFile && !file.prevPath && !fileDeletedAndReadded))
commit(types.SET_FILE_RAW_DATA, { file, raw, fileDeletedAndReadded });
if (file.mrChange && file.mrChange.new_file === false) { if (file.mrChange && file.mrChange.new_file === false) {
const baseSha = const baseSha =
(getters.currentMergeRequest && getters.currentMergeRequest.baseCommitSha) || ''; (getters.currentMergeRequest && getters.currentMergeRequest.baseCommitSha) || '';
...@@ -151,7 +158,7 @@ export const changeFileContent = ({ commit, dispatch, state }, { path, content } ...@@ -151,7 +158,7 @@ export const changeFileContent = ({ commit, dispatch, state }, { path, content }
if (file.changed && indexOfChangedFile === -1) { if (file.changed && indexOfChangedFile === -1) {
commit(types.ADD_FILE_TO_CHANGED, path); commit(types.ADD_FILE_TO_CHANGED, path);
} else if (!file.changed && indexOfChangedFile !== -1) { } else if (!file.changed && !file.tempFile && indexOfChangedFile !== -1) {
commit(types.REMOVE_FILE_FROM_CHANGED, path); commit(types.REMOVE_FILE_FROM_CHANGED, path);
} }
......
...@@ -54,27 +54,29 @@ export default { ...@@ -54,27 +54,29 @@ export default {
} }
}); });
}, },
[types.SET_FILE_RAW_DATA](state, { file, raw }) { [types.SET_FILE_RAW_DATA](state, { file, raw, fileDeletedAndReadded = false }) {
const openPendingFile = state.openFiles.find( const openPendingFile = state.openFiles.find(
f => f.path === file.path && f.pending && !(f.tempFile && !f.prevPath), f =>
f.path === file.path && f.pending && !(f.tempFile && !f.prevPath && !fileDeletedAndReadded),
); );
const stagedFile = state.stagedFiles.find(f => f.path === file.path);
if (file.tempFile && file.content === '') { if (file.tempFile && file.content === '' && !fileDeletedAndReadded) {
Object.assign(state.entries[file.path], { Object.assign(state.entries[file.path], { content: raw });
content: raw, } else if (fileDeletedAndReadded) {
}); Object.assign(stagedFile, { raw });
} else { } else {
Object.assign(state.entries[file.path], { Object.assign(state.entries[file.path], { raw });
raw,
});
} }
if (!openPendingFile) return; if (!openPendingFile) return;
if (!openPendingFile.tempFile) { if (!openPendingFile.tempFile) {
openPendingFile.raw = raw; openPendingFile.raw = raw;
} else if (openPendingFile.tempFile) { } else if (openPendingFile.tempFile && !fileDeletedAndReadded) {
openPendingFile.content = raw; openPendingFile.content = raw;
} else if (fileDeletedAndReadded) {
Object.assign(stagedFile, { raw });
} }
}, },
[types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) { [types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) {
......
---
title: "Web IDE: Fix Incorrect diff of deletion and addition of the same file"
merge_request: 21680
author:
type: fixed
...@@ -202,6 +202,53 @@ describe('IDE store file actions', () => { ...@@ -202,6 +202,53 @@ describe('IDE store file actions', () => {
}; };
}); });
describe('call to service', () => {
const callExpectation = serviceCalled => {
store.dispatch('getFileData', { path: localFile.path });
if (serviceCalled) {
expect(service.getFileData).toHaveBeenCalled();
} else {
expect(service.getFileData).not.toHaveBeenCalled();
}
};
beforeEach(() => {
service.getFileData.mockImplementation(() => new Promise(() => {}));
});
it("isn't called if file.raw exists", () => {
localFile.raw = 'raw data';
callExpectation(false);
});
it("isn't called if file is a tempFile", () => {
localFile.raw = '';
localFile.tempFile = true;
callExpectation(false);
});
it('is called if file is a tempFile but also renamed', () => {
localFile.raw = '';
localFile.tempFile = true;
localFile.prevPath = 'old_path';
callExpectation(true);
});
it('is called if tempFile but file was deleted and readded', () => {
localFile.raw = '';
localFile.tempFile = true;
localFile.prevPath = 'old_path';
store.state.stagedFiles = [{ ...localFile, deleted: true }];
callExpectation(true);
});
});
describe('success', () => { describe('success', () => {
beforeEach(() => { beforeEach(() => {
mock.onGet(`${RELATIVE_URL_ROOT}/test/test/7297abc/${localFile.path}`).replyOnce( mock.onGet(`${RELATIVE_URL_ROOT}/test/test/7297abc/${localFile.path}`).replyOnce(
...@@ -332,10 +379,10 @@ describe('IDE store file actions', () => { ...@@ -332,10 +379,10 @@ describe('IDE store file actions', () => {
mock.onGet(`${RELATIVE_URL_ROOT}/test/test/7297abc/${localFile.path}`).networkError(); mock.onGet(`${RELATIVE_URL_ROOT}/test/test/7297abc/${localFile.path}`).networkError();
}); });
it('dispatches error action', done => { it('dispatches error action', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
actions return actions
.getFileData( .getFileData(
{ state: store.state, commit() {}, dispatch, getters: store.getters }, { state: store.state, commit() {}, dispatch, getters: store.getters },
{ path: localFile.path }, { path: localFile.path },
...@@ -350,10 +397,7 @@ describe('IDE store file actions', () => { ...@@ -350,10 +397,7 @@ describe('IDE store file actions', () => {
makeFileActive: true, makeFileActive: true,
}, },
}); });
});
done();
})
.catch(done.fail);
}); });
}); });
}); });
...@@ -446,12 +490,14 @@ describe('IDE store file actions', () => { ...@@ -446,12 +490,14 @@ describe('IDE store file actions', () => {
mock.onGet(/(.*)/).networkError(); mock.onGet(/(.*)/).networkError();
}); });
it('dispatches error action', done => { it('dispatches error action', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
actions return actions
.getRawFileData({ state: store.state, commit() {}, dispatch }, { path: tmpFile.path }) .getRawFileData(
.then(done.fail) { state: store.state, commit() {}, dispatch, getters: store.getters },
{ path: tmpFile.path },
)
.catch(() => { .catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', { expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occurred whilst loading the file content.', text: 'An error occurred whilst loading the file content.',
...@@ -461,8 +507,6 @@ describe('IDE store file actions', () => { ...@@ -461,8 +507,6 @@ describe('IDE store file actions', () => {
path: tmpFile.path, path: tmpFile.path,
}, },
}); });
done();
}); });
}); });
}); });
......
...@@ -11,7 +11,7 @@ describe('IDE store file mutations', () => { ...@@ -11,7 +11,7 @@ describe('IDE store file mutations', () => {
beforeEach(() => { beforeEach(() => {
localStore = createStore(); localStore = createStore();
localState = localStore.state; localState = localStore.state;
localFile = { ...file(), type: 'blob' }; localFile = { ...file('file'), type: 'blob', content: 'original' };
localState.entries[localFile.path] = localFile; localState.entries[localFile.path] = localFile;
}); });
...@@ -139,35 +139,68 @@ describe('IDE store file mutations', () => { ...@@ -139,35 +139,68 @@ describe('IDE store file mutations', () => {
}); });
describe('SET_FILE_RAW_DATA', () => { describe('SET_FILE_RAW_DATA', () => {
it('sets raw data', () => { const callMutationForFile = f => {
mutations.SET_FILE_RAW_DATA(localState, { mutations.SET_FILE_RAW_DATA(localState, {
file: localFile, file: f,
raw: 'testing', raw: 'testing',
fileDeletedAndReadded: localStore.getters.isFileDeletedAndReadded(localFile.path),
}); });
};
it('sets raw data', () => {
callMutationForFile(localFile);
expect(localFile.raw).toBe('testing'); expect(localFile.raw).toBe('testing');
}); });
it('sets raw data to stagedFile if file was deleted and readded', () => {
localState.stagedFiles = [{ ...localFile, deleted: true }];
localFile.tempFile = true;
callMutationForFile(localFile);
expect(localFile.raw).toBeFalsy();
expect(localState.stagedFiles[0].raw).toBe('testing');
});
it("sets raw data to a file's content if tempFile is empty", () => {
localFile.tempFile = true;
localFile.content = '';
callMutationForFile(localFile);
expect(localFile.raw).toBeFalsy();
expect(localFile.content).toBe('testing');
});
it('adds raw data to open pending file', () => { it('adds raw data to open pending file', () => {
localState.openFiles.push({ ...localFile, pending: true }); localState.openFiles.push({ ...localFile, pending: true });
mutations.SET_FILE_RAW_DATA(localState, { callMutationForFile(localFile);
file: localFile,
raw: 'testing',
});
expect(localState.openFiles[0].raw).toBe('testing'); expect(localState.openFiles[0].raw).toBe('testing');
}); });
it('does not add raw data to open pending tempFile file', () => { it('sets raw to content of a renamed tempFile', () => {
localState.openFiles.push({ ...localFile, pending: true, tempFile: true }); localFile.tempFile = true;
localFile.prevPath = 'old_path';
localState.openFiles.push({ ...localFile, pending: true });
mutations.SET_FILE_RAW_DATA(localState, { callMutationForFile(localFile);
file: localFile,
raw: 'testing',
});
expect(localState.openFiles[0].raw).not.toBe('testing'); expect(localState.openFiles[0].raw).not.toBe('testing');
expect(localState.openFiles[0].content).toBe('testing');
});
it('adds raw data to a staged deleted file if unstaged change has a tempFile of the same name', () => {
localFile.tempFile = true;
localState.openFiles.push({ ...localFile, pending: true });
localState.stagedFiles = [{ ...localFile, deleted: true }];
callMutationForFile(localFile);
expect(localFile.raw).toBeFalsy();
expect(localState.stagedFiles[0].raw).toBe('testing');
}); });
}); });
......
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