diff options
Diffstat (limited to 'spec/frontend/diffs')
-rw-r--r-- | spec/frontend/diffs/components/app_spec.js | 1 | ||||
-rw-r--r-- | spec/frontend/diffs/components/compare_versions_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/diffs/components/diff_expansion_cell_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/diffs/components/diff_file_spec.js | 22 | ||||
-rw-r--r-- | spec/frontend/diffs/components/diff_stats_spec.js | 104 | ||||
-rw-r--r-- | spec/frontend/diffs/components/diff_table_cell_spec.js | 56 | ||||
-rw-r--r-- | spec/frontend/diffs/components/inline_diff_view_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/diffs/components/no_changes_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/diffs/components/parallel_diff_view_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/diffs/components/tree_list_spec.js | 1 | ||||
-rw-r--r-- | spec/frontend/diffs/diff_file_spec.js | 60 | ||||
-rw-r--r-- | spec/frontend/diffs/store/actions_spec.js | 27 | ||||
-rw-r--r-- | spec/frontend/diffs/store/mutations_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/diffs/store/utils_spec.js | 55 |
14 files changed, 295 insertions, 43 deletions
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js index b7f03f35dfb..ac046ddc203 100644 --- a/spec/frontend/diffs/components/app_spec.js +++ b/spec/frontend/diffs/components/app_spec.js @@ -41,6 +41,7 @@ describe('diffs/components/app', () => { store = createDiffsStore(); store.state.diffs.isLoading = false; + store.state.diffs.isTreeLoaded = true; extendStore(store); diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js index 7f69a6344c1..7fdbc791589 100644 --- a/spec/frontend/diffs/components/compare_versions_spec.js +++ b/spec/frontend/diffs/components/compare_versions_spec.js @@ -30,7 +30,7 @@ describe('CompareVersions', () => { store, propsData: { mergeRequestDiffs: diffsMockData, - diffFilesLength: 0, + diffFilesCountText: null, ...props, }, }); diff --git a/spec/frontend/diffs/components/diff_expansion_cell_spec.js b/spec/frontend/diffs/components/diff_expansion_cell_spec.js index ef2e0dfe59b..b8aca4ad86b 100644 --- a/spec/frontend/diffs/components/diff_expansion_cell_spec.js +++ b/spec/frontend/diffs/components/diff_expansion_cell_spec.js @@ -1,12 +1,12 @@ import Vue from 'vue'; import { cloneDeep } from 'lodash'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; +import { getByText } from '@testing-library/dom'; import { createStore } from '~/mr_notes/stores'; import DiffExpansionCell from '~/diffs/components/diff_expansion_cell.vue'; import { getPreviousLineIndex } from '~/diffs/store/utils'; import { INLINE_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE } from '~/diffs/constants'; import diffFileMockData from '../mock_data/diff_file'; -import { getByText } from '@testing-library/dom'; const EXPAND_UP_CLASS = '.js-unfold'; const EXPAND_DOWN_CLASS = '.js-unfold-down'; diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js index 7e154d76f45..ead8bd79cdb 100644 --- a/spec/frontend/diffs/components/diff_file_spec.js +++ b/spec/frontend/diffs/components/diff_file_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; -import { createStore } from '~/mr_notes/stores'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; import { mockTracking, triggerEvent } from 'helpers/tracking_helper'; +import { createStore } from '~/mr_notes/stores'; import DiffFileComponent from '~/diffs/components/diff_file.vue'; import { diffViewerModes, diffViewerErrors } from '~/ide/constants'; import diffFileMockDataReadable from '../mock_data/diff_file'; @@ -128,6 +128,26 @@ describe('DiffFile', () => { }); }); + 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 = {}; + + done(); + }); + }); + it('should be collapsed for renamed files', done => { vm.renderIt = true; vm.isCollapsed = false; diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 5956b478019..7a083fb6bde 100644 --- a/spec/frontend/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js @@ -2,53 +2,97 @@ import { shallowMount } from '@vue/test-utils'; 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; +const DIFF_FILES_COUNT = '300'; +const DIFF_FILES_COUNT_TRUNCATED = '300+'; + describe('diff_stats', () => { - it('does not render a group if diffFileLengths is empty', () => { - const wrapper = shallowMount(DiffStats, { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(DiffStats, { propsData: { - addedLines: 1, - removedLines: 2, + addedLines: TEST_ADDED_LINES, + removedLines: TEST_REMOVED_LINES, + ...props, }, }); - const groups = wrapper.findAll('.diff-stats-group'); + }; - expect(groups.length).toBe(2); - }); + describe('diff stats group', () => { + const findDiffStatsGroup = () => wrapper.findAll('.diff-stats-group'); - it('does not render a group if diffFileLengths is not a number', () => { - const wrapper = shallowMount(DiffStats, { - propsData: { - addedLines: 1, - removedLines: 2, - diffFilesLength: Number.NaN, - }, + it('is not rendered if diffFilesCountText is empty', () => { + createComponent(); + + expect(findDiffStatsGroup().length).toBe(2); }); - const groups = wrapper.findAll('.diff-stats-group'); - expect(groups.length).toBe(2); - }); + it('is not rendered if diffFilesCountText is not a number', () => { + createComponent({ + diffFilesCountText: null, + }); - it('shows amount of files changed, lines added and lines removed when passed all props', () => { - const wrapper = shallowMount(DiffStats, { - propsData: { - addedLines: 100, - removedLines: 200, - diffFilesLength: 300, - }, + expect(findDiffStatsGroup().length).toBe(2); }); + }); + describe('line changes', () => { const findFileLine = name => wrapper.find(name); + + it('shows the amount of lines added', () => { + expect(findFileLine('.js-file-addition-line').text()).toBe(TEST_ADDED_LINES.toString()); + }); + + it('shows the amount of lines removed', () => { + expect(findFileLine('.js-file-deletion-line').text()).toBe(TEST_REMOVED_LINES.toString()); + }); + }); + + describe('files changes', () => { const findIcon = name => wrapper .findAll(Icon) .filter(c => c.attributes('name') === name) .at(0).element.parentNode; - const additions = findFileLine('.js-file-addition-line'); - const deletions = findFileLine('.js-file-deletion-line'); - const filesChanged = findIcon('doc-code'); - expect(additions.text()).toBe('100'); - expect(deletions.text()).toBe('200'); - expect(filesChanged.textContent).toContain('300'); + it('shows amount of file changed with plural "files" when 0 files has changed', () => { + const oneFileChanged = '0'; + + createComponent({ + diffFilesCountText: oneFileChanged, + }); + + expect(findIcon('doc-code').textContent.trim()).toBe(`${oneFileChanged} files`); + }); + + it('shows amount of file changed with singular "file" when 1 file is changed', () => { + const oneFileChanged = '1'; + + createComponent({ + diffFilesCountText: oneFileChanged, + }); + + expect(findIcon('doc-code').textContent.trim()).toBe(`${oneFileChanged} file`); + }); + + it('shows amount of files change with plural "files" when multiple files are changed', () => { + createComponent({ + diffFilesCountText: DIFF_FILES_COUNT, + }); + + expect(findIcon('doc-code').textContent.trim()).toContain(`${DIFF_FILES_COUNT} files`); + }); + + it('shows amount of files change with plural "files" when files changed is truncated', () => { + createComponent({ + diffFilesCountText: DIFF_FILES_COUNT_TRUNCATED, + }); + + expect(findIcon('doc-code').textContent.trim()).toContain( + `${DIFF_FILES_COUNT_TRUNCATED} files`, + ); + }); }); }); diff --git a/spec/frontend/diffs/components/diff_table_cell_spec.js b/spec/frontend/diffs/components/diff_table_cell_spec.js index 9693fe68b57..02f5c27eecb 100644 --- a/spec/frontend/diffs/components/diff_table_cell_spec.js +++ b/spec/frontend/diffs/components/diff_table_cell_spec.js @@ -1,10 +1,10 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; +import { TEST_HOST } from 'helpers/test_constants'; import DiffTableCell from '~/diffs/components/diff_table_cell.vue'; import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue'; import { LINE_POSITION_RIGHT } from '~/diffs/constants'; import { createStore } from '~/mr_notes/stores'; -import { TEST_HOST } from 'helpers/test_constants'; import discussionsMockData from '../mock_data/diff_discussions'; import diffFileMockData from '../mock_data/diff_file'; @@ -18,6 +18,12 @@ const TEST_LINE_CODE = 'LC_42'; const TEST_FILE_HASH = diffFileMockData.file_hash; describe('DiffTableCell', () => { + 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'; + let wrapper; let line; let store; @@ -67,6 +73,7 @@ describe('DiffTableCell', () => { const findTd = () => wrapper.find({ ref: 'td' }); const findNoteButton = () => wrapper.find({ ref: 'addDiffNoteButton' }); const findLineNumber = () => wrapper.find({ ref: 'lineNumberRef' }); + const findTooltip = () => wrapper.find({ ref: 'addNoteTooltip' }); const findAvatars = () => wrapper.find(DiffGutterAvatars); describe('td', () => { @@ -134,6 +141,53 @@ describe('DiffTableCell', () => { }); }, ); + + it.each` + disabled | commentsDisabled + ${'disabled'} | ${true} + ${undefined} | ${false} + `( + 'has attribute disabled=$disabled when the outer component has prop commentsDisabled=$commentsDisabled', + ({ disabled, commentsDisabled }) => { + line.commentsDisabled = commentsDisabled; + + createComponent({ + showCommentButton: true, + isHover: true, + }); + + wrapper.setData({ isCommentButtonRendered: true }); + + return wrapper.vm.$nextTick().then(() => { + expect(findNoteButton().attributes('disabled')).toBe(disabled); + }); + }, + ); + + 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 }) => { + line.commentsDisabled = commentsDisabled; + + createComponent({ + showCommentButton: true, + isHover: true, + }); + + wrapper.setData({ isCommentButtonRendered: true }); + + return wrapper.vm.$nextTick().then(() => { + expect(findTooltip().attributes('title')).toBe(tooltip); + }); + }, + ); }); describe('line number', () => { diff --git a/spec/frontend/diffs/components/inline_diff_view_spec.js b/spec/frontend/diffs/components/inline_diff_view_spec.js index eeef8e5a7b0..6c37f86658e 100644 --- a/spec/frontend/diffs/components/inline_diff_view_spec.js +++ b/spec/frontend/diffs/components/inline_diff_view_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import '~/behaviors/markdown/render_gfm'; -import { createStore } from '~/mr_notes/stores'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; +import { createStore } from '~/mr_notes/stores'; import InlineDiffView from '~/diffs/components/inline_diff_view.vue'; import diffFileMockData from '../mock_data/diff_file'; import discussionsMockData from '../mock_data/diff_discussions'; diff --git a/spec/frontend/diffs/components/no_changes_spec.js b/spec/frontend/diffs/components/no_changes_spec.js index 2eca97a47fd..2795c68b4ee 100644 --- a/spec/frontend/diffs/components/no_changes_spec.js +++ b/spec/frontend/diffs/components/no_changes_spec.js @@ -1,8 +1,8 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; +import { GlButton } from '@gitlab/ui'; import { createStore } from '~/mr_notes/stores'; import NoChanges from '~/diffs/components/no_changes.vue'; -import { GlButton } from '@gitlab/ui'; describe('Diff no changes empty state', () => { let vm; diff --git a/spec/frontend/diffs/components/parallel_diff_view_spec.js b/spec/frontend/diffs/components/parallel_diff_view_spec.js index 30231f0ba71..cb1a47f60d5 100644 --- a/spec/frontend/diffs/components/parallel_diff_view_spec.js +++ b/spec/frontend/diffs/components/parallel_diff_view_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import { createStore } from '~/mr_notes/stores'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; +import { createStore } from '~/mr_notes/stores'; import ParallelDiffView from '~/diffs/components/parallel_diff_view.vue'; import * as constants from '~/diffs/constants'; import diffFileMockData from '../mock_data/diff_file'; diff --git a/spec/frontend/diffs/components/tree_list_spec.js b/spec/frontend/diffs/components/tree_list_spec.js index f78c5f25ee7..14cb2a17aec 100644 --- a/spec/frontend/diffs/components/tree_list_spec.js +++ b/spec/frontend/diffs/components/tree_list_spec.js @@ -17,6 +17,7 @@ describe('Diffs tree list component', () => { }); // Setup initial state + store.state.diffs.isTreeLoaded = true; store.state.diffs.diffFiles.push('test'); store.state.diffs = { addedLines: 10, diff --git a/spec/frontend/diffs/diff_file_spec.js b/spec/frontend/diffs/diff_file_spec.js new file mode 100644 index 00000000000..5d74760ef66 --- /dev/null +++ b/spec/frontend/diffs/diff_file_spec.js @@ -0,0 +1,60 @@ +import { prepareRawDiffFile } from '~/diffs/diff_file'; + +const DIFF_FILES = [ + { + file_hash: 'ABC', // This file is just a normal file + }, + { + file_hash: 'DEF', // This file replaces a symlink + a_mode: '0', + b_mode: '0755', + }, + { + file_hash: 'DEF', // This symlink is replaced by a file + a_mode: '120000', + b_mode: '0', + }, + { + file_hash: 'GHI', // This symlink replaces a file + a_mode: '0', + b_mode: '120000', + }, + { + file_hash: 'GHI', // This file is replaced by a symlink + a_mode: '0755', + b_mode: '0', + }, +]; + +function makeBrokenSymlinkObject(replaced, wasSymbolic, isSymbolic, wasReal, isReal) { + return { + replaced, + wasSymbolic, + isSymbolic, + wasReal, + isReal, + }; +} + +describe('diff_file utilities', () => { + describe('prepareRawDiffFile', () => { + it.each` + fileIndex | description | brokenSymlink + ${0} | ${'a file that is not symlink-adjacent'} | ${false} + ${1} | ${'a file that replaces a symlink'} | ${makeBrokenSymlinkObject(false, false, false, false, true)} + ${2} | ${'a symlink that is replaced by a file'} | ${makeBrokenSymlinkObject(true, true, false, false, false)} + ${3} | ${'a symlink that replaces a file'} | ${makeBrokenSymlinkObject(false, false, true, false, false)} + ${4} | ${'a file that is replaced by a symlink'} | ${makeBrokenSymlinkObject(true, false, false, true, false)} + `( + 'properly marks $description with the correct .brokenSymlink value', + ({ fileIndex, brokenSymlink }) => { + const preppedRaw = prepareRawDiffFile({ + file: DIFF_FILES[fileIndex], + allFiles: DIFF_FILES, + }); + + expect(preppedRaw.brokenSymlink).toStrictEqual(brokenSymlink); + }, + ); + }); +}); diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js index fc5e39357ca..5fef35d6c5b 100644 --- a/spec/frontend/diffs/store/actions_spec.js +++ b/spec/frontend/diffs/store/actions_spec.js @@ -1,6 +1,8 @@ import MockAdapter from 'axios-mock-adapter'; import Cookies from 'js-cookie'; import mockDiffFile from 'jest/diffs/mock_data/diff_file'; +import { useLocalStorageSpy } from 'helpers/local_storage_helper'; +import { TEST_HOST } from 'jest/helpers/test_constants'; import { DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE, @@ -56,12 +58,10 @@ import testAction from '../../helpers/vuex_action_helper'; import * as utils from '~/diffs/store/utils'; import * as commonUtils from '~/lib/utils/common_utils'; import { mergeUrlParams } from '~/lib/utils/url_utility'; -import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import { diffMetadata } from '../mock_data/diff_metadata'; -import createFlash from '~/flash'; -import { TEST_HOST } from 'jest/helpers/test_constants'; +import { deprecatedCreateFlash as createFlash } from '~/flash'; -jest.mock('~/flash', () => jest.fn()); +jest.mock('~/flash'); describe('DiffsStoreActions', () => { useLocalStorageSpy(); @@ -1594,24 +1594,39 @@ describe('DiffsStoreActions', () => { describe('setCurrentDiffFileIdFromNote', () => { it('commits UPDATE_CURRENT_DIFF_FILE_ID', () => { const commit = jest.fn(); + const state = { diffFiles: [{ file_hash: '123' }] }; const rootGetters = { getDiscussion: () => ({ diff_file: { file_hash: '123' } }), notesById: { '1': { discussion_id: '2' } }, }; - setCurrentDiffFileIdFromNote({ commit, rootGetters }, '1'); + setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1'); expect(commit).toHaveBeenCalledWith(types.UPDATE_CURRENT_DIFF_FILE_ID, '123'); }); it('does not commit UPDATE_CURRENT_DIFF_FILE_ID when discussion has no diff_file', () => { const commit = jest.fn(); + const state = { diffFiles: [{ file_hash: '123' }] }; const rootGetters = { getDiscussion: () => ({ id: '1' }), notesById: { '1': { discussion_id: '2' } }, }; - setCurrentDiffFileIdFromNote({ commit, rootGetters }, '1'); + setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1'); + + expect(commit).not.toHaveBeenCalled(); + }); + + it('does not commit UPDATE_CURRENT_DIFF_FILE_ID when diff file does not exist', () => { + const commit = jest.fn(); + const state = { diffFiles: [{ file_hash: '123' }] }; + const rootGetters = { + getDiscussion: () => ({ diff_file: { file_hash: '124' } }), + notesById: { '1': { discussion_id: '2' } }, + }; + + setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1'); expect(commit).not.toHaveBeenCalled(); }); diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js index c24d406fef3..70047899612 100644 --- a/spec/frontend/diffs/store/mutations_spec.js +++ b/spec/frontend/diffs/store/mutations_spec.js @@ -830,6 +830,7 @@ describe('DiffsStoreMutations', () => { const state = { treeEntries: {}, tree: [], + isTreeLoaded: false, }; mutations[types.SET_TREE_DATA](state, { @@ -844,6 +845,7 @@ describe('DiffsStoreMutations', () => { }); expect(state.tree).toEqual(['tree']); + expect(state.isTreeLoaded).toEqual(true); }); }); diff --git a/spec/frontend/diffs/store/utils_spec.js b/spec/frontend/diffs/store/utils_spec.js index d87619e1e3c..62c82468ea0 100644 --- a/spec/frontend/diffs/store/utils_spec.js +++ b/spec/frontend/diffs/store/utils_spec.js @@ -20,6 +20,14 @@ import { noteableDataMock } from '../../notes/mock_data'; const getDiffFileMock = () => JSON.parse(JSON.stringify(diffFileMockData)); const getDiffMetadataMock = () => JSON.parse(JSON.stringify(diffMetadata)); +function extractLinesFromFile(file) { + const unpackedParallel = file.parallel_diff_lines + .flatMap(({ left, right }) => [left, right]) + .filter(Boolean); + + return [...file.highlighted_diff_lines, ...unpackedParallel]; +} + describe('DiffsStoreUtils', () => { describe('findDiffFile', () => { const files = [{ file_hash: 1, name: 'one' }]; @@ -429,6 +437,28 @@ describe('DiffsStoreUtils', () => { expect(preppedLine.right).toEqual(correctLine); expect(preppedLine.line_code).toEqual(correctLine.line_code); }); + + it.each` + brokenSymlink + ${false} + ${{}} + ${'anything except `false`'} + `( + "properly assigns each line's `commentsDisabled` as the same value as the parent file's `brokenSymlink` value (`$brokenSymlink`)", + ({ brokenSymlink }) => { + preppedLine = utils.prepareLineForRenamedFile({ + diffViewType: INLINE_DIFF_VIEW_TYPE, + line: sourceLine, + index: lineIndex, + diffFile: { + ...diffFile, + brokenSymlink, + }, + }); + + expect(preppedLine.commentsDisabled).toStrictEqual(brokenSymlink); + }, + ); }); describe('prepareDiffData', () => { @@ -541,6 +571,25 @@ describe('DiffsStoreUtils', () => { }), ]); }); + + it('adds the `.brokenSymlink` property to each diff file', () => { + preparedDiff.diff_files.forEach(file => { + expect(file).toEqual(expect.objectContaining({ brokenSymlink: false })); + }); + }); + + it("copies the diff file's `.brokenSymlink` value to each of that file's child lines", () => { + const lines = [ + ...preparedDiff.diff_files, + ...splitInlineDiff.diff_files, + ...splitParallelDiff.diff_files, + ...completedDiff.diff_files, + ].flatMap(file => extractLinesFromFile(file)); + + lines.forEach(line => { + expect(line.commentsDisabled).toBe(false); + }); + }); }); describe('for diff metadata', () => { @@ -603,6 +652,12 @@ describe('DiffsStoreUtils', () => { }, ]); }); + + it('adds the `.brokenSymlink` property to each meta diff file', () => { + preparedDiffFiles.forEach(file => { + expect(file).toMatchObject({ brokenSymlink: false }); + }); + }); }); }); |