Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/diffs')
-rw-r--r--spec/frontend/diffs/components/app_spec.js208
-rw-r--r--spec/frontend/diffs/components/collapsed_files_warning_spec.js88
-rw-r--r--spec/frontend/diffs/components/commit_item_spec.js3
-rw-r--r--spec/frontend/diffs/components/compare_versions_spec.js3
-rw-r--r--spec/frontend/diffs/components/diff_content_spec.js28
-rw-r--r--spec/frontend/diffs/components/diff_discussions_spec.js4
-rw-r--r--spec/frontend/diffs/components/diff_expansion_cell_spec.js19
-rw-r--r--spec/frontend/diffs/components/diff_file_header_spec.js19
-rw-r--r--spec/frontend/diffs/components/diff_file_row_spec.js30
-rw-r--r--spec/frontend/diffs/components/diff_file_spec.js44
-rw-r--r--spec/frontend/diffs/components/diff_stats_spec.js4
-rw-r--r--spec/frontend/diffs/components/image_diff_overlay_spec.js4
-rw-r--r--spec/frontend/diffs/components/inline_diff_expansion_row_spec.js5
-rw-r--r--spec/frontend/diffs/components/inline_diff_table_row_spec.js355
-rw-r--r--spec/frontend/diffs/components/inline_diff_view_spec.js4
-rw-r--r--spec/frontend/diffs/components/merge_conflict_warning_spec.js77
-rw-r--r--spec/frontend/diffs/components/no_changes_spec.js2
-rw-r--r--spec/frontend/diffs/components/parallel_diff_table_row_spec.js259
-rw-r--r--spec/frontend/diffs/components/parallel_diff_view_spec.js40
-rw-r--r--spec/frontend/diffs/components/settings_dropdown_spec.js42
-rw-r--r--spec/frontend/diffs/components/tree_list_spec.js115
-rw-r--r--spec/frontend/diffs/mock_data/diff_file.js111
-rw-r--r--spec/frontend/diffs/mock_data/diff_metadata.js3
-rw-r--r--spec/frontend/diffs/store/actions_spec.js207
-rw-r--r--spec/frontend/diffs/store/mutations_spec.js83
-rw-r--r--spec/frontend/diffs/store/utils_spec.js55
26 files changed, 1191 insertions, 621 deletions
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index ac046ddc203..cd3a6aa0e28 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlPagination } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'spec/test_constants';
import Mousetrap from 'mousetrap';
@@ -9,6 +9,7 @@ import NoChanges from '~/diffs/components/no_changes.vue';
import DiffFile from '~/diffs/components/diff_file.vue';
import CompareVersions from '~/diffs/components/compare_versions.vue';
import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue';
+import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
import CommitWidget from '~/diffs/components/commit_widget.vue';
import TreeList from '~/diffs/components/tree_list.vue';
import { INLINE_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE } from '~/diffs/constants';
@@ -22,6 +23,10 @@ const TEST_ENDPOINT = `${TEST_HOST}/diff/endpoint`;
const COMMIT_URL = '[BASE URL]/OLD';
const UPDATED_COMMIT_URL = '[BASE URL]/NEW';
+function getCollapsedFilesWarning(wrapper) {
+ return wrapper.find(CollapsedFilesWarning);
+}
+
describe('diffs/components/app', () => {
const oldMrTabs = window.mrTabs;
let store;
@@ -108,7 +113,6 @@ describe('diffs/components/app', () => {
};
jest.spyOn(window, 'requestIdleCallback').mockImplementation(fn => fn());
createComponent();
- jest.spyOn(wrapper.vm, 'fetchDiffFiles').mockImplementation(fetchResolver);
jest.spyOn(wrapper.vm, 'fetchDiffFilesMeta').mockImplementation(fetchResolver);
jest.spyOn(wrapper.vm, 'fetchDiffFilesBatch').mockImplementation(fetchResolver);
jest.spyOn(wrapper.vm, 'fetchCoverageFiles').mockImplementation(fetchResolver);
@@ -139,37 +143,21 @@ describe('diffs/components/app', () => {
parallel_diff_lines: ['line'],
};
- function expectFetchToOccur({
- vueInstance,
- done = () => {},
- batch = false,
- existingFiles = 1,
- } = {}) {
+ function expectFetchToOccur({ vueInstance, done = () => {}, existingFiles = 1 } = {}) {
vueInstance.$nextTick(() => {
expect(vueInstance.diffFiles.length).toEqual(existingFiles);
-
- if (!batch) {
- expect(vueInstance.fetchDiffFiles).toHaveBeenCalled();
- expect(vueInstance.fetchDiffFilesBatch).not.toHaveBeenCalled();
- } else {
- expect(vueInstance.fetchDiffFiles).not.toHaveBeenCalled();
- expect(vueInstance.fetchDiffFilesBatch).toHaveBeenCalled();
- }
+ expect(vueInstance.fetchDiffFilesBatch).toHaveBeenCalled();
done();
});
}
- beforeEach(() => {
- wrapper.vm.glFeatures.singleMrDiffView = true;
- });
-
it('fetches diffs if it has none', done => {
wrapper.vm.isLatestVersion = () => false;
store.state.diffs.diffViewType = getOppositeViewType(wrapper.vm.diffViewType);
- expectFetchToOccur({ vueInstance: wrapper.vm, batch: false, existingFiles: 0, done });
+ expectFetchToOccur({ vueInstance: wrapper.vm, existingFiles: 0, done });
});
it('fetches diffs if it has both view styles, but no lines in either', done => {
@@ -200,89 +188,46 @@ describe('diffs/components/app', () => {
});
it('fetches batch diffs if it has none', done => {
- wrapper.vm.glFeatures.diffsBatchLoad = true;
-
store.state.diffs.diffViewType = getOppositeViewType(wrapper.vm.diffViewType);
- expectFetchToOccur({ vueInstance: wrapper.vm, batch: true, existingFiles: 0, done });
+ expectFetchToOccur({ vueInstance: wrapper.vm, existingFiles: 0, done });
});
it('fetches batch diffs if it has both view styles, but no lines in either', done => {
- wrapper.vm.glFeatures.diffsBatchLoad = true;
-
store.state.diffs.diffFiles.push(noLinesDiff);
store.state.diffs.diffViewType = getOppositeViewType(wrapper.vm.diffViewType);
- expectFetchToOccur({ vueInstance: wrapper.vm, batch: true, done });
+ expectFetchToOccur({ vueInstance: wrapper.vm, done });
});
it('fetches batch diffs if it only has inline view style', done => {
- wrapper.vm.glFeatures.diffsBatchLoad = true;
-
store.state.diffs.diffFiles.push(inlineLinesDiff);
store.state.diffs.diffViewType = getOppositeViewType(wrapper.vm.diffViewType);
- expectFetchToOccur({ vueInstance: wrapper.vm, batch: true, done });
+ expectFetchToOccur({ vueInstance: wrapper.vm, done });
});
it('fetches batch diffs if it only has parallel view style', done => {
- wrapper.vm.glFeatures.diffsBatchLoad = true;
-
store.state.diffs.diffFiles.push(parallelLinesDiff);
store.state.diffs.diffViewType = getOppositeViewType(wrapper.vm.diffViewType);
- expectFetchToOccur({ vueInstance: wrapper.vm, batch: true, done });
- });
-
- it('does not fetch diffs if it has already fetched both styles of diff', () => {
- wrapper.vm.glFeatures.diffsBatchLoad = false;
-
- store.state.diffs.diffFiles.push(fullDiff);
- store.state.diffs.diffViewType = getOppositeViewType(wrapper.vm.diffViewType);
-
- expect(wrapper.vm.diffFiles.length).toEqual(1);
- expect(wrapper.vm.fetchDiffFiles).not.toHaveBeenCalled();
- expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled();
+ expectFetchToOccur({ vueInstance: wrapper.vm, done });
});
it('does not fetch batch diffs if it has already fetched both styles of diff', () => {
- wrapper.vm.glFeatures.diffsBatchLoad = true;
-
store.state.diffs.diffFiles.push(fullDiff);
store.state.diffs.diffViewType = getOppositeViewType(wrapper.vm.diffViewType);
expect(wrapper.vm.diffFiles.length).toEqual(1);
- expect(wrapper.vm.fetchDiffFiles).not.toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled();
});
});
- it('calls fetchDiffFiles if diffsBatchLoad is not enabled', done => {
- expect(wrapper.vm.diffFilesLength).toEqual(0);
- wrapper.vm.glFeatures.diffsBatchLoad = false;
- wrapper.vm.fetchData(false);
-
- expect(wrapper.vm.fetchDiffFiles).toHaveBeenCalled();
- setImmediate(() => {
- expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
- expect(wrapper.vm.fetchDiffFilesMeta).not.toHaveBeenCalled();
- expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled();
- expect(wrapper.vm.fetchCoverageFiles).toHaveBeenCalled();
- expect(wrapper.vm.unwatchDiscussions).toHaveBeenCalled();
- expect(wrapper.vm.diffFilesLength).toEqual(100);
- expect(wrapper.vm.unwatchRetrievingBatches).toHaveBeenCalled();
-
- done();
- });
- });
-
it('calls batch methods if diffsBatchLoad is enabled, and not latest version', done => {
expect(wrapper.vm.diffFilesLength).toEqual(0);
- wrapper.vm.glFeatures.diffsBatchLoad = true;
wrapper.vm.isLatestVersion = () => false;
wrapper.vm.fetchData(false);
- expect(wrapper.vm.fetchDiffFiles).not.toHaveBeenCalled();
setImmediate(() => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled();
@@ -297,10 +242,8 @@ describe('diffs/components/app', () => {
it('calls batch methods if diffsBatchLoad is enabled, and latest version', done => {
expect(wrapper.vm.diffFilesLength).toEqual(0);
- wrapper.vm.glFeatures.diffsBatchLoad = true;
wrapper.vm.fetchData(false);
- expect(wrapper.vm.fetchDiffFiles).not.toHaveBeenCalled();
setImmediate(() => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled();
@@ -320,7 +263,7 @@ describe('diffs/components/app', () => {
state.diffs.isParallelView = false;
});
- expect(wrapper.contains('.container-limited.limit-container-width')).toBe(true);
+ expect(wrapper.find('.container-limited.limit-container-width').exists()).toBe(true);
});
it('does not add container-limiting classes when showFileTree is false with inline diffs', () => {
@@ -329,7 +272,7 @@ describe('diffs/components/app', () => {
state.diffs.isParallelView = false;
});
- expect(wrapper.contains('.container-limited.limit-container-width')).toBe(false);
+ expect(wrapper.find('.container-limited.limit-container-width').exists()).toBe(false);
});
it('does not add container-limiting classes when isFluidLayout', () => {
@@ -337,7 +280,7 @@ describe('diffs/components/app', () => {
state.diffs.isParallelView = false;
});
- expect(wrapper.contains('.container-limited.limit-container-width')).toBe(false);
+ expect(wrapper.find('.container-limited.limit-container-width').exists()).toBe(false);
});
it('displays loading icon on loading', () => {
@@ -345,7 +288,7 @@ describe('diffs/components/app', () => {
state.diffs.isLoading = true;
});
- expect(wrapper.contains(GlLoadingIcon)).toBe(true);
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
it('displays loading icon on batch loading', () => {
@@ -353,20 +296,20 @@ describe('diffs/components/app', () => {
state.diffs.isBatchLoading = true;
});
- expect(wrapper.contains(GlLoadingIcon)).toBe(true);
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
it('displays diffs container when not loading', () => {
createComponent();
- expect(wrapper.contains(GlLoadingIcon)).toBe(false);
- expect(wrapper.contains('#diffs')).toBe(true);
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.find('#diffs').exists()).toBe(true);
});
it('does not show commit info', () => {
createComponent();
- expect(wrapper.contains('.blob-commit-info')).toBe(false);
+ expect(wrapper.find('.blob-commit-info').exists()).toBe(false);
});
describe('row highlighting', () => {
@@ -442,7 +385,7 @@ describe('diffs/components/app', () => {
it('renders empty state when no diff files exist', () => {
createComponent();
- expect(wrapper.contains(NoChanges)).toBe(true);
+ expect(wrapper.find(NoChanges).exists()).toBe(true);
});
it('does not render empty state when diff files exist', () => {
@@ -452,7 +395,7 @@ describe('diffs/components/app', () => {
});
});
- expect(wrapper.contains(NoChanges)).toBe(false);
+ expect(wrapper.find(NoChanges).exists()).toBe(false);
expect(wrapper.findAll(DiffFile).length).toBe(1);
});
@@ -462,7 +405,7 @@ describe('diffs/components/app', () => {
state.diffs.mergeRequestDiff = mergeRequestDiff;
});
- expect(wrapper.contains(NoChanges)).toBe(false);
+ expect(wrapper.find(NoChanges).exists()).toBe(false);
});
});
@@ -722,7 +665,7 @@ describe('diffs/components/app', () => {
state.diffs.mergeRequestDiff = mergeRequestDiff;
});
- expect(wrapper.contains(CompareVersions)).toBe(true);
+ expect(wrapper.find(CompareVersions).exists()).toBe(true);
expect(wrapper.find(CompareVersions).props()).toEqual(
expect.objectContaining({
mergeRequestDiffs: diffsMockData,
@@ -730,24 +673,51 @@ describe('diffs/components/app', () => {
);
});
- it('should render hidden files warning if render overflow warning is present', () => {
- createComponent({}, ({ state }) => {
- state.diffs.renderOverflowWarning = true;
- state.diffs.realSize = '5';
- state.diffs.plainDiffPath = 'plain diff path';
- state.diffs.emailPatchPath = 'email patch path';
- state.diffs.size = 1;
+ describe('warnings', () => {
+ describe('hidden files', () => {
+ it('should render hidden files warning if render overflow warning is present', () => {
+ createComponent({}, ({ state }) => {
+ state.diffs.renderOverflowWarning = true;
+ state.diffs.realSize = '5';
+ state.diffs.plainDiffPath = 'plain diff path';
+ state.diffs.emailPatchPath = 'email patch path';
+ state.diffs.size = 1;
+ });
+
+ expect(wrapper.find(HiddenFilesWarning).exists()).toBe(true);
+ expect(wrapper.find(HiddenFilesWarning).props()).toEqual(
+ expect.objectContaining({
+ total: '5',
+ plainDiffPath: 'plain diff path',
+ emailPatchPath: 'email patch path',
+ visible: 1,
+ }),
+ );
+ });
});
- expect(wrapper.contains(HiddenFilesWarning)).toBe(true);
- expect(wrapper.find(HiddenFilesWarning).props()).toEqual(
- expect.objectContaining({
- total: '5',
- plainDiffPath: 'plain diff path',
- emailPatchPath: 'email patch path',
- visible: 1,
- }),
- );
+ describe('collapsed files', () => {
+ it('should render the collapsed files warning if there are any collapsed files', () => {
+ createComponent({}, ({ state }) => {
+ state.diffs.diffFiles = [{ viewer: { collapsed: true } }];
+ });
+
+ expect(getCollapsedFilesWarning(wrapper).exists()).toBe(true);
+ });
+
+ it('should not render the collapsed files warning if the user has dismissed the alert already', async () => {
+ createComponent({}, ({ state }) => {
+ state.diffs.diffFiles = [{ viewer: { collapsed: true } }];
+ });
+
+ expect(getCollapsedFilesWarning(wrapper).exists()).toBe(true);
+
+ wrapper.vm.collapsedWarningDismissed = true;
+ await wrapper.vm.$nextTick();
+
+ expect(getCollapsedFilesWarning(wrapper).exists()).toBe(false);
+ });
+ });
});
it('should display commit widget if store has a commit', () => {
@@ -757,7 +727,7 @@ describe('diffs/components/app', () => {
};
});
- expect(wrapper.contains(CommitWidget)).toBe(true);
+ expect(wrapper.find(CommitWidget).exists()).toBe(true);
});
it('should display diff file if there are diff files', () => {
@@ -765,7 +735,7 @@ describe('diffs/components/app', () => {
state.diffs.diffFiles.push({ sha: '123' });
});
- expect(wrapper.contains(DiffFile)).toBe(true);
+ expect(wrapper.find(DiffFile).exists()).toBe(true);
});
it('should render tree list', () => {
@@ -843,13 +813,16 @@ describe('diffs/components/app', () => {
});
describe('pagination', () => {
+ const fileByFileNav = () => wrapper.find('[data-testid="file-by-file-navigation"]');
+ const paginator = () => fileByFileNav().find(GlPagination);
+
it('sets previous button as disabled', () => {
createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
});
- expect(wrapper.find('[data-testid="singleFilePrevious"]').props('disabled')).toBe(true);
- expect(wrapper.find('[data-testid="singleFileNext"]').props('disabled')).toBe(false);
+ expect(paginator().attributes('prevpage')).toBe(undefined);
+ expect(paginator().attributes('nextpage')).toBe('2');
});
it('sets next button as disabled', () => {
@@ -858,17 +831,26 @@ describe('diffs/components/app', () => {
state.diffs.currentDiffFileId = '312';
});
- expect(wrapper.find('[data-testid="singleFilePrevious"]').props('disabled')).toBe(false);
- expect(wrapper.find('[data-testid="singleFileNext"]').props('disabled')).toBe(true);
+ expect(paginator().attributes('prevpage')).toBe('1');
+ expect(paginator().attributes('nextpage')).toBe(undefined);
+ });
+
+ it("doesn't display when there's fewer than 2 files", () => {
+ createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
+ state.diffs.diffFiles.push({ file_hash: '123' });
+ state.diffs.currentDiffFileId = '123';
+ });
+
+ expect(fileByFileNav().exists()).toBe(false);
});
it.each`
- currentDiffFileId | button | index
- ${'123'} | ${'singleFileNext'} | ${1}
- ${'312'} | ${'singleFilePrevious'} | ${0}
+ currentDiffFileId | targetFile
+ ${'123'} | ${2}
+ ${'312'} | ${1}
`(
- 'it calls navigateToDiffFileIndex with $index when $button is clicked',
- ({ currentDiffFileId, button, index }) => {
+ 'it calls navigateToDiffFileIndex with $index when $link is clicked',
+ async ({ currentDiffFileId, targetFile }) => {
createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
state.diffs.currentDiffFileId = currentDiffFileId;
@@ -876,11 +858,11 @@ describe('diffs/components/app', () => {
jest.spyOn(wrapper.vm, 'navigateToDiffFileIndex');
- wrapper.find(`[data-testid="${button}"]`).vm.$emit('click');
+ paginator().vm.$emit('input', targetFile);
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.navigateToDiffFileIndex).toHaveBeenCalledWith(index);
- });
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.navigateToDiffFileIndex).toHaveBeenCalledWith(targetFile - 1);
},
);
});
diff --git a/spec/frontend/diffs/components/collapsed_files_warning_spec.js b/spec/frontend/diffs/components/collapsed_files_warning_spec.js
new file mode 100644
index 00000000000..670eab5472f
--- /dev/null
+++ b/spec/frontend/diffs/components/collapsed_files_warning_spec.js
@@ -0,0 +1,88 @@
+import Vuex from 'vuex';
+import { shallowMount, mount, createLocalVue } from '@vue/test-utils';
+import createStore from '~/diffs/store/modules';
+import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
+import { CENTERED_LIMITED_CONTAINER_CLASSES } from '~/diffs/constants';
+
+const propsData = {
+ limited: true,
+ mergeable: true,
+ resolutionPath: 'a-path',
+};
+const limitedClasses = CENTERED_LIMITED_CONTAINER_CLASSES.split(' ');
+
+describe('CollapsedFilesWarning', () => {
+ const localVue = createLocalVue();
+ let store;
+ let wrapper;
+
+ localVue.use(Vuex);
+
+ const getAlertActionButton = () =>
+ wrapper.find(CollapsedFilesWarning).find('button.gl-alert-action:first-child');
+ const getAlertCloseButton = () => wrapper.find(CollapsedFilesWarning).find('button');
+
+ const createComponent = (props = {}, { full } = { full: false }) => {
+ const mounter = full ? mount : shallowMount;
+ store = new Vuex.Store({
+ modules: {
+ diffs: createStore(),
+ },
+ });
+
+ wrapper = mounter(CollapsedFilesWarning, {
+ propsData: { ...propsData, ...props },
+ localVue,
+ store,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it.each`
+ limited | containerClasses
+ ${true} | ${limitedClasses}
+ ${false} | ${[]}
+ `(
+ 'has the correct container classes when limited is $limited',
+ ({ limited, containerClasses }) => {
+ createComponent({ limited });
+
+ expect(wrapper.classes()).toEqual(containerClasses);
+ },
+ );
+
+ it.each`
+ present | dismissed
+ ${false} | ${true}
+ ${true} | ${false}
+ `('toggles the alert when dismissed is $dismissed', ({ present, dismissed }) => {
+ createComponent({ dismissed });
+
+ expect(wrapper.find('[data-testid="root"]').exists()).toBe(present);
+ });
+
+ it('dismisses the component when the alert "x" is clicked', async () => {
+ createComponent({}, { full: true });
+
+ expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
+
+ getAlertCloseButton().element.click();
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find('[data-testid="root"]').exists()).toBe(false);
+ });
+
+ it('triggers the expandAllFiles action when the alert action button is clicked', () => {
+ createComponent({}, { full: true });
+
+ jest.spyOn(wrapper.vm.$store, 'dispatch').mockReturnValue(undefined);
+
+ getAlertActionButton().vm.$emit('click');
+
+ expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith('diffs/expandAllFiles', undefined);
+ });
+});
diff --git a/spec/frontend/diffs/components/commit_item_spec.js b/spec/frontend/diffs/components/commit_item_spec.js
index 0df951d43a7..c48445790f7 100644
--- a/spec/frontend/diffs/components/commit_item_spec.js
+++ b/spec/frontend/diffs/components/commit_item_spec.js
@@ -24,8 +24,7 @@ describe('diffs/components/commit_item', () => {
const getTitleElement = () => wrapper.find('.commit-row-message.item-title');
const getDescElement = () => wrapper.find('pre.commit-row-description');
- const getDescExpandElement = () =>
- wrapper.find('.commit-content .text-expander.js-toggle-button');
+ const getDescExpandElement = () => wrapper.find('.commit-content .js-toggle-button');
const getShaElement = () => wrapper.find('.commit-sha-group');
const getAvatarElement = () => wrapper.find('.user-avatar-link');
const getCommitterElement = () => wrapper.find('.committer');
diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js
index 7fdbc791589..b3dfc71260c 100644
--- a/spec/frontend/diffs/components/compare_versions_spec.js
+++ b/spec/frontend/diffs/components/compare_versions_spec.js
@@ -2,7 +2,6 @@ import { trimText } from 'helpers/text_helper';
import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import CompareVersionsComponent from '~/diffs/components/compare_versions.vue';
-import Icon from '~/vue_shared/components/icon.vue';
import { createStore } from '~/mr_notes/stores';
import diffsMockData from '../mock_data/merge_request_diffs';
import getDiffWithCommit from '../mock_data/diff_with_commit';
@@ -51,7 +50,7 @@ describe('CompareVersions', () => {
expect(treeListBtn.exists()).toBe(true);
expect(treeListBtn.attributes('title')).toBe('Hide file browser');
- expect(treeListBtn.find(Icon).props('name')).toBe('file-tree');
+ expect(treeListBtn.props('icon')).toBe('file-tree');
});
it('should render comparison dropdowns with correct values', () => {
diff --git a/spec/frontend/diffs/components/diff_content_spec.js b/spec/frontend/diffs/components/diff_content_spec.js
index b78895f9e55..6d0120d888e 100644
--- a/spec/frontend/diffs/components/diff_content_spec.js
+++ b/spec/frontend/diffs/components/diff_content_spec.js
@@ -177,23 +177,19 @@ describe('DiffContent', () => {
});
wrapper.find(NoteForm).vm.$emit('handleFormUpdate', noteStub);
- expect(saveDiffDiscussionMock).toHaveBeenCalledWith(
- expect.any(Object),
- {
- note: noteStub,
- formData: {
- noteableData: expect.any(Object),
- diffFile: currentDiffFile,
- positionType: IMAGE_DIFF_POSITION_TYPE,
- x: undefined,
- y: undefined,
- width: undefined,
- height: undefined,
- noteableType: undefined,
- },
+ expect(saveDiffDiscussionMock).toHaveBeenCalledWith(expect.any(Object), {
+ note: noteStub,
+ formData: {
+ noteableData: expect.any(Object),
+ diffFile: currentDiffFile,
+ positionType: IMAGE_DIFF_POSITION_TYPE,
+ x: undefined,
+ y: undefined,
+ width: undefined,
+ height: undefined,
+ noteableType: undefined,
},
- undefined,
- );
+ });
});
});
});
diff --git a/spec/frontend/diffs/components/diff_discussions_spec.js b/spec/frontend/diffs/components/diff_discussions_spec.js
index 83becc7a20a..96b76183cee 100644
--- a/spec/frontend/diffs/components/diff_discussions_spec.js
+++ b/spec/frontend/diffs/components/diff_discussions_spec.js
@@ -1,9 +1,9 @@
import { mount, createLocalVue } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
import DiffDiscussions from '~/diffs/components/diff_discussions.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import NoteableDiscussion from '~/notes/components/noteable_discussion.vue';
import DiscussionNotes from '~/notes/components/discussion_notes.vue';
-import Icon from '~/vue_shared/components/icon.vue';
import { createStore } from '~/mr_notes/stores';
import '~/behaviors/markdown/render_gfm';
import discussionsMockData from '../mock_data/diff_discussions';
@@ -51,7 +51,7 @@ describe('DiffDiscussions', () => {
const diffNotesToggle = findDiffNotesToggle();
expect(diffNotesToggle.exists()).toBe(true);
- expect(diffNotesToggle.find(Icon).exists()).toBe(true);
+ expect(diffNotesToggle.find(GlIcon).exists()).toBe(true);
expect(diffNotesToggle.classes('diff-notes-collapse')).toBe(true);
});
diff --git a/spec/frontend/diffs/components/diff_expansion_cell_spec.js b/spec/frontend/diffs/components/diff_expansion_cell_spec.js
index b8aca4ad86b..81e08f09f62 100644
--- a/spec/frontend/diffs/components/diff_expansion_cell_spec.js
+++ b/spec/frontend/diffs/components/diff_expansion_cell_spec.js
@@ -10,7 +10,6 @@ import diffFileMockData from '../mock_data/diff_file';
const EXPAND_UP_CLASS = '.js-unfold';
const EXPAND_DOWN_CLASS = '.js-unfold-down';
-const LINE_TO_USE = 5;
const lineSources = {
[INLINE_DIFF_VIEW_TYPE]: 'highlighted_diff_lines',
[PARALLEL_DIFF_VIEW_TYPE]: 'parallel_diff_lines',
@@ -66,7 +65,7 @@ describe('DiffExpansionCell', () => {
beforeEach(() => {
mockFile = cloneDeep(diffFileMockData);
- mockLine = getLine(mockFile, INLINE_DIFF_VIEW_TYPE, LINE_TO_USE);
+ mockLine = getLine(mockFile, INLINE_DIFF_VIEW_TYPE, 8);
store = createStore();
store.state.diffs.diffFiles = [mockFile];
jest.spyOn(store, 'dispatch').mockReturnValue(Promise.resolve());
@@ -88,7 +87,7 @@ describe('DiffExpansionCell', () => {
const findExpandUp = () => vm.$el.querySelector(EXPAND_UP_CLASS);
const findExpandDown = () => vm.$el.querySelector(EXPAND_DOWN_CLASS);
- const findExpandAll = () => getByText(vm.$el, 'Show unchanged lines');
+ const findExpandAll = () => getByText(vm.$el, 'Show all unchanged lines');
describe('top row', () => {
it('should have "expand up" and "show all" option', () => {
@@ -126,12 +125,12 @@ describe('DiffExpansionCell', () => {
describe('any row', () => {
[
- { diffViewType: INLINE_DIFF_VIEW_TYPE, file: { parallel_diff_lines: [] } },
- { diffViewType: PARALLEL_DIFF_VIEW_TYPE, file: { highlighted_diff_lines: [] } },
- ].forEach(({ diffViewType, file }) => {
+ { diffViewType: INLINE_DIFF_VIEW_TYPE, lineIndex: 8, file: { parallel_diff_lines: [] } },
+ { diffViewType: PARALLEL_DIFF_VIEW_TYPE, lineIndex: 7, file: { highlighted_diff_lines: [] } },
+ ].forEach(({ diffViewType, file, lineIndex }) => {
describe(`with diffViewType (${diffViewType})`, () => {
beforeEach(() => {
- mockLine = getLine(mockFile, diffViewType, LINE_TO_USE);
+ mockLine = getLine(mockFile, diffViewType, lineIndex);
store.state.diffs.diffFiles = [{ ...mockFile, ...file }];
store.state.diffs.diffViewType = diffViewType;
});
@@ -189,10 +188,10 @@ describe('DiffExpansionCell', () => {
});
it('on expand down clicked, dispatch loadMoreLines', () => {
- mockFile[lineSources[diffViewType]][LINE_TO_USE + 1] = cloneDeep(
- mockFile[lineSources[diffViewType]][LINE_TO_USE],
+ mockFile[lineSources[diffViewType]][lineIndex + 1] = cloneDeep(
+ mockFile[lineSources[diffViewType]][lineIndex],
);
- const nextLine = getLine(mockFile, diffViewType, LINE_TO_USE + 1);
+ const nextLine = getLine(mockFile, diffViewType, lineIndex + 1);
nextLine.meta_data.old_pos = 300;
nextLine.meta_data.new_pos = 300;
diff --git a/spec/frontend/diffs/components/diff_file_header_spec.js b/spec/frontend/diffs/components/diff_file_header_spec.js
index 671dced080c..a0cad32b9fb 100644
--- a/spec/frontend/diffs/components/diff_file_header_spec.js
+++ b/spec/frontend/diffs/components/diff_file_header_spec.js
@@ -1,9 +1,10 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
+import { GlIcon } from '@gitlab/ui';
+import { cloneDeep } from 'lodash';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
import EditButton from '~/diffs/components/edit_button.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import Icon from '~/vue_shared/components/icon.vue';
import diffDiscussionsMockData from '../mock_data/diff_discussions';
import { truncateSha } from '~/lib/utils/text_utility';
import { diffViewerModes } from '~/ide/constants';
@@ -26,12 +27,16 @@ const diffFile = Object.freeze(
}),
);
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
describe('DiffFileHeader component', () => {
let wrapper;
+ let mockStoreConfig;
const diffHasExpandedDiscussionsResultMock = jest.fn();
const diffHasDiscussionsResultMock = jest.fn();
- const mockStoreConfig = {
+ const defaultMockStoreConfig = {
state: {},
modules: {
diffs: {
@@ -44,6 +49,7 @@ describe('DiffFileHeader component', () => {
toggleFileDiscussions: jest.fn(),
toggleFileDiscussionWrappers: jest.fn(),
toggleFullDiff: jest.fn(),
+ toggleActiveFileByHash: jest.fn(),
},
},
},
@@ -55,6 +61,8 @@ describe('DiffFileHeader component', () => {
diffHasExpandedDiscussionsResultMock,
...Object.values(mockStoreConfig.modules.diffs.actions),
].forEach(mock => mock.mockReset());
+
+ wrapper.destroy();
});
const findHeader = () => wrapper.find({ ref: 'header' });
@@ -70,7 +78,7 @@ describe('DiffFileHeader component', () => {
const findCollapseIcon = () => wrapper.find({ ref: 'collapseIcon' });
const findIconByName = iconName => {
- const icons = wrapper.findAll(Icon).filter(w => w.props('name') === iconName);
+ const icons = wrapper.findAll(GlIcon).filter(w => w.props('name') === iconName);
if (icons.length === 0) return icons;
if (icons.length > 1) {
throw new Error(`Multiple icons found for ${iconName}`);
@@ -79,8 +87,7 @@ describe('DiffFileHeader component', () => {
};
const createComponent = props => {
- const localVue = createLocalVue();
- localVue.use(Vuex);
+ mockStoreConfig = cloneDeep(defaultMockStoreConfig);
const store = new Vuex.Store(mockStoreConfig);
wrapper = shallowMount(DiffFileHeader, {
@@ -285,7 +292,7 @@ describe('DiffFileHeader component', () => {
findToggleDiscussionsButton().vm.$emit('click');
expect(
mockStoreConfig.modules.diffs.actions.toggleFileDiscussionWrappers,
- ).toHaveBeenCalledWith(expect.any(Object), diffFile, undefined);
+ ).toHaveBeenCalledWith(expect.any(Object), diffFile);
});
});
diff --git a/spec/frontend/diffs/components/diff_file_row_spec.js b/spec/frontend/diffs/components/diff_file_row_spec.js
index afdd4bfb335..23adc8f9da4 100644
--- a/spec/frontend/diffs/components/diff_file_row_spec.js
+++ b/spec/frontend/diffs/components/diff_file_row_spec.js
@@ -7,9 +7,12 @@ import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
describe('Diff File Row component', () => {
let wrapper;
- const createComponent = (props = {}) => {
+ const createComponent = (props = {}, highlightCurrentDiffRow = false) => {
wrapper = shallowMount(DiffFileRow, {
propsData: { ...props },
+ provide: {
+ glFeatures: { highlightCurrentDiffRow },
+ },
});
};
@@ -56,6 +59,31 @@ describe('Diff File Row component', () => {
);
});
+ it.each`
+ features | fileType | isViewed | expected
+ ${{ highlightCurrentDiffRow: true }} | ${'blob'} | ${false} | ${'gl-font-weight-bold'}
+ ${{}} | ${'blob'} | ${true} | ${''}
+ ${{}} | ${'tree'} | ${false} | ${''}
+ ${{}} | ${'tree'} | ${true} | ${''}
+ `(
+ 'with (features="$features", fileType="$fileType", isViewed=$isViewed), sets fileClasses="$expected"',
+ ({ features, fileType, isViewed, expected }) => {
+ createComponent(
+ {
+ file: {
+ type: fileType,
+ fileHash: '#123456789',
+ },
+ level: 0,
+ hideFileStats: false,
+ viewedFiles: isViewed ? { '#123456789': true } : {},
+ },
+ features.highlightCurrentDiffRow,
+ );
+ expect(wrapper.find(FileRow).props('fileClasses')).toBe(expected);
+ },
+ );
+
describe('FileRowStats components', () => {
it.each`
type | hideFileStats | value | desc
diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js
index ead8bd79cdb..79f0f6bc327 100644
--- a/spec/frontend/diffs/components/diff_file_spec.js
+++ b/spec/frontend/diffs/components/diff_file_spec.js
@@ -45,7 +45,7 @@ describe('DiffFile', () => {
vm.$nextTick()
.then(() => {
- expect(el.querySelectorAll('.line_content').length).toBe(5);
+ expect(el.querySelectorAll('.line_content').length).toBe(8);
expect(el.querySelectorAll('.js-line-expansion-content').length).toBe(1);
triggerEvent('.btn-clipboard');
})
@@ -90,8 +90,8 @@ describe('DiffFile', () => {
vm.isCollapsed = true;
vm.$nextTick(() => {
- expect(vm.$el.innerText).toContain('This diff is collapsed');
- expect(vm.$el.querySelectorAll('.js-click-to-expand').length).toEqual(1);
+ expect(vm.$el.innerText).toContain('This file is collapsed.');
+ expect(vm.$el.querySelector('[data-testid="expandButton"]')).not.toBeFalsy();
done();
});
@@ -102,8 +102,8 @@ describe('DiffFile', () => {
vm.isCollapsed = true;
vm.$nextTick(() => {
- expect(vm.$el.innerText).toContain('This diff is collapsed');
- expect(vm.$el.querySelectorAll('.js-click-to-expand').length).toEqual(1);
+ expect(vm.$el.innerText).toContain('This file is collapsed.');
+ expect(vm.$el.querySelector('[data-testid="expandButton"]')).not.toBeFalsy();
done();
});
@@ -121,28 +121,8 @@ describe('DiffFile', () => {
vm.isCollapsed = true;
vm.$nextTick(() => {
- expect(vm.$el.innerText).toContain('This diff is collapsed');
- expect(vm.$el.querySelectorAll('.js-click-to-expand').length).toEqual(1);
-
- done();
- });
- });
-
- it('should auto-expand collapsed files when viewDiffsFileByFile is true', done => {
- vm.$destroy();
- window.gon = {
- features: { autoExpandCollapsedDiffs: true },
- };
- vm = createComponentWithStore(Vue.extend(DiffFileComponent), createStore(), {
- file: JSON.parse(JSON.stringify(diffFileMockDataUnreadable)),
- canCurrentUserFork: false,
- viewDiffsFileByFile: true,
- }).$mount();
-
- vm.$nextTick(() => {
- expect(vm.$el.innerText).not.toContain('This diff is collapsed');
-
- window.gon = {};
+ expect(vm.$el.innerText).toContain('This file is collapsed.');
+ expect(vm.$el.querySelector('[data-testid="expandButton"]')).not.toBeFalsy();
done();
});
@@ -155,7 +135,7 @@ describe('DiffFile', () => {
vm.file.viewer.name = diffViewerModes.renamed;
vm.$nextTick(() => {
- expect(vm.$el.innerText).not.toContain('This diff is collapsed');
+ expect(vm.$el.innerText).not.toContain('This file is collapsed.');
done();
});
@@ -168,7 +148,7 @@ describe('DiffFile', () => {
vm.file.viewer.name = diffViewerModes.mode_changed;
vm.$nextTick(() => {
- expect(vm.$el.innerText).not.toContain('This diff is collapsed');
+ expect(vm.$el.innerText).not.toContain('This file is collapsed.');
done();
});
@@ -235,7 +215,7 @@ describe('DiffFile', () => {
it('calls handleLoadCollapsedDiff if collapsed changed & file has no lines', done => {
jest.spyOn(vm, 'handleLoadCollapsedDiff').mockImplementation(() => {});
- vm.file.highlighted_diff_lines = undefined;
+ vm.file.highlighted_diff_lines = [];
vm.file.parallel_diff_lines = [];
vm.isCollapsed = true;
@@ -262,8 +242,8 @@ describe('DiffFile', () => {
jest.spyOn(vm, 'handleLoadCollapsedDiff').mockImplementation(() => {});
- vm.file.highlighted_diff_lines = undefined;
- vm.file.parallel_diff_lines = [];
+ vm.file.highlighted_diff_lines = [];
+ vm.file.parallel_diff_lines = undefined;
vm.isCollapsed = true;
vm.$nextTick()
diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js
index 7a083fb6bde..4dcbb3ec332 100644
--- a/spec/frontend/diffs/components/diff_stats_spec.js
+++ b/spec/frontend/diffs/components/diff_stats_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
import DiffStats from '~/diffs/components/diff_stats.vue';
-import Icon from '~/vue_shared/components/icon.vue';
const TEST_ADDED_LINES = 100;
const TEST_REMOVED_LINES = 200;
@@ -53,7 +53,7 @@ describe('diff_stats', () => {
describe('files changes', () => {
const findIcon = name =>
wrapper
- .findAll(Icon)
+ .findAll(GlIcon)
.filter(c => c.attributes('name') === name)
.at(0).element.parentNode;
diff --git a/spec/frontend/diffs/components/image_diff_overlay_spec.js b/spec/frontend/diffs/components/image_diff_overlay_spec.js
index accf0a972d0..5a88a3cabd1 100644
--- a/spec/frontend/diffs/components/image_diff_overlay_spec.js
+++ b/spec/frontend/diffs/components/image_diff_overlay_spec.js
@@ -1,8 +1,8 @@
import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue';
import { createStore } from '~/mr_notes/stores';
import { imageDiffDiscussions } from '../mock_data/diff_discussions';
-import Icon from '~/vue_shared/components/icon.vue';
describe('Diffs image diff overlay component', () => {
const dimensions = {
@@ -64,7 +64,7 @@ describe('Diffs image diff overlay component', () => {
it('renders icon when showCommentIcon is true', () => {
createComponent({ showCommentIcon: true });
- expect(wrapper.find(Icon).exists()).toBe(true);
+ expect(wrapper.find(GlIcon).exists()).toBe(true);
});
it('sets badge comment positions', () => {
diff --git a/spec/frontend/diffs/components/inline_diff_expansion_row_spec.js b/spec/frontend/diffs/components/inline_diff_expansion_row_spec.js
index 90f012fbafe..81e5403d502 100644
--- a/spec/frontend/diffs/components/inline_diff_expansion_row_spec.js
+++ b/spec/frontend/diffs/components/inline_diff_expansion_row_spec.js
@@ -5,12 +5,13 @@ import InlineDiffExpansionRow from '~/diffs/components/inline_diff_expansion_row
import diffFileMockData from '../mock_data/diff_file';
describe('InlineDiffExpansionRow', () => {
- const matchLine = diffFileMockData.highlighted_diff_lines[5];
+ const mockData = { ...diffFileMockData };
+ const matchLine = mockData.highlighted_diff_lines.pop();
const createComponent = (options = {}) => {
const cmp = Vue.extend(InlineDiffExpansionRow);
const defaults = {
- fileHash: diffFileMockData.file_hash,
+ fileHash: mockData.file_hash,
contextLinesPath: 'contextLinesPath',
line: matchLine,
isTop: false,
diff --git a/spec/frontend/diffs/components/inline_diff_table_row_spec.js b/spec/frontend/diffs/components/inline_diff_table_row_spec.js
index f929f97b598..951b3f6258b 100644
--- a/spec/frontend/diffs/components/inline_diff_table_row_spec.js
+++ b/spec/frontend/diffs/components/inline_diff_table_row_spec.js
@@ -1,114 +1,317 @@
import { shallowMount } from '@vue/test-utils';
+import { TEST_HOST } from 'helpers/test_constants';
import { createStore } from '~/mr_notes/stores';
import InlineDiffTableRow from '~/diffs/components/inline_diff_table_row.vue';
+import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue';
import diffFileMockData from '../mock_data/diff_file';
+import discussionsMockData from '../mock_data/diff_discussions';
+
+const TEST_USER_ID = 'abc123';
+const TEST_USER = { id: TEST_USER_ID };
describe('InlineDiffTableRow', () => {
let wrapper;
- let vm;
+ let store;
const thisLine = diffFileMockData.highlighted_diff_lines[0];
- beforeEach(() => {
+ const createComponent = (props = {}, propsStore = store) => {
wrapper = shallowMount(InlineDiffTableRow, {
- store: createStore(),
+ store: propsStore,
propsData: {
line: thisLine,
fileHash: diffFileMockData.file_hash,
filePath: diffFileMockData.file_path,
contextLinesPath: 'contextLinesPath',
isHighlighted: false,
+ ...props,
},
});
- vm = wrapper.vm;
+ };
+
+ const setWindowLocation = value => {
+ Object.defineProperty(window, 'location', {
+ writable: true,
+ value,
+ });
+ };
+
+ beforeEach(() => {
+ store = createStore();
+ store.state.notes.userData = TEST_USER;
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
});
- it('does not add hll class to line content when line does not match highlighted row', done => {
- vm.$nextTick()
- .then(() => {
- expect(wrapper.find('.line_content').classes('hll')).toBe(false);
- })
- .then(done)
- .catch(done.fail);
+ it('does not add hll class to line content when line does not match highlighted row', () => {
+ createComponent();
+ expect(wrapper.find('.line_content').classes('hll')).toBe(false);
});
- it('adds hll class to lineContent when line is the highlighted row', done => {
- vm.$nextTick()
- .then(() => {
- vm.$store.state.diffs.highlightedRow = thisLine.line_code;
-
- return vm.$nextTick();
- })
- .then(() => {
- expect(wrapper.find('.line_content').classes('hll')).toBe(true);
- })
- .then(done)
- .catch(done.fail);
+ it('adds hll class to lineContent when line is the highlighted row', () => {
+ store.state.diffs.highlightedRow = thisLine.line_code;
+ createComponent({}, store);
+ expect(wrapper.find('.line_content').classes('hll')).toBe(true);
});
it('adds hll class to lineContent when line is part of a multiline comment', () => {
- wrapper.setProps({ isCommented: true });
- return vm.$nextTick().then(() => {
- expect(wrapper.find('.line_content').classes('hll')).toBe(true);
- });
+ createComponent({ isCommented: true });
+ expect(wrapper.find('.line_content').classes('hll')).toBe(true);
});
describe('sets coverage title and class', () => {
- it('for lines with coverage', done => {
- vm.$nextTick()
- .then(() => {
- const name = diffFileMockData.file_path;
- const line = thisLine.new_line;
-
- vm.$store.state.diffs.coverageFiles = { files: { [name]: { [line]: 5 } } };
-
- return vm.$nextTick();
- })
- .then(() => {
- const coverage = wrapper.find('.line-coverage');
-
- expect(coverage.attributes('title')).toContain('Test coverage: 5 hits');
- expect(coverage.classes('coverage')).toBe(true);
- })
- .then(done)
- .catch(done.fail);
+ it('for lines with coverage', () => {
+ const name = diffFileMockData.file_path;
+ const line = thisLine.new_line;
+
+ store.state.diffs.coverageFiles = { files: { [name]: { [line]: 5 } } };
+ createComponent({}, store);
+ const coverage = wrapper.find('.line-coverage');
+
+ expect(coverage.attributes('title')).toContain('Test coverage: 5 hits');
+ expect(coverage.classes('coverage')).toBe(true);
+ });
+
+ it('for lines without coverage', () => {
+ const name = diffFileMockData.file_path;
+ const line = thisLine.new_line;
+
+ store.state.diffs.coverageFiles = { files: { [name]: { [line]: 0 } } };
+ createComponent({}, store);
+ const coverage = wrapper.find('.line-coverage');
+
+ expect(coverage.attributes('title')).toContain('No test coverage');
+ expect(coverage.classes('no-coverage')).toBe(true);
+ });
+
+ it('for unknown lines', () => {
+ store.state.diffs.coverageFiles = {};
+ createComponent({}, store);
+
+ const coverage = wrapper.find('.line-coverage');
+
+ expect(coverage.attributes('title')).toBeUndefined();
+ expect(coverage.classes('coverage')).toBe(false);
+ expect(coverage.classes('no-coverage')).toBe(false);
+ });
+ });
+
+ describe('Table Cells', () => {
+ const findNewTd = () => wrapper.find({ ref: 'newTd' });
+ const findOldTd = () => wrapper.find({ ref: 'oldTd' });
+
+ describe('td', () => {
+ it('highlights when isHighlighted true', () => {
+ store.state.diffs.highlightedRow = thisLine.line_code;
+ createComponent({}, store);
+
+ expect(findNewTd().classes()).toContain('hll');
+ expect(findOldTd().classes()).toContain('hll');
+ });
+
+ it('does not highlight when isHighlighted false', () => {
+ createComponent();
+
+ expect(findNewTd().classes()).not.toContain('hll');
+ expect(findOldTd().classes()).not.toContain('hll');
+ });
+ });
+
+ describe('comment button', () => {
+ const findNoteButton = () => wrapper.find({ ref: 'addDiffNoteButton' });
+
+ it.each`
+ userData | query | mergeRefHeadComments | expectation
+ ${TEST_USER} | ${'diff_head=false'} | ${false} | ${true}
+ ${TEST_USER} | ${'diff_head=true'} | ${true} | ${true}
+ ${TEST_USER} | ${'diff_head=true'} | ${false} | ${false}
+ ${null} | ${''} | ${true} | ${false}
+ `(
+ 'exists is $expectation - with userData ($userData) query ($query)',
+ ({ userData, query, mergeRefHeadComments, expectation }) => {
+ store.state.notes.userData = userData;
+ gon.features = { mergeRefHeadComments };
+ setWindowLocation({ href: `${TEST_HOST}?${query}` });
+ createComponent({}, store);
+
+ expect(findNoteButton().exists()).toBe(expectation);
+ },
+ );
+
+ it.each`
+ isHover | line | expectation
+ ${true} | ${{ ...thisLine, discussions: [] }} | ${true}
+ ${false} | ${{ ...thisLine, discussions: [] }} | ${false}
+ ${true} | ${{ ...thisLine, type: 'context', discussions: [] }} | ${false}
+ ${true} | ${{ ...thisLine, type: 'old-nonewline', discussions: [] }} | ${false}
+ ${true} | ${{ ...thisLine, discussions: [{}] }} | ${false}
+ `('visible is $expectation - line ($line)', ({ isHover, line, expectation }) => {
+ createComponent({ line });
+ wrapper.setData({ isHover });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findNoteButton().isVisible()).toBe(expectation);
+ });
+ });
+
+ it.each`
+ disabled | commentsDisabled
+ ${'disabled'} | ${true}
+ ${undefined} | ${false}
+ `(
+ 'has attribute disabled=$disabled when the outer component has prop commentsDisabled=$commentsDisabled',
+ ({ disabled, commentsDisabled }) => {
+ createComponent({
+ line: { ...thisLine, commentsDisabled },
+ });
+
+ wrapper.setData({ isHover: true });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findNoteButton().attributes('disabled')).toBe(disabled);
+ });
+ },
+ );
+
+ const symlinkishFileTooltip =
+ 'Commenting on symbolic links that replace or are replaced by files is currently not supported.';
+ const realishFileTooltip =
+ 'Commenting on files that replace or are replaced by symbolic links is currently not supported.';
+ const otherFileTooltip = 'Add a comment to this line';
+ const findTooltip = () => wrapper.find({ ref: 'addNoteTooltip' });
+
+ it.each`
+ tooltip | commentsDisabled
+ ${symlinkishFileTooltip} | ${{ wasSymbolic: true }}
+ ${symlinkishFileTooltip} | ${{ isSymbolic: true }}
+ ${realishFileTooltip} | ${{ wasReal: true }}
+ ${realishFileTooltip} | ${{ isReal: true }}
+ ${otherFileTooltip} | ${false}
+ `(
+ 'has the correct tooltip when commentsDisabled=$commentsDisabled',
+ ({ tooltip, commentsDisabled }) => {
+ createComponent({
+ line: { ...thisLine, commentsDisabled },
+ });
+
+ wrapper.setData({ isHover: true });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findTooltip().attributes('title')).toBe(tooltip);
+ });
+ },
+ );
});
- it('for lines without coverage', done => {
- vm.$nextTick()
- .then(() => {
- const name = diffFileMockData.file_path;
- const line = thisLine.new_line;
+ describe('line number', () => {
+ const findLineNumberOld = () => wrapper.find({ ref: 'lineNumberRefOld' });
+ const findLineNumberNew = () => wrapper.find({ ref: 'lineNumberRefNew' });
+
+ it('renders line numbers in correct cells', () => {
+ createComponent();
+
+ expect(findLineNumberOld().exists()).toBe(false);
+ expect(findLineNumberNew().exists()).toBe(true);
+ });
- vm.$store.state.diffs.coverageFiles = { files: { [name]: { [line]: 0 } } };
+ describe('with lineNumber prop', () => {
+ const TEST_LINE_CODE = 'LC_42';
+ const TEST_LINE_NUMBER = 1;
- return vm.$nextTick();
- })
- .then(() => {
- const coverage = wrapper.find('.line-coverage');
+ describe.each`
+ lineProps | findLineNumber | expectedHref | expectedClickArg
+ ${{ line_code: TEST_LINE_CODE, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${`#${TEST_LINE_CODE}`} | ${TEST_LINE_CODE}
+ ${{ line_code: undefined, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${undefined}
+ ${{ line_code: undefined, left: { line_code: TEST_LINE_CODE }, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${TEST_LINE_CODE}
+ ${{ line_code: undefined, right: { line_code: TEST_LINE_CODE }, new_line: TEST_LINE_NUMBER }} | ${findLineNumberNew} | ${'#'} | ${TEST_LINE_CODE}
+ `(
+ 'with line ($lineProps)',
+ ({ lineProps, findLineNumber, expectedHref, expectedClickArg }) => {
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ createComponent({
+ line: { ...thisLine, ...lineProps },
+ });
+ });
- expect(coverage.attributes('title')).toContain('No test coverage');
- expect(coverage.classes('no-coverage')).toBe(true);
- })
- .then(done)
- .catch(done.fail);
+ it('renders', () => {
+ expect(findLineNumber().exists()).toBe(true);
+ expect(findLineNumber().attributes()).toEqual({
+ href: expectedHref,
+ 'data-linenumber': TEST_LINE_NUMBER.toString(),
+ });
+ });
+
+ it('on click, dispatches setHighlightedRow', () => {
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+
+ findLineNumber().trigger('click');
+
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'diffs/setHighlightedRow',
+ expectedClickArg,
+ );
+ expect(store.dispatch).toHaveBeenCalledTimes(2);
+ });
+ },
+ );
+ });
});
- it('for unknown lines', done => {
- vm.$nextTick()
- .then(() => {
- vm.$store.state.diffs.coverageFiles = {};
-
- return vm.$nextTick();
- })
- .then(() => {
- const coverage = wrapper.find('.line-coverage');
-
- expect(coverage.attributes('title')).toBeUndefined();
- expect(coverage.classes('coverage')).toBe(false);
- expect(coverage.classes('no-coverage')).toBe(false);
- })
- .then(done)
- .catch(done.fail);
+ describe('diff-gutter-avatars', () => {
+ const TEST_LINE_CODE = 'LC_42';
+ const TEST_FILE_HASH = diffFileMockData.file_hash;
+ const findAvatars = () => wrapper.find(DiffGutterAvatars);
+ let line;
+
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+
+ line = {
+ line_code: TEST_LINE_CODE,
+ type: 'new',
+ old_line: null,
+ new_line: 1,
+ discussions: [{ ...discussionsMockData }],
+ discussionsExpanded: true,
+ text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ rich_text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ meta_data: null,
+ };
+ });
+
+ describe('with showCommentButton', () => {
+ it('renders if line has discussions', () => {
+ createComponent({ line });
+
+ expect(findAvatars().props()).toEqual({
+ discussions: line.discussions,
+ discussionsExpanded: line.discussionsExpanded,
+ });
+ });
+
+ it('does notrender if line has no discussions', () => {
+ line.discussions = [];
+ createComponent({ line });
+
+ expect(findAvatars().exists()).toEqual(false);
+ });
+
+ it('toggles line discussion', () => {
+ createComponent({ line });
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+
+ findAvatars().vm.$emit('toggleLineDiscussions');
+
+ expect(store.dispatch).toHaveBeenCalledWith('diffs/toggleLineDiscussions', {
+ lineCode: TEST_LINE_CODE,
+ fileHash: TEST_FILE_HASH,
+ expanded: !line.discussionsExpanded,
+ });
+ });
+ });
});
});
});
diff --git a/spec/frontend/diffs/components/inline_diff_view_spec.js b/spec/frontend/diffs/components/inline_diff_view_spec.js
index 6c37f86658e..39c581e2796 100644
--- a/spec/frontend/diffs/components/inline_diff_view_spec.js
+++ b/spec/frontend/diffs/components/inline_diff_view_spec.js
@@ -30,8 +30,8 @@ describe('InlineDiffView', () => {
it('should have rendered diff lines', () => {
const el = component.$el;
- expect(el.querySelectorAll('tr.line_holder').length).toEqual(5);
- expect(el.querySelectorAll('tr.line_holder.new').length).toEqual(2);
+ expect(el.querySelectorAll('tr.line_holder').length).toEqual(8);
+ expect(el.querySelectorAll('tr.line_holder.new').length).toEqual(4);
expect(el.querySelectorAll('tr.line_expansion.match').length).toEqual(1);
expect(el.textContent.indexOf('Bad dates')).toBeGreaterThan(-1);
});
diff --git a/spec/frontend/diffs/components/merge_conflict_warning_spec.js b/spec/frontend/diffs/components/merge_conflict_warning_spec.js
new file mode 100644
index 00000000000..2f303f25f66
--- /dev/null
+++ b/spec/frontend/diffs/components/merge_conflict_warning_spec.js
@@ -0,0 +1,77 @@
+import { shallowMount, mount } from '@vue/test-utils';
+import MergeConflictWarning from '~/diffs/components/merge_conflict_warning.vue';
+import { CENTERED_LIMITED_CONTAINER_CLASSES } from '~/diffs/constants';
+
+const propsData = {
+ limited: true,
+ mergeable: true,
+ resolutionPath: 'a-path',
+};
+const limitedClasses = CENTERED_LIMITED_CONTAINER_CLASSES.split(' ');
+
+function findResolveButton(wrapper) {
+ return wrapper.find('.gl-alert-actions a.gl-button:first-child');
+}
+function findLocalMergeButton(wrapper) {
+ return wrapper.find('.gl-alert-actions button.gl-button:last-child');
+}
+
+describe('MergeConflictWarning', () => {
+ let wrapper;
+
+ const createComponent = (props = {}, { full } = { full: false }) => {
+ const mounter = full ? mount : shallowMount;
+
+ wrapper = mounter(MergeConflictWarning, {
+ propsData: { ...propsData, ...props },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it.each`
+ limited | containerClasses
+ ${true} | ${limitedClasses}
+ ${false} | ${[]}
+ `(
+ 'has the correct container classes when limited is $limited',
+ ({ limited, containerClasses }) => {
+ createComponent({ limited });
+
+ expect(wrapper.classes()).toEqual(containerClasses);
+ },
+ );
+
+ it.each`
+ present | resolutionPath
+ ${false} | ${''}
+ ${true} | ${'some-path'}
+ `(
+ 'toggles the resolve conflicts button based on the provided resolutionPath "$resolutionPath"',
+ ({ present, resolutionPath }) => {
+ createComponent({ resolutionPath }, { full: true });
+ const resolveButton = findResolveButton(wrapper);
+
+ expect(resolveButton.exists()).toBe(present);
+ if (present) {
+ expect(resolveButton.attributes('href')).toBe(resolutionPath);
+ }
+ },
+ );
+
+ it.each`
+ present | mergeable
+ ${false} | ${false}
+ ${true} | ${true}
+ `(
+ 'toggles the local merge button based on the provided mergeable property "$mergable"',
+ ({ present, mergeable }) => {
+ createComponent({ mergeable }, { full: true });
+ const localMerge = findLocalMergeButton(wrapper);
+
+ expect(localMerge.exists()).toBe(present);
+ },
+ );
+});
diff --git a/spec/frontend/diffs/components/no_changes_spec.js b/spec/frontend/diffs/components/no_changes_spec.js
index 2795c68b4ee..78805a1cddc 100644
--- a/spec/frontend/diffs/components/no_changes_spec.js
+++ b/spec/frontend/diffs/components/no_changes_spec.js
@@ -36,7 +36,7 @@ describe('Diff no changes empty state', () => {
};
});
- expect(vm.contains('script')).toBe(false);
+ expect(vm.find('script').exists()).toBe(false);
});
describe('Renders', () => {
diff --git a/spec/frontend/diffs/components/parallel_diff_table_row_spec.js b/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
index 339352943a9..13c4ce06f18 100644
--- a/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
+++ b/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
@@ -1,9 +1,12 @@
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { TEST_HOST } from 'helpers/test_constants';
import { createStore } from '~/mr_notes/stores';
import ParallelDiffTableRow from '~/diffs/components/parallel_diff_table_row.vue';
import diffFileMockData from '../mock_data/diff_file';
+import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue';
+import discussionsMockData from '../mock_data/diff_discussions';
describe('ParallelDiffTableRow', () => {
describe('when one side is empty', () => {
@@ -158,4 +161,260 @@ describe('ParallelDiffTableRow', () => {
});
});
});
+
+ describe('Table Cells', () => {
+ let wrapper;
+ let store;
+ let thisLine;
+ const TEST_USER_ID = 'abc123';
+ const TEST_USER = { id: TEST_USER_ID };
+
+ const createComponent = (props = {}, propsStore = store, data = {}) => {
+ wrapper = shallowMount(ParallelDiffTableRow, {
+ store: propsStore,
+ propsData: {
+ line: thisLine,
+ fileHash: diffFileMockData.file_hash,
+ filePath: diffFileMockData.file_path,
+ contextLinesPath: 'contextLinesPath',
+ isHighlighted: false,
+ ...props,
+ },
+ data() {
+ return data;
+ },
+ });
+ };
+
+ const setWindowLocation = value => {
+ Object.defineProperty(window, 'location', {
+ writable: true,
+ value,
+ });
+ };
+
+ beforeEach(() => {
+ // eslint-disable-next-line prefer-destructuring
+ thisLine = diffFileMockData.parallel_diff_lines[2];
+ store = createStore();
+ store.state.notes.userData = TEST_USER;
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findNewTd = () => wrapper.find({ ref: 'newTd' });
+ const findOldTd = () => wrapper.find({ ref: 'oldTd' });
+
+ describe('td', () => {
+ it('highlights when isHighlighted true', () => {
+ store.state.diffs.highlightedRow = thisLine.left.line_code;
+ createComponent({}, store);
+
+ expect(findNewTd().classes()).toContain('hll');
+ expect(findOldTd().classes()).toContain('hll');
+ });
+
+ it('does not highlight when isHighlighted false', () => {
+ createComponent();
+
+ expect(findNewTd().classes()).not.toContain('hll');
+ expect(findOldTd().classes()).not.toContain('hll');
+ });
+ });
+
+ describe('comment button', () => {
+ const findNoteButton = () => wrapper.find({ ref: 'addDiffNoteButtonLeft' });
+
+ it.each`
+ hover | line | userData | query | mergeRefHeadComments | expectation
+ ${true} | ${{}} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${true}
+ ${true} | ${{ line: { left: null } }} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${false}
+ ${true} | ${{}} | ${TEST_USER} | ${'diff_head=true'} | ${true} | ${true}
+ ${true} | ${{}} | ${TEST_USER} | ${'diff_head=true'} | ${false} | ${false}
+ ${true} | ${{}} | ${null} | ${''} | ${true} | ${false}
+ ${false} | ${{}} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${false}
+ `(
+ 'exists is $expectation - with userData ($userData) query ($query)',
+ async ({ hover, line, userData, query, mergeRefHeadComments, expectation }) => {
+ store.state.notes.userData = userData;
+ gon.features = { mergeRefHeadComments };
+ setWindowLocation({ href: `${TEST_HOST}?${query}` });
+ createComponent(line, store);
+ if (hover) await wrapper.find('.line_holder').trigger('mouseover');
+
+ expect(findNoteButton().exists()).toBe(expectation);
+ },
+ );
+
+ it.each`
+ line | expectation
+ ${{ ...thisLine, left: { discussions: [] } }} | ${true}
+ ${{ ...thisLine, left: { type: 'context', discussions: [] } }} | ${false}
+ ${{ ...thisLine, left: { type: 'old-nonewline', discussions: [] } }} | ${false}
+ ${{ ...thisLine, left: { discussions: [{}] } }} | ${false}
+ `('visible is $expectation - line ($line)', async ({ line, expectation }) => {
+ createComponent({ line }, store, { isLeftHover: true, isCommentButtonRendered: true });
+
+ expect(findNoteButton().isVisible()).toBe(expectation);
+ });
+
+ it.each`
+ disabled | commentsDisabled
+ ${'disabled'} | ${true}
+ ${undefined} | ${false}
+ `(
+ 'has attribute disabled=$disabled when the outer component has prop commentsDisabled=$commentsDisabled',
+ ({ disabled, commentsDisabled }) => {
+ thisLine.left.commentsDisabled = commentsDisabled;
+ createComponent({ line: { ...thisLine } }, store, {
+ isLeftHover: true,
+ isCommentButtonRendered: true,
+ });
+
+ expect(findNoteButton().attributes('disabled')).toBe(disabled);
+ },
+ );
+
+ const symlinkishFileTooltip =
+ 'Commenting on symbolic links that replace or are replaced by files is currently not supported.';
+ const realishFileTooltip =
+ 'Commenting on files that replace or are replaced by symbolic links is currently not supported.';
+ const otherFileTooltip = 'Add a comment to this line';
+ const findTooltip = () => wrapper.find({ ref: 'addNoteTooltipLeft' });
+
+ it.each`
+ tooltip | commentsDisabled
+ ${symlinkishFileTooltip} | ${{ wasSymbolic: true }}
+ ${symlinkishFileTooltip} | ${{ isSymbolic: true }}
+ ${realishFileTooltip} | ${{ wasReal: true }}
+ ${realishFileTooltip} | ${{ isReal: true }}
+ ${otherFileTooltip} | ${false}
+ `(
+ 'has the correct tooltip when commentsDisabled=$commentsDisabled',
+ ({ tooltip, commentsDisabled }) => {
+ thisLine.left.commentsDisabled = commentsDisabled;
+ createComponent({ line: { ...thisLine } }, store, {
+ isLeftHover: true,
+ isCommentButtonRendered: true,
+ });
+
+ expect(findTooltip().attributes('title')).toBe(tooltip);
+ },
+ );
+ });
+
+ describe('line number', () => {
+ const findLineNumberOld = () => wrapper.find({ ref: 'lineNumberRefOld' });
+ const findLineNumberNew = () => wrapper.find({ ref: 'lineNumberRefNew' });
+
+ it('renders line numbers in correct cells', () => {
+ createComponent();
+
+ expect(findLineNumberOld().exists()).toBe(true);
+ expect(findLineNumberNew().exists()).toBe(true);
+ });
+
+ describe('with lineNumber prop', () => {
+ const TEST_LINE_CODE = 'LC_42';
+ const TEST_LINE_NUMBER = 1;
+
+ describe.each`
+ lineProps | findLineNumber | expectedHref | expectedClickArg
+ ${{ line_code: TEST_LINE_CODE, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${`#${TEST_LINE_CODE}`} | ${TEST_LINE_CODE}
+ ${{ line_code: undefined, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${undefined}
+ `(
+ 'with line ($lineProps)',
+ ({ lineProps, findLineNumber, expectedHref, expectedClickArg }) => {
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ Object.assign(thisLine.left, lineProps);
+ Object.assign(thisLine.right, lineProps);
+ createComponent({
+ line: { ...thisLine },
+ });
+ });
+
+ it('renders', () => {
+ expect(findLineNumber().exists()).toBe(true);
+ expect(findLineNumber().attributes()).toEqual({
+ href: expectedHref,
+ 'data-linenumber': TEST_LINE_NUMBER.toString(),
+ });
+ });
+
+ it('on click, dispatches setHighlightedRow', () => {
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+
+ findLineNumber().trigger('click');
+
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'diffs/setHighlightedRow',
+ expectedClickArg,
+ );
+ expect(store.dispatch).toHaveBeenCalledTimes(2);
+ });
+ },
+ );
+ });
+ });
+
+ describe('diff-gutter-avatars', () => {
+ const TEST_LINE_CODE = 'LC_42';
+ const TEST_FILE_HASH = diffFileMockData.file_hash;
+ const findAvatars = () => wrapper.find(DiffGutterAvatars);
+ let line;
+
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+
+ line = {
+ left: {
+ line_code: TEST_LINE_CODE,
+ type: 'new',
+ old_line: null,
+ new_line: 1,
+ discussions: [{ ...discussionsMockData }],
+ discussionsExpanded: true,
+ text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ rich_text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ meta_data: null,
+ },
+ };
+ });
+
+ describe('with showCommentButton', () => {
+ it('renders if line has discussions', () => {
+ createComponent({ line });
+
+ expect(findAvatars().props()).toEqual({
+ discussions: line.left.discussions,
+ discussionsExpanded: line.left.discussionsExpanded,
+ });
+ });
+
+ it('does notrender if line has no discussions', () => {
+ line.left.discussions = [];
+ createComponent({ line });
+
+ expect(findAvatars().exists()).toEqual(false);
+ });
+
+ it('toggles line discussion', () => {
+ createComponent({ line });
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+
+ findAvatars().vm.$emit('toggleLineDiscussions');
+
+ expect(store.dispatch).toHaveBeenCalledWith('diffs/toggleLineDiscussions', {
+ lineCode: TEST_LINE_CODE,
+ fileHash: TEST_FILE_HASH,
+ expanded: !line.left.discussionsExpanded,
+ });
+ });
+ });
+ });
+ });
});
diff --git a/spec/frontend/diffs/components/parallel_diff_view_spec.js b/spec/frontend/diffs/components/parallel_diff_view_spec.js
index cb1a47f60d5..44ed303d0ef 100644
--- a/spec/frontend/diffs/components/parallel_diff_view_spec.js
+++ b/spec/frontend/diffs/components/parallel_diff_view_spec.js
@@ -1,33 +1,37 @@
-import Vue from 'vue';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import Vuex from 'vuex';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
import { createStore } from '~/mr_notes/stores';
import ParallelDiffView from '~/diffs/components/parallel_diff_view.vue';
-import * as constants from '~/diffs/constants';
+import parallelDiffTableRow from '~/diffs/components/parallel_diff_table_row.vue';
import diffFileMockData from '../mock_data/diff_file';
-describe('ParallelDiffView', () => {
- let component;
- const getDiffFileMock = () => ({ ...diffFileMockData });
+let wrapper;
+const localVue = createLocalVue();
+
+localVue.use(Vuex);
- beforeEach(() => {
- const diffFile = getDiffFileMock();
+function factory() {
+ const diffFile = { ...diffFileMockData };
+ const store = createStore();
- component = createComponentWithStore(Vue.extend(ParallelDiffView), createStore(), {
+ wrapper = shallowMount(ParallelDiffView, {
+ localVue,
+ store,
+ propsData: {
diffFile,
diffLines: diffFile.parallel_diff_lines,
- }).$mount();
+ },
});
+}
+describe('ParallelDiffView', () => {
afterEach(() => {
- component.$destroy();
+ wrapper.destroy();
});
- describe('assigned', () => {
- describe('diffLines', () => {
- it('should normalize lines for empty cells', () => {
- expect(component.diffLines[0].left.type).toEqual(constants.EMPTY_CELL_TYPE);
- expect(component.diffLines[1].left.type).toEqual(constants.EMPTY_CELL_TYPE);
- });
- });
+ it('renders diff lines', () => {
+ factory();
+
+ expect(wrapper.findAll(parallelDiffTableRow).length).toBe(8);
});
});
diff --git a/spec/frontend/diffs/components/settings_dropdown_spec.js b/spec/frontend/diffs/components/settings_dropdown_spec.js
index 2e95d79ea49..72330d8efba 100644
--- a/spec/frontend/diffs/components/settings_dropdown_spec.js
+++ b/spec/frontend/diffs/components/settings_dropdown_spec.js
@@ -7,7 +7,7 @@ import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constant
const localVue = createLocalVue();
localVue.use(Vuex);
-describe('Diff settiings dropdown component', () => {
+describe('Diff settings dropdown component', () => {
let vm;
let actions;
@@ -50,7 +50,7 @@ describe('Diff settiings dropdown component', () => {
vm.find('.js-list-view').trigger('click');
- expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), false, undefined);
+ expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), false);
});
it('tree view button dispatches setRenderTreeList with true', () => {
@@ -58,53 +58,53 @@ describe('Diff settiings dropdown component', () => {
vm.find('.js-tree-view').trigger('click');
- expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), true, undefined);
+ expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), true);
});
- it('sets list button as active when renderTreeList is false', () => {
+ it('sets list button as selected when renderTreeList is false', () => {
createComponent(store => {
Object.assign(store.state.diffs, {
renderTreeList: false,
});
});
- expect(vm.find('.js-list-view').classes('active')).toBe(true);
- expect(vm.find('.js-tree-view').classes('active')).toBe(false);
+ expect(vm.find('.js-list-view').classes('selected')).toBe(true);
+ expect(vm.find('.js-tree-view').classes('selected')).toBe(false);
});
- it('sets tree button as active when renderTreeList is true', () => {
+ it('sets tree button as selected when renderTreeList is true', () => {
createComponent(store => {
Object.assign(store.state.diffs, {
renderTreeList: true,
});
});
- expect(vm.find('.js-list-view').classes('active')).toBe(false);
- expect(vm.find('.js-tree-view').classes('active')).toBe(true);
+ expect(vm.find('.js-list-view').classes('selected')).toBe(false);
+ expect(vm.find('.js-tree-view').classes('selected')).toBe(true);
});
});
describe('compare changes', () => {
- it('sets inline button as active', () => {
+ it('sets inline button as selected', () => {
createComponent(store => {
Object.assign(store.state.diffs, {
diffViewType: INLINE_DIFF_VIEW_TYPE,
});
});
- expect(vm.find('.js-inline-diff-button').classes('active')).toBe(true);
- expect(vm.find('.js-parallel-diff-button').classes('active')).toBe(false);
+ expect(vm.find('.js-inline-diff-button').classes('selected')).toBe(true);
+ expect(vm.find('.js-parallel-diff-button').classes('selected')).toBe(false);
});
- it('sets parallel button as active', () => {
+ it('sets parallel button as selected', () => {
createComponent(store => {
Object.assign(store.state.diffs, {
diffViewType: PARALLEL_DIFF_VIEW_TYPE,
});
});
- expect(vm.find('.js-inline-diff-button').classes('active')).toBe(false);
- expect(vm.find('.js-parallel-diff-button').classes('active')).toBe(true);
+ expect(vm.find('.js-inline-diff-button').classes('selected')).toBe(false);
+ expect(vm.find('.js-parallel-diff-button').classes('selected')).toBe(true);
});
it('calls setInlineDiffViewType when clicking inline button', () => {
@@ -153,14 +153,10 @@ describe('Diff settiings dropdown component', () => {
checkbox.element.checked = true;
checkbox.trigger('change');
- expect(actions.setShowWhitespace).toHaveBeenCalledWith(
- expect.anything(),
- {
- showWhitespace: true,
- pushState: true,
- },
- undefined,
- );
+ expect(actions.setShowWhitespace).toHaveBeenCalledWith(expect.anything(), {
+ showWhitespace: true,
+ pushState: true,
+ });
});
});
});
diff --git a/spec/frontend/diffs/components/tree_list_spec.js b/spec/frontend/diffs/components/tree_list_spec.js
index 14cb2a17aec..cc177a81d88 100644
--- a/spec/frontend/diffs/components/tree_list_spec.js
+++ b/spec/frontend/diffs/components/tree_list_spec.js
@@ -1,16 +1,26 @@
import Vuex from 'vuex';
-import { mount, createLocalVue } from '@vue/test-utils';
+import { shallowMount, mount, createLocalVue } from '@vue/test-utils';
import TreeList from '~/diffs/components/tree_list.vue';
import createStore from '~/diffs/store/modules';
+import FileTree from '~/vue_shared/components/file_tree.vue';
describe('Diffs tree list component', () => {
let wrapper;
+ let store;
const getFileRows = () => wrapper.findAll('.file-row');
const localVue = createLocalVue();
localVue.use(Vuex);
- const createComponent = state => {
- const store = new Vuex.Store({
+ const createComponent = (mountFn = mount) => {
+ wrapper = mountFn(TreeList, {
+ store,
+ localVue,
+ propsData: { hideFileStats: false },
+ });
+ };
+
+ beforeEach(() => {
+ store = new Vuex.Store({
modules: {
diffs: createStore(),
},
@@ -23,61 +33,57 @@ describe('Diffs tree list component', () => {
addedLines: 10,
removedLines: 20,
...store.state.diffs,
- ...state,
};
+ });
- wrapper = mount(TreeList, {
- store,
- localVue,
- propsData: { hideFileStats: false },
+ const setupFilesInState = () => {
+ const treeEntries = {
+ 'index.js': {
+ addedLines: 0,
+ changed: true,
+ deleted: false,
+ fileHash: 'test',
+ key: 'index.js',
+ name: 'index.js',
+ path: 'app/index.js',
+ removedLines: 0,
+ tempFile: true,
+ type: 'blob',
+ parentPath: 'app',
+ },
+ app: {
+ key: 'app',
+ path: 'app',
+ name: 'app',
+ type: 'tree',
+ tree: [],
+ },
+ };
+
+ Object.assign(store.state.diffs, {
+ treeEntries,
+ tree: [treeEntries['index.js'], treeEntries.app],
});
};
- beforeEach(() => {
- localStorage.removeItem('mr_diff_tree_list');
-
- createComponent();
- });
-
afterEach(() => {
wrapper.destroy();
});
- it('renders empty text', () => {
- expect(wrapper.text()).toContain('No files found');
+ describe('default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders empty text', () => {
+ expect(wrapper.text()).toContain('No files found');
+ });
});
describe('with files', () => {
beforeEach(() => {
- const treeEntries = {
- 'index.js': {
- addedLines: 0,
- changed: true,
- deleted: false,
- fileHash: 'test',
- key: 'index.js',
- name: 'index.js',
- path: 'app/index.js',
- removedLines: 0,
- tempFile: true,
- type: 'blob',
- parentPath: 'app',
- },
- app: {
- key: 'app',
- path: 'app',
- name: 'app',
- type: 'tree',
- tree: [],
- },
- };
-
- createComponent({
- treeEntries,
- tree: [treeEntries['index.js'], treeEntries.app],
- });
-
- return wrapper.vm.$nextTick();
+ setupFilesInState();
+ createComponent();
});
it('renders tree', () => {
@@ -136,4 +142,23 @@ describe('Diffs tree list component', () => {
});
});
});
+
+ describe('with viewedDiffFileIds', () => {
+ const viewedDiffFileIds = { fileId: '#12345' };
+
+ beforeEach(() => {
+ setupFilesInState();
+ store.state.diffs.viewedDiffFileIds = viewedDiffFileIds;
+ });
+
+ it('passes the viewedDiffFileIds to the FileTree', () => {
+ createComponent(shallowMount);
+
+ return wrapper.vm.$nextTick().then(() => {
+ // Have to use $attrs['viewed-files'] because we are passing down an object
+ // and attributes('') stringifies values (e.g. [object])...
+ expect(wrapper.find(FileTree).vm.$attrs['viewed-files']).toBe(viewedDiffFileIds);
+ });
+ });
+ });
});
diff --git a/spec/frontend/diffs/mock_data/diff_file.js b/spec/frontend/diffs/mock_data/diff_file.js
index e4b2fdf6ede..c2a4424ee95 100644
--- a/spec/frontend/diffs/mock_data/diff_file.js
+++ b/spec/frontend/diffs/mock_data/diff_file.js
@@ -56,8 +56,8 @@ export default {
old_line: null,
new_line: 1,
discussions: [],
- text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
- rich_text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
meta_data: null,
},
{
@@ -66,8 +66,8 @@ export default {
old_line: null,
new_line: 2,
discussions: [],
- text: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
- rich_text: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
+ text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
meta_data: null,
},
{
@@ -76,8 +76,8 @@ export default {
old_line: 1,
new_line: 3,
discussions: [],
- text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
- rich_text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
meta_data: null,
},
{
@@ -86,8 +86,8 @@ export default {
old_line: 2,
new_line: 4,
discussions: [],
- text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
- rich_text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
+ text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
meta_data: null,
},
{
@@ -96,8 +96,38 @@ export default {
old_line: 3,
new_line: 5,
discussions: [],
- text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
- rich_text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_6',
+ type: 'old',
+ old_line: 4,
+ new_line: null,
+ discussions: [],
+ text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_7',
+ type: 'new',
+ old_line: null,
+ new_line: 5,
+ discussions: [],
+ text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_9',
+ type: 'new',
+ old_line: null,
+ new_line: 6,
+ discussions: [],
+ text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
meta_data: null,
},
{
@@ -116,43 +146,39 @@ export default {
],
parallel_diff_lines: [
{
- left: {
- type: 'empty-cell',
- },
+ left: null,
right: {
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1',
type: 'new',
old_line: null,
new_line: 1,
discussions: [],
- text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
meta_data: null,
},
},
{
- left: {
- type: 'empty-cell',
- },
+ left: null,
right: {
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2',
type: 'new',
old_line: null,
new_line: 2,
discussions: [],
- text: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
+ text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
meta_data: null,
},
},
{
left: {
- line_Code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
type: null,
old_line: 1,
new_line: 3,
discussions: [],
- text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
meta_data: null,
},
@@ -162,7 +188,7 @@ export default {
old_line: 1,
new_line: 3,
discussions: [],
- text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
meta_data: null,
},
@@ -174,7 +200,7 @@ export default {
old_line: 2,
new_line: 4,
discussions: [],
- text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
+ text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
meta_data: null,
},
@@ -184,7 +210,7 @@ export default {
old_line: 2,
new_line: 4,
discussions: [],
- text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
+ text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
meta_data: null,
},
@@ -196,7 +222,7 @@ export default {
old_line: 3,
new_line: 5,
discussions: [],
- text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
meta_data: null,
},
@@ -206,13 +232,48 @@ export default {
old_line: 3,
new_line: 5,
discussions: [],
- text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
meta_data: null,
},
},
{
left: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_6',
+ type: 'old',
+ old_line: 4,
+ new_line: null,
+ discussions: [],
+ text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ right: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_7',
+ type: 'new',
+ old_line: null,
+ new_line: 5,
+ discussions: [],
+ text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ },
+ {
+ left: null,
+ right: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_9',
+ type: 'new',
+ old_line: null,
+ new_line: 6,
+ discussions: [],
+ text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ },
+ {
+ left: {
line_code: null,
type: 'match',
old_line: null,
diff --git a/spec/frontend/diffs/mock_data/diff_metadata.js b/spec/frontend/diffs/mock_data/diff_metadata.js
index b73b29e4bc8..cfa0038c06f 100644
--- a/spec/frontend/diffs/mock_data/diff_metadata.js
+++ b/spec/frontend/diffs/mock_data/diff_metadata.js
@@ -1,6 +1,3 @@
-/* eslint-disable import/prefer-default-export */
-/* https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/20 */
-
export const diffMetadata = {
real_size: '1',
size: 1,
diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js
index 5fef35d6c5b..4f647b0cd41 100644
--- a/spec/frontend/diffs/store/actions_spec.js
+++ b/spec/frontend/diffs/store/actions_spec.js
@@ -13,7 +13,6 @@ import {
} from '~/diffs/constants';
import {
setBaseConfig,
- fetchDiffFiles,
fetchDiffFilesBatch,
fetchDiffFilesMeta,
fetchCoverageFiles,
@@ -101,7 +100,6 @@ describe('DiffsStoreActions', () => {
const projectPath = '/root/project';
const dismissEndpoint = '/-/user_callouts';
const showSuggestPopover = false;
- const useSingleDiffStyle = false;
testAction(
setBaseConfig,
@@ -113,7 +111,6 @@ describe('DiffsStoreActions', () => {
projectPath,
dismissEndpoint,
showSuggestPopover,
- useSingleDiffStyle,
},
{
endpoint: '',
@@ -123,7 +120,6 @@ describe('DiffsStoreActions', () => {
projectPath: '',
dismissEndpoint: '',
showSuggestPopover: true,
- useSingleDiffStyle: true,
},
[
{
@@ -136,7 +132,6 @@ describe('DiffsStoreActions', () => {
projectPath,
dismissEndpoint,
showSuggestPopover,
- useSingleDiffStyle,
},
},
],
@@ -146,39 +141,6 @@ describe('DiffsStoreActions', () => {
});
});
- describe('fetchDiffFiles', () => {
- it('should fetch diff files', done => {
- const endpoint = '/fetch/diff/files?view=inline&w=1';
- const mock = new MockAdapter(axios);
- const res = { diff_files: 1, merge_request_diffs: [] };
- mock.onGet(endpoint).reply(200, res);
-
- testAction(
- fetchDiffFiles,
- {},
- { endpoint, diffFiles: [], showWhitespace: false, diffViewType: 'inline' },
- [
- { type: types.SET_LOADING, payload: true },
- { type: types.SET_LOADING, payload: false },
- { type: types.SET_MERGE_REQUEST_DIFFS, payload: res.merge_request_diffs },
- { type: types.SET_DIFF_DATA, payload: res },
- ],
- [],
- () => {
- mock.restore();
- done();
- },
- );
-
- fetchDiffFiles({ state: { endpoint }, commit: () => null })
- .then(data => {
- expect(data).toEqual(res);
- done();
- })
- .catch(done.fail);
- });
- });
-
describe('fetchDiffFilesBatch', () => {
let mock;
@@ -223,16 +185,16 @@ describe('DiffsStoreActions', () => {
testAction(
fetchDiffFilesBatch,
{},
- { endpointBatch, useSingleDiffStyle: true, diffViewType: 'inline' },
+ { endpointBatch, diffViewType: 'inline' },
[
{ type: types.SET_BATCH_LOADING, payload: true },
{ type: types.SET_RETRIEVING_BATCHES, payload: true },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res1.diff_files } },
{ type: types.SET_BATCH_LOADING, payload: false },
- { type: types.UPDATE_CURRENT_DIFF_FILE_ID, payload: 'test' },
+ { type: types.VIEW_DIFF_FILE, payload: 'test' },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res2.diff_files } },
{ type: types.SET_BATCH_LOADING, payload: false },
- { type: types.UPDATE_CURRENT_DIFF_FILE_ID, payload: 'test2' },
+ { type: types.VIEW_DIFF_FILE, payload: 'test2' },
{ type: types.SET_RETRIEVING_BATCHES, payload: false },
],
[],
@@ -253,7 +215,6 @@ describe('DiffsStoreActions', () => {
commit: () => {},
state: {
endpointBatch: `${endpointBatch}?view=${otherView}`,
- useSingleDiffStyle: true,
diffViewType: viewStyle,
},
})
@@ -283,7 +244,7 @@ describe('DiffsStoreActions', () => {
testAction(
fetchDiffFilesMeta,
{},
- { endpointMetadata },
+ { endpointMetadata, diffViewType: 'inline' },
[
{ type: types.SET_LOADING, payload: true },
{ type: types.SET_LOADING, payload: false },
@@ -299,146 +260,6 @@ describe('DiffsStoreActions', () => {
});
});
- describe('when the single diff view feature flag is off', () => {
- describe('fetchDiffFiles', () => {
- it('should fetch diff files', done => {
- const endpoint = '/fetch/diff/files?w=1';
- const mock = new MockAdapter(axios);
- const res = { diff_files: 1, merge_request_diffs: [] };
- mock.onGet(endpoint).reply(200, res);
-
- testAction(
- fetchDiffFiles,
- {},
- {
- endpoint,
- diffFiles: [],
- showWhitespace: false,
- diffViewType: 'inline',
- useSingleDiffStyle: false,
- currentDiffFileId: null,
- },
- [
- { type: types.SET_LOADING, payload: true },
- { type: types.SET_LOADING, payload: false },
- { type: types.SET_MERGE_REQUEST_DIFFS, payload: res.merge_request_diffs },
- { type: types.SET_DIFF_DATA, payload: res },
- ],
- [],
- () => {
- mock.restore();
- done();
- },
- );
-
- fetchDiffFiles({ state: { endpoint }, commit: () => null })
- .then(data => {
- expect(data).toEqual(res);
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('fetchDiffFilesBatch', () => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('should fetch batch diff files', done => {
- const endpointBatch = '/fetch/diffs_batch';
- const res1 = { diff_files: [{ file_hash: 'test' }], pagination: { next_page: 2 } };
- const res2 = { diff_files: [{ file_hash: 'test2' }], pagination: {} };
- mock
- .onGet(mergeUrlParams({ per_page: DIFFS_PER_PAGE, w: '1', page: 1 }, endpointBatch))
- .reply(200, res1)
- .onGet(mergeUrlParams({ per_page: DIFFS_PER_PAGE, w: '1', page: 2 }, endpointBatch))
- .reply(200, res2);
-
- testAction(
- fetchDiffFilesBatch,
- {},
- { endpointBatch, useSingleDiffStyle: false, currentDiffFileId: null },
- [
- { type: types.SET_BATCH_LOADING, payload: true },
- { type: types.SET_RETRIEVING_BATCHES, payload: true },
- { type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res1.diff_files } },
- { type: types.SET_BATCH_LOADING, payload: false },
- { type: types.UPDATE_CURRENT_DIFF_FILE_ID, payload: 'test' },
- { type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res2.diff_files } },
- { type: types.SET_BATCH_LOADING, payload: false },
- { type: types.UPDATE_CURRENT_DIFF_FILE_ID, payload: 'test2' },
- { type: types.SET_RETRIEVING_BATCHES, payload: false },
- ],
- [],
- done,
- );
- });
-
- it.each`
- querystrings | requestUrl
- ${'?view=parallel'} | ${'/fetch/diffs_batch?view=parallel'}
- ${'?view=inline'} | ${'/fetch/diffs_batch?view=inline'}
- ${''} | ${'/fetch/diffs_batch'}
- `(
- 'should use the endpoint $requestUrl if the endpointBatch in state includes `$querystrings` as a querystring',
- ({ querystrings, requestUrl }) => {
- const endpointBatch = '/fetch/diffs_batch';
-
- fetchDiffFilesBatch({
- commit: () => {},
- state: {
- endpointBatch: `${endpointBatch}${querystrings}`,
- diffViewType: 'inline',
- },
- })
- .then(() => {
- expect(mock.history.get[0].url).toEqual(requestUrl);
- })
- .catch(() => {});
- },
- );
- });
-
- describe('fetchDiffFilesMeta', () => {
- const endpointMetadata = '/fetch/diffs_metadata.json';
- const noFilesData = { ...diffMetadata };
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- delete noFilesData.diff_files;
-
- mock.onGet(endpointMetadata).reply(200, diffMetadata);
- });
- it('should fetch diff meta information', done => {
- testAction(
- fetchDiffFilesMeta,
- {},
- { endpointMetadata, useSingleDiffStyle: false },
- [
- { type: types.SET_LOADING, payload: true },
- { type: types.SET_LOADING, payload: false },
- { type: types.SET_MERGE_REQUEST_DIFFS, payload: diffMetadata.merge_request_diffs },
- { type: types.SET_DIFF_DATA, payload: noFilesData },
- ],
- [],
- () => {
- mock.restore();
- done();
- },
- );
- });
- });
- });
-
describe('fetchCoverageFiles', () => {
let mock;
const endpointCoverage = '/fetch';
@@ -479,7 +300,7 @@ describe('DiffsStoreActions', () => {
it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => {
testAction(setHighlightedRow, 'ABC_123', {}, [
{ type: types.SET_HIGHLIGHTED_ROW, payload: 'ABC_123' },
- { type: types.UPDATE_CURRENT_DIFF_FILE_ID, payload: 'ABC' },
+ { type: types.VIEW_DIFF_FILE, payload: 'ABC' },
]);
});
});
@@ -589,7 +410,7 @@ describe('DiffsStoreActions', () => {
testAction(
assignDiscussionsToDiff,
[],
- { diffFiles: [], useSingleDiffStyle: true },
+ { diffFiles: [] },
[],
[{ type: 'setCurrentDiffFileIdFromNote', payload: '123' }],
done,
@@ -1083,7 +904,7 @@ describe('DiffsStoreActions', () => {
expect(document.location.hash).toBe('#test');
});
- it('commits UPDATE_CURRENT_DIFF_FILE_ID', () => {
+ it('commits VIEW_DIFF_FILE', () => {
const state = {
treeEntries: {
path: {
@@ -1094,7 +915,7 @@ describe('DiffsStoreActions', () => {
scrollToFile({ state, commit }, 'path');
- expect(commit).toHaveBeenCalledWith(types.UPDATE_CURRENT_DIFF_FILE_ID, 'test');
+ expect(commit).toHaveBeenCalledWith(types.VIEW_DIFF_FILE, 'test');
});
});
@@ -1592,7 +1413,7 @@ describe('DiffsStoreActions', () => {
});
describe('setCurrentDiffFileIdFromNote', () => {
- it('commits UPDATE_CURRENT_DIFF_FILE_ID', () => {
+ it('commits VIEW_DIFF_FILE', () => {
const commit = jest.fn();
const state = { diffFiles: [{ file_hash: '123' }] };
const rootGetters = {
@@ -1602,10 +1423,10 @@ describe('DiffsStoreActions', () => {
setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1');
- expect(commit).toHaveBeenCalledWith(types.UPDATE_CURRENT_DIFF_FILE_ID, '123');
+ expect(commit).toHaveBeenCalledWith(types.VIEW_DIFF_FILE, '123');
});
- it('does not commit UPDATE_CURRENT_DIFF_FILE_ID when discussion has no diff_file', () => {
+ it('does not commit VIEW_DIFF_FILE when discussion has no diff_file', () => {
const commit = jest.fn();
const state = { diffFiles: [{ file_hash: '123' }] };
const rootGetters = {
@@ -1618,7 +1439,7 @@ describe('DiffsStoreActions', () => {
expect(commit).not.toHaveBeenCalled();
});
- it('does not commit UPDATE_CURRENT_DIFF_FILE_ID when diff file does not exist', () => {
+ it('does not commit VIEW_DIFF_FILE when diff file does not exist', () => {
const commit = jest.fn();
const state = { diffFiles: [{ file_hash: '123' }] };
const rootGetters = {
@@ -1633,12 +1454,12 @@ describe('DiffsStoreActions', () => {
});
describe('navigateToDiffFileIndex', () => {
- it('commits UPDATE_CURRENT_DIFF_FILE_ID', done => {
+ it('commits VIEW_DIFF_FILE', done => {
testAction(
navigateToDiffFileIndex,
0,
{ diffFiles: [{ file_hash: '123' }] },
- [{ type: types.UPDATE_CURRENT_DIFF_FILE_ID, payload: '123' }],
+ [{ type: types.VIEW_DIFF_FILE, payload: '123' }],
[],
done,
);
diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js
index 70047899612..e1d855ae0cf 100644
--- a/spec/frontend/diffs/store/mutations_spec.js
+++ b/spec/frontend/diffs/store/mutations_spec.js
@@ -11,13 +11,11 @@ describe('DiffsStoreMutations', () => {
const state = {};
const endpoint = '/diffs/endpoint';
const projectPath = '/root/project';
- const useSingleDiffStyle = false;
- mutations[types.SET_BASE_CONFIG](state, { endpoint, projectPath, useSingleDiffStyle });
+ mutations[types.SET_BASE_CONFIG](state, { endpoint, projectPath });
expect(state.endpoint).toEqual(endpoint);
expect(state.projectPath).toEqual(projectPath);
- expect(state.useSingleDiffStyle).toEqual(useSingleDiffStyle);
});
});
@@ -70,12 +68,13 @@ describe('DiffsStoreMutations', () => {
});
describe('SET_DIFF_DATA', () => {
- it('should set diff data type properly', () => {
+ it('should not modify the existing state', () => {
const state = {
diffFiles: [
{
- ...diffFileMockData,
- parallel_diff_lines: [],
+ content_sha: diffFileMockData.content_sha,
+ file_hash: diffFileMockData.file_hash,
+ highlighted_diff_lines: [],
},
],
};
@@ -85,43 +84,7 @@ describe('DiffsStoreMutations', () => {
mutations[types.SET_DIFF_DATA](state, diffMock);
- const firstLine = state.diffFiles[0].parallel_diff_lines[0];
-
- expect(firstLine.right.text).toBeUndefined();
- expect(state.diffFiles.length).toEqual(1);
- expect(state.diffFiles[0].renderIt).toEqual(true);
- expect(state.diffFiles[0].collapsed).toEqual(false);
- });
-
- describe('given diffsBatchLoad feature flag is enabled', () => {
- beforeEach(() => {
- gon.features = { diffsBatchLoad: true };
- });
-
- afterEach(() => {
- delete gon.features;
- });
-
- it('should not modify the existing state', () => {
- const state = {
- diffFiles: [
- {
- content_sha: diffFileMockData.content_sha,
- file_hash: diffFileMockData.file_hash,
- highlighted_diff_lines: [],
- },
- ],
- };
- const diffMock = {
- diff_files: [diffFileMockData],
- };
-
- mutations[types.SET_DIFF_DATA](state, diffMock);
-
- // If the batch load is enabled, there shouldn't be any processing
- // done on the existing state object, so we shouldn't have this.
- expect(state.diffFiles[0].parallel_diff_lines).toBeUndefined();
- });
+ expect(state.diffFiles[0].parallel_diff_lines).toBeUndefined();
});
});
@@ -682,6 +645,36 @@ describe('DiffsStoreMutations', () => {
expect(state.diffFiles[0].highlighted_diff_lines[0].discussions).toHaveLength(1);
expect(state.diffFiles[0].highlighted_diff_lines[0].discussions[0].id).toBe(1);
});
+
+ it('should add discussion to file', () => {
+ const state = {
+ latestDiff: true,
+ diffFiles: [
+ {
+ file_hash: 'ABC',
+ discussions: [],
+ parallel_diff_lines: [],
+ highlighted_diff_lines: [],
+ },
+ ],
+ };
+ const discussion = {
+ id: 1,
+ line_code: 'ABC_1',
+ diff_discussion: true,
+ resolvable: true,
+ diff_file: {
+ file_hash: state.diffFiles[0].file_hash,
+ },
+ };
+
+ mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
+ discussion,
+ diffPositionByLineCode: null,
+ });
+
+ expect(state.diffFiles[0].discussions.length).toEqual(1);
+ });
});
describe('REMOVE_LINE_DISCUSSIONS', () => {
@@ -774,11 +767,11 @@ describe('DiffsStoreMutations', () => {
});
});
- describe('UPDATE_CURRENT_DIFF_FILE_ID', () => {
+ describe('VIEW_DIFF_FILE', () => {
it('updates currentDiffFileId', () => {
const state = createState();
- mutations[types.UPDATE_CURRENT_DIFF_FILE_ID](state, 'somefileid');
+ mutations[types.VIEW_DIFF_FILE](state, 'somefileid');
expect(state.currentDiffFileId).toBe('somefileid');
});
diff --git a/spec/frontend/diffs/store/utils_spec.js b/spec/frontend/diffs/store/utils_spec.js
index 62c82468ea0..39a482c85ae 100644
--- a/spec/frontend/diffs/store/utils_spec.js
+++ b/spec/frontend/diffs/store/utils_spec.js
@@ -1167,4 +1167,59 @@ describe('DiffsStoreUtils', () => {
expect(utils.getDefaultWhitespace(undefined, '0')).toBe(true);
});
});
+
+ describe('isAdded', () => {
+ it.each`
+ type | expected
+ ${'new'} | ${true}
+ ${'new-nonewline'} | ${true}
+ ${'old'} | ${false}
+ `('returns $expected when type is $type', ({ type, expected }) => {
+ expect(utils.isAdded({ type })).toBe(expected);
+ });
+ });
+
+ describe('isRemoved', () => {
+ it.each`
+ type | expected
+ ${'old'} | ${true}
+ ${'old-nonewline'} | ${true}
+ ${'new'} | ${false}
+ `('returns $expected when type is $type', ({ type, expected }) => {
+ expect(utils.isRemoved({ type })).toBe(expected);
+ });
+ });
+
+ describe('isUnchanged', () => {
+ it.each`
+ type | expected
+ ${null} | ${true}
+ ${'new'} | ${false}
+ ${'old'} | ${false}
+ `('returns $expected when type is $type', ({ type, expected }) => {
+ expect(utils.isUnchanged({ type })).toBe(expected);
+ });
+ });
+
+ describe('isMeta', () => {
+ it.each`
+ type | expected
+ ${'match'} | ${true}
+ ${'new-nonewline'} | ${true}
+ ${'old-nonewline'} | ${true}
+ ${'new'} | ${false}
+ `('returns $expected when type is $type', ({ type, expected }) => {
+ expect(utils.isMeta({ type })).toBe(expected);
+ });
+ });
+
+ describe('parallelizeDiffLines', () => {
+ it('converts inline diff lines to parallel diff lines', () => {
+ const file = getDiffFileMock();
+
+ expect(utils.parallelizeDiffLines(file.highlighted_diff_lines)).toEqual(
+ file.parallel_diff_lines,
+ );
+ });
+ });
});