diff --git a/app/assets/javascripts/behaviors/shortcuts/keybindings.js b/app/assets/javascripts/behaviors/shortcuts/keybindings.js index 8aa7db18c7ffdd96c9824c2ef0524b1f12bcbf55..a60395e5b2e99d4427a2425a4d30ffbe71699b70 100644 --- a/app/assets/javascripts/behaviors/shortcuts/keybindings.js +++ b/app/assets/javascripts/behaviors/shortcuts/keybindings.js @@ -487,6 +487,19 @@ export const MR_COPY_SOURCE_BRANCH_NAME = { defaultKeys: ['b'], }; +export const MR_EXPAND_ALL_FILES = { + id: 'mergeRequests.expandAllFiles', + description: __('Expand all files'), + defaultKeys: [';'], +}; + +export const MR_COLLAPSE_ALL_FILES = { + id: 'mergeRequests.collapseAllFiles', + description: __('Collapse all files'), + // eslint-disable-next-line @gitlab/require-i18n-strings + defaultKeys: ['shift+;'], +}; + export const MR_COMMITS_NEXT_COMMIT = { id: 'mergeRequestCommits.nextCommit', description: __('Next commit'), diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 81fa13235d1678e77e3e4ef09ef8edcfa4c07ecc..61eb9c55ff46bfe5010aafe23a4a326d91bee600 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -16,7 +16,6 @@ import { } from '~/behaviors/shortcuts/keybindings'; import { createAlert } from '~/alert'; import { InternalEvents } from '~/tracking'; -import { isSingleViewStyle } from '~/helpers/diffs_helper'; import { helpPagePath } from '~/helpers/help_page_helper'; import { parseBoolean, handleLocationHash } from '~/lib/utils/common_utils'; import { BV_HIDE_TOOLTIP, DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; @@ -60,6 +59,7 @@ import HiddenFilesWarning from './hidden_files_warning.vue'; import NoChanges from './no_changes.vue'; import VirtualScrollerScrollSync from './virtual_scroller_scroll_sync'; import DiffsFileTree from './diffs_file_tree.vue'; +import DiffAppControls from './diff_app_controls.vue'; import getMRCodequalityAndSecurityReports from './graphql/get_mr_codequality_and_security_reports.query.graphql'; export const FINDINGS_STATUS_PARSED = 'PARSED'; @@ -71,6 +71,7 @@ export default { FINDINGS_STATUS_PARSED, FINDINGS_STATUS_ERROR, components: { + DiffAppControls, DiffsFileTree, FindingsDrawer, DynamicScroller, @@ -238,6 +239,8 @@ export default { 'targetBranchName', 'branchName', 'showTreeList', + 'addedLines', + 'removedLines', ]), ...mapGetters('diffs', [ 'whichCollapsedTypes', @@ -317,6 +320,9 @@ export default { }; return throttle(hide, 100); }, + hasChanges() { + return this.diffFiles.length > 0; + }, }, watch: { commit(newCommit, oldCommit) { @@ -450,6 +456,8 @@ export default { 'disableVirtualScroller', 'fetchLinkedFile', 'toggleTreeList', + 'expandAllFiles', + 'collapseAllFiles', ]), ...mapActions('findingsDrawer', ['setDrawer']), closeDrawer() { @@ -530,12 +538,6 @@ export default { refetchDiffData({ refetchMeta = true } = {}) { this.fetchData({ toggleTree: false, fetchMeta: refetchMeta }); }, - needsReload() { - return this.diffFiles.length && isSingleViewStyle(this.diffFiles[0]); - }, - needsFirstLoad() { - return !this.diffFiles.length; - }, fetchData({ toggleTree = true, fetchMeta = true } = {}) { if (this.linkedFileUrl && this.linkedFileStatus !== 'loaded') { this.linkedFileStatus = 'loading'; @@ -749,7 +751,18 @@ export default {
- +
+ + +
diff --git a/app/assets/javascripts/diffs/components/diff_app_controls.vue b/app/assets/javascripts/diffs/components/diff_app_controls.vue new file mode 100644 index 0000000000000000000000000000000000000000..1111e820424b5469c960da3677b7fea40a0511ef --- /dev/null +++ b/app/assets/javascripts/diffs/components/diff_app_controls.vue @@ -0,0 +1,109 @@ + + + diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue index 35e71714a82fe663b203205588292e0898d57f20..baab0a86ad760fb4d00db3d316cc9c468d216fa9 100644 --- a/app/assets/javascripts/diffs/components/diff_stats.vue +++ b/app/assets/javascripts/diffs/components/diff_stats.vue @@ -20,7 +20,7 @@ export default { type: Number, required: true, }, - diffFilesCountText: { + diffsCount: { type: String, required: false, default: null, @@ -28,13 +28,13 @@ export default { }, computed: { diffFilesLength() { - return parseInt(this.diffFilesCountText, 10); + return parseInt(this.diffsCount, 10); }, filesText() { return n__('file', 'files', this.diffFilesLength); }, isCompareVersionsHeader() { - return Boolean(this.diffFilesCountText); + return Boolean(this.diffsCount); }, hasDiffFiles() { return isNumber(this.diffFilesLength) && this.diffFilesLength >= 0; @@ -63,7 +63,7 @@ export default {
- {{ diffFilesCountText }} {{ filesText }} + {{ diffsCount }} {{ filesText }}
{ export const toggleAllDiffDiscussions = ({ commit, getters }) => { commit(types.SET_EXPAND_ALL_DIFF_DISCUSSIONS, !getters.allDiffDiscussionsExpanded); }; + +export const expandAllFiles = ({ commit }) => { + commit(types.SET_COLLAPSED_STATE_FOR_ALL_FILES, { collapsed: false }); +}; + +export const collapseAllFiles = ({ commit }) => { + commit(types.SET_COLLAPSED_STATE_FOR_ALL_FILES, { collapsed: true }); +}; diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index a9e5a47c7bb1155fc7c69e3a485f56f4b8312bb7..7b02ff49e0bcb545839589e9fdfe2f5009e614cb 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -59,3 +59,5 @@ export const DISABLE_VIRTUAL_SCROLLING = 'DISABLE_VIRTUAL_SCROLLING'; export const TOGGLE_FILE_COMMENT_FORM = 'TOGGLE_FILE_COMMENT_FORM'; export const SET_FILE_COMMENT_FORM = 'SET_FILE_COMMENT_FORM'; export const ADD_DRAFT_TO_FILE = 'ADD_DRAFT_TO_FILE'; + +export const SET_COLLAPSED_STATE_FOR_ALL_FILES = 'SET_COLLAPSED_STATE_FOR_ALL_FILES'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 712d889781d345e21f713f9da807c4398a76a750..65771f6b568f04ee9205076ecb82009a7bd48cd6 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -427,4 +427,12 @@ export default { [types.SET_LINKED_FILE_HASH](state, fileHash) { state.linkedFileHash = fileHash; }, + [types.SET_COLLAPSED_STATE_FOR_ALL_FILES](state, { collapsed }) { + state.diffFiles.forEach((file) => { + const { viewer } = file; + if (!viewer) return; + viewer.automaticallyCollapsed = false; + viewer.manuallyCollapsed = collapsed; + }); + }, }; diff --git a/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js b/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js index a134a7273b2dfae96b86cadb1c2cce1c2907af10..a974ff6ca2aae3ce81e5faa05828e9bb37a2a8be 100644 --- a/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js +++ b/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js @@ -1122,3 +1122,11 @@ export function unlinkFile() { export function toggleAllDiffDiscussions() { this[types.SET_EXPAND_ALL_DIFF_DISCUSSIONS](!this.allDiffDiscussionsExpanded); } + +export function expandAllFiles() { + this[types.SET_COLLAPSED_STATE_FOR_ALL_FILES]({ collapsed: false }); +} + +export function collapseAllFiles() { + this[types.SET_COLLAPSED_STATE_FOR_ALL_FILES]({ collapsed: true }); +} diff --git a/app/assets/javascripts/diffs/stores/legacy_diffs/mutations.js b/app/assets/javascripts/diffs/stores/legacy_diffs/mutations.js index d56b24dd9d6761cdf0b685983bb1326926274c76..44c9ee9b79f985b5eec90a6d8170f8b82c13cced 100644 --- a/app/assets/javascripts/diffs/stores/legacy_diffs/mutations.js +++ b/app/assets/javascripts/diffs/stores/legacy_diffs/mutations.js @@ -420,4 +420,12 @@ export default { [types.SET_LINKED_FILE_HASH](fileHash) { this.linkedFileHash = fileHash; }, + [types.SET_COLLAPSED_STATE_FOR_ALL_FILES]({ collapsed }) { + this.diffFiles.forEach((file) => { + const { viewer } = file; + if (!viewer) return; + viewer.automaticallyCollapsed = false; + viewer.manuallyCollapsed = collapsed; + }); + }, }; diff --git a/app/assets/javascripts/helpers/diffs_helper.js b/app/assets/javascripts/helpers/diffs_helper.js index e733b3109f352bf68d7718ced56a485c14e4adf3..b67a49c577e5975c436fc91b73aad9ce3e3f32e3 100644 --- a/app/assets/javascripts/helpers/diffs_helper.js +++ b/app/assets/javascripts/helpers/diffs_helper.js @@ -6,10 +6,6 @@ export function hasParallelLines(diffFile) { return diffFile?.parallel_diff_lines?.length > 0; } -export function isSingleViewStyle(diffFile) { - return !hasParallelLines(diffFile) || !hasInlineLines(diffFile); -} - export function hasDiff(diffFile) { return hasInlineLines(diffFile) || hasParallelLines(diffFile); } diff --git a/ee/spec/frontend/diffs/components/app_spec.js b/ee/spec/frontend/diffs/components/app_spec.js index 0a123f9c541974e3475e5695a4f59f4a133df35d..242402f4c0d8dcdd7c5918394c6f6912c5b80c68 100644 --- a/ee/spec/frontend/diffs/components/app_spec.js +++ b/ee/spec/frontend/diffs/components/app_spec.js @@ -39,6 +39,7 @@ describe('diffs/components/app', () => { }, }; store.getters['findingsDrawer/activeDrawer'] = {}; + store.getters['diffs/diffFiles'] = []; store.getters['diffs/flatBlobsList'] = []; store.getters['diffs/isBatchLoading'] = false; store.getters['diffs/isBatchLoadingError'] = false; diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7e288299ca96975b7550f1dabab80bb510d2ed83..99699cfdcc842a6ea87f7324346563eee1b99b54 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -13437,6 +13437,9 @@ msgstr "" msgid "Collapse %{section} merge requests" msgstr "" +msgid "Collapse all files" +msgstr "" + msgid "Collapse eligible approvers" msgstr "" diff --git a/spec/features/merge_request/user_comments_on_whitespace_hidden_diff_spec.rb b/spec/features/merge_request/user_comments_on_whitespace_hidden_diff_spec.rb index 7c5d448e82cd13205bb98e24baacfa1e7784a00f..0ce42d977e7af768105cb611db4551520cf64a35 100644 --- a/spec/features/merge_request/user_comments_on_whitespace_hidden_diff_spec.rb +++ b/spec/features/merge_request/user_comments_on_whitespace_hidden_diff_spec.rb @@ -130,7 +130,7 @@ context 'when commenting on collapsed line combinations that are not present in the real diff' do before do - find_all('[data-testid="expand-icon"]').first.click + find_all('[aria-label="Expand all lines"]').first.click click_diff_line( find_by_scrolling('div[data-path="files/js/breadcrumbs.js"] .left-side a[data-linenumber="15"]') diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js index 9f41a3e05ad86875494eea69ac945298b5a571d3..8ecbff0571b8a726174c58b4c3a81fbd6ff4f280 100644 --- a/spec/frontend/diffs/components/app_spec.js +++ b/spec/frontend/diffs/components/app_spec.js @@ -18,6 +18,7 @@ import DiffFile from '~/diffs/components/diff_file.vue'; import NoChanges from '~/diffs/components/no_changes.vue'; import FindingsDrawer from '~/diffs/components/shared/findings_drawer.vue'; import DiffsFileTree from '~/diffs/components/diffs_file_tree.vue'; +import DiffAppControls from '~/diffs/components/diff_app_controls.vue'; import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue'; import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue'; @@ -39,7 +40,6 @@ import { diffMetadata } from 'jest/diffs/mock_data/diff_metadata'; import createDiffsStore from '../create_diffs_store'; import diffsMockData from '../mock_data/merge_request_diffs'; -const mergeRequestDiff = { version_index: 1 }; const TEST_ENDPOINT = `${TEST_HOST}/diff/endpoint`; const COMMIT_URL = `${TEST_HOST}/COMMIT/OLD`; const UPDATED_COMMIT_URL = `${TEST_HOST}/COMMIT/NEW`; @@ -68,7 +68,7 @@ describe('diffs/components/app', () => { provisions = {}, baseConfig = {}, actions = {}, - }) => { + } = {}) => { fakeApollo = createMockApollo([ [getMRCodequalityAndSecurityReports, codeQualityAndSastQueryHandlerSuccess], ]); @@ -490,22 +490,60 @@ describe('diffs/components/app', () => { describe('diffs', () => { it('should render compare versions component', () => { + createComponent(); + expect(wrapper.findComponent(CompareVersions).exists()).toBe(true); + expect(wrapper.findComponent(CompareVersions).props()).toMatchObject({ + toggleFileTreeVisible: false, + }); + }); + + it('should render file tree toggle in compare versions', () => { createComponent({ extendStore: ({ state }) => { - state.diffs.mergeRequestDiffs = diffsMockData; - state.diffs.targetBranchName = 'target-branch'; - state.diffs.mergeRequestDiff = mergeRequestDiff; + state.diffs.diffFiles = [getDiffFileMock()]; }, }); - expect(wrapper.findComponent(CompareVersions).exists()).toBe(true); - expect(wrapper.findComponent(CompareVersions).props()).toEqual( + expect(wrapper.findComponent(CompareVersions).props()).toMatchObject({ + toggleFileTreeVisible: true, + }); + }); + + it('should render app controls component', () => { + createComponent({ + extendStore: ({ state }) => { + state.diffs.diffFiles = diffsMockData; + state.diffs.realSize = '10'; + state.diffs.addedLines = 15; + state.diffs.removedLines = 20; + }, + }); + + expect(wrapper.findComponent(DiffAppControls).exists()).toBe(true); + expect(wrapper.findComponent(DiffAppControls).props()).toEqual( expect.objectContaining({ - diffFilesCountText: null, + hasChanges: true, + diffsCount: '10', + addedLines: 15, + removedLines: 20, }), ); }); + it('collapses all files', async () => { + createComponent(); + const spy = jest.spyOn(store, 'dispatch'); + await wrapper.findComponent(DiffAppControls).vm.$emit('collapseAllFiles'); + expect(spy).toHaveBeenCalledWith('diffs/collapseAllFiles', undefined); + }); + + it('expands all files', async () => { + createComponent(); + jest.spyOn(store, 'dispatch'); + await wrapper.findComponent(DiffAppControls).vm.$emit('expandAllFiles'); + expect(store.dispatch).toHaveBeenCalledWith('diffs/expandAllFiles', undefined); + }); + describe('warnings', () => { describe('hidden files', () => { it('should render hidden files warning if render overflow warning is present', () => { diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js index 2355f1dff0d98349242f3ab2d69080671b1d4d84..87a93f543d42afd7950154061eb9a1c26eddc6b4 100644 --- a/spec/frontend/diffs/components/compare_versions_spec.js +++ b/spec/frontend/diffs/components/compare_versions_spec.js @@ -22,20 +22,19 @@ describe('CompareVersions', () => { const targetBranchName = 'tmp-wine-dev'; const { commit } = getDiffWithCommit; - const createWrapper = (props = {}, commitArgs = {}, createCommit = true) => { + const createWrapper = ({ props = {}, commitArgs = {}, createCommit = true } = {}) => { if (createCommit) { store.state.diffs.commit = { ...store.state.diffs.commit, ...commitArgs }; } wrapper = mount(CompareVersionsComponent, { - mocks: { - $store: store, - }, propsData: { - mergeRequestDiffs: diffsMockData, - diffFilesCountText: '1', + toggleFileTreeVisible: true, ...props, }, + mocks: { + $store: store, + }, }); }; const findCompareSourceDropdown = () => wrapper.find('.mr-version-dropdown'); @@ -77,7 +76,7 @@ describe('CompareVersions', () => { describe('template', () => { beforeEach(() => { - createWrapper({}, {}, false); + createWrapper({ createCommit: false }); }); it('should render Tree List toggle button with correct attribute values', () => { @@ -99,17 +98,11 @@ describe('CompareVersions', () => { }); }); - describe('noChangedFiles', () => { - beforeEach(() => { - store.state.diffs.diffFiles = []; - }); - - it('should not render Tree List toggle button when there are no changes', () => { - createWrapper(); - const treeListBtn = wrapper.find('.js-toggle-tree-list'); + it('should not render Tree List toggle button when a prop is false', () => { + createWrapper({ props: { toggleFileTreeVisible: false } }); + const treeListBtn = wrapper.find('.js-toggle-tree-list'); - expect(treeListBtn.exists()).toBe(false); - }); + expect(treeListBtn.exists()).toBe(false); }); describe('commit', () => { @@ -147,7 +140,7 @@ describe('CompareVersions', () => { describe('without neighbor commits', () => { beforeEach(() => { - createWrapper({ commit: { ...commit, prev_commit_id: null, next_commit_id: null } }); + createWrapper({ commitArgs: { ...commit, prev_commit_id: null, next_commit_id: null } }); }); it('does not render any navigation buttons', () => { @@ -165,20 +158,16 @@ describe('CompareVersions', () => { prev_commit_id: 'prev', }; - createWrapper({}, mrCommit); + createWrapper({ commitArgs: mrCommit }); }); it('renders the commit navigation buttons', () => { expect(getCommitNavButtonsElement().exists()).toEqual(true); - createWrapper({ - commit: { ...mrCommit, next_commit_id: null }, - }); + createWrapper({ commitArgs: { ...mrCommit, next_commit_id: null } }); expect(getCommitNavButtonsElement().exists()).toEqual(true); - createWrapper({ - commit: { ...mrCommit, prev_commit_id: null }, - }); + createWrapper({ commitArgs: { ...mrCommit, prev_commit_id: null } }); expect(getCommitNavButtonsElement().exists()).toEqual(true); }); @@ -204,7 +193,7 @@ describe('CompareVersions', () => { }); it('renders a disabled button when there is no prev commit', () => { - createWrapper({}, { ...mrCommit, prev_commit_id: null }); + createWrapper({ commitArgs: { ...mrCommit, prev_commit_id: null } }); const button = getPrevCommitNavElement(); @@ -234,7 +223,7 @@ describe('CompareVersions', () => { }); it('renders a disabled button when there is no next commit', () => { - createWrapper({}, { ...mrCommit, next_commit_id: null }); + createWrapper({ commitArgs: { ...mrCommit, next_commit_id: null } }); const button = getNextCommitNavElement(); diff --git a/spec/frontend/diffs/components/diff_app_controls_spec.js b/spec/frontend/diffs/components/diff_app_controls_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..181f8b42b629a3279b69f9ff1bcdb74f7f804c7d --- /dev/null +++ b/spec/frontend/diffs/components/diff_app_controls_spec.js @@ -0,0 +1,90 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlButton } from '@gitlab/ui'; +import DiffAppControls from '~/diffs/components/diff_app_controls.vue'; +import DiffStats from '~/diffs/components/diff_stats.vue'; +import SettingsDropdown from '~/diffs/components/settings_dropdown.vue'; +import { + keysFor, + MR_COLLAPSE_ALL_FILES, + MR_EXPAND_ALL_FILES, +} from '~/behaviors/shortcuts/keybindings'; +import { Mousetrap } from '~/lib/mousetrap'; + +const DEFAULT_PROPS = { + diffsCount: '5', + addedLines: 10, + removedLines: 5, +}; + +describe('DiffAppControls', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(DiffAppControls, { + propsData: { + ...DEFAULT_PROPS, + ...props, + }, + }); + }; + + const findButtonByIcon = (icon) => + wrapper + .findAllComponents(GlButton) + .filter((buttonWrapper) => buttonWrapper.props('icon') === icon) + .at(0); + + describe('when has changes', () => { + beforeEach(() => { + createComponent({ hasChanges: true }); + }); + + it('renders diff stats', () => { + expect(wrapper.findComponent(DiffStats).exists()).toBe(true); + expect(wrapper.findComponent(DiffStats).props()).toMatchObject({ + diffsCount: DEFAULT_PROPS.diffsCount, + addedLines: DEFAULT_PROPS.addedLines, + removedLines: DEFAULT_PROPS.removedLines, + }); + }); + + it('renders expand buttons', () => { + expect(findButtonByIcon('expand').exists()).toBe(true); + expect(findButtonByIcon('collapse').exists()).toBe(true); + }); + + it('emits expandAllFiles', () => { + findButtonByIcon('expand').vm.$emit('click'); + expect(wrapper.emitted('expandAllFiles')).toStrictEqual([[]]); + }); + + it('emits expandAllFiles on hotkey', () => { + Mousetrap.trigger(keysFor(MR_EXPAND_ALL_FILES)[0]); + expect(wrapper.emitted('expandAllFiles')).toStrictEqual([[]]); + }); + + it('emits collapseAllFiles', () => { + findButtonByIcon('collapse').vm.$emit('click'); + expect(wrapper.emitted('collapseAllFiles')).toStrictEqual([[]]); + }); + + it('emits collapseAllFiles on hotkey', () => { + Mousetrap.trigger(keysFor(MR_COLLAPSE_ALL_FILES)[0]); + expect(wrapper.emitted('collapseAllFiles')).toStrictEqual([[]]); + }); + + it('renders settings', () => { + expect(wrapper.findComponent(SettingsDropdown).exists()).toBe(true); + }); + }); + + describe('when has no changes', () => { + beforeEach(() => { + createComponent({ hasChanges: false }); + }); + + it('renders settings', () => { + expect(wrapper.findComponent(SettingsDropdown).exists()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 3a04547fa69e1beabcd37a798949184ef5577778..737654b1406a4d4282b388ef129896d8c2c0078c 100644 --- a/spec/frontend/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js @@ -28,15 +28,15 @@ describe('diff_stats', () => { describe('diff stats group', () => { const findDiffStatsGroup = () => wrapper.findAll('.diff-stats-group'); - it('is not rendered if diffFilesCountText is empty', () => { + it('is not rendered if diffsCount is empty', () => { createComponent(); expect(findDiffStatsGroup().length).toBe(2); }); - it('is not rendered if diffFilesCountText is not a number', () => { + it('is not rendered if diffsCount is not a number', () => { createComponent({ - diffFilesCountText: null, + diffsCount: null, }); expect(findDiffStatsGroup().length).toBe(2); @@ -95,7 +95,7 @@ describe('diff_stats', () => { const oneFileChanged = '0'; createComponent({ - diffFilesCountText: oneFileChanged, + diffsCount: oneFileChanged, }); expect(findIcon('doc-code').textContent.trim()).toBe(`${oneFileChanged} files`); @@ -105,7 +105,7 @@ describe('diff_stats', () => { const oneFileChanged = '1'; createComponent({ - diffFilesCountText: oneFileChanged, + diffsCount: oneFileChanged, }); expect(findIcon('doc-code').textContent.trim()).toBe(`${oneFileChanged} file`); @@ -113,7 +113,7 @@ describe('diff_stats', () => { it('shows amount of files change with plural "files" when multiple files are changed', () => { createComponent({ - diffFilesCountText: DIFF_FILES_COUNT, + diffsCount: DIFF_FILES_COUNT, }); expect(findIcon('doc-code').textContent.trim()).toContain(`${DIFF_FILES_COUNT} files`); @@ -121,7 +121,7 @@ describe('diff_stats', () => { it('shows amount of files change with plural "files" when files changed is truncated', () => { createComponent({ - diffFilesCountText: DIFF_FILES_COUNT_TRUNCATED, + diffsCount: DIFF_FILES_COUNT_TRUNCATED, }); expect(findIcon('doc-code').textContent.trim()).toContain( diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js index 8339909436a8ac9e7073069dd3b0524586d7e5b9..b8c62bb06e249b4421cb88c226e3d6e5e855db6a 100644 --- a/spec/frontend/diffs/store/actions_spec.js +++ b/spec/frontend/diffs/store/actions_spec.js @@ -2218,4 +2218,38 @@ describe('DiffsStoreActions', () => { testAction(diffActions.unlinkFile, undefined, {}, [], []); }); }); + + describe('expandAllFiles', () => { + it('triggers mutation', () => { + testAction( + diffActions.expandAllFiles, + undefined, + {}, + [ + { + type: types.SET_COLLAPSED_STATE_FOR_ALL_FILES, + payload: { collapsed: false }, + }, + ], + [], + ); + }); + }); + + describe('collapseAllFiles', () => { + it('triggers mutation', () => { + testAction( + diffActions.collapseAllFiles, + undefined, + {}, + [ + { + type: types.SET_COLLAPSED_STATE_FOR_ALL_FILES, + payload: { collapsed: true }, + }, + ], + [], + ); + }); + }); }); diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js index 1d9e51e05e6b7766f9dd0ce66f43e27839e9aca9..8c71e47e9698f9ae29f3e70b7e90add7cf367151 100644 --- a/spec/frontend/diffs/store/mutations_spec.js +++ b/spec/frontend/diffs/store/mutations_spec.js @@ -1349,4 +1349,20 @@ describe('DiffsStoreMutations', () => { expect(state.linkedFileHash).toBe(file.file_hash); }); }); + + describe('SET_COLLAPSED_STATE_FOR_ALL_FILES', () => { + it('sets collapsed state for all files', () => { + const state = { + diffFiles: [getDiffFileMock(), getDiffFileMock()], + }; + + mutations[types.SET_COLLAPSED_STATE_FOR_ALL_FILES](state, { collapsed: true }); + + expect( + state.diffFiles.every( + ({ viewer }) => viewer.manuallyCollapsed && !viewer.automaticallyCollapsed, + ), + ).toBe(true); + }); + }); }); diff --git a/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js b/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js index 597b93b8c259fc36542612117b097ebed6c389aa..c40539ac8d8fac5b5e0c456107c9127ef832d094 100644 --- a/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js +++ b/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js @@ -2219,4 +2219,38 @@ describe.skip('DiffsStoreActions', () => { testAction(diffActions.unlinkFile, undefined, {}, [], []); }); }); + + describe('expandAllFiles', () => { + it('triggers mutation', () => { + testAction( + diffActions.expandAllFiles, + undefined, + {}, + [ + { + type: types.SET_COLLAPSED_STATE_FOR_ALL_FILES, + payload: { collapsed: false }, + }, + ], + [], + ); + }); + }); + + describe('collapseAllFiles', () => { + it('triggers mutation', () => { + testAction( + diffActions.collapseAllFiles, + undefined, + {}, + [ + { + type: types.SET_COLLAPSED_STATE_FOR_ALL_FILES, + payload: { collapsed: true }, + }, + ], + [], + ); + }); + }); }); diff --git a/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js b/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js index 77917730a9c1f6181b804ceee52282cd681698b5..11a778b69f8251abec5bfa210dc28fbe78f88dcb 100644 --- a/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js +++ b/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js @@ -1350,4 +1350,20 @@ describe.skip('DiffsStoreMutations', () => { expect(state.linkedFileHash).toBe(file.file_hash); }); }); + + describe('SET_COLLAPSED_STATE_FOR_ALL_FILES', () => { + it('sets collapsed state for all files', () => { + const state = { + diffFiles: [getDiffFileMock(), getDiffFileMock()], + }; + + mutations[types.SET_COLLAPSED_STATE_FOR_ALL_FILES](state, { collapsed: true }); + + expect( + state.diffFiles.every( + ({ viewer }) => viewer.manuallyCollapsed && !viewer.automaticallyCollapsed, + ), + ).toBe(true); + }); + }); }); diff --git a/spec/frontend/helpers/diffs_helper_spec.js b/spec/frontend/helpers/diffs_helper_spec.js index ba5c5ce8534d0c22dcb011795b39a4a09ef9cec7..7cf02a69da1515ab7a1d911a6e25c530827b7b4d 100644 --- a/spec/frontend/helpers/diffs_helper_spec.js +++ b/spec/frontend/helpers/diffs_helper_spec.js @@ -56,43 +56,6 @@ describe('diffs helper', () => { }); }); - describe('isSingleViewStyle', () => { - it('is true when the file has at least 1 inline line but no parallel lines for any reason', () => { - const noParallelLines = getDiffFile({ parallel_diff_lines: undefined }); - const emptyParallelLines = getDiffFile({ parallel_diff_lines: [] }); - - expect(diffsHelper.isSingleViewStyle(noParallelLines)).toBe(true); - expect(diffsHelper.isSingleViewStyle(emptyParallelLines)).toBe(true); - }); - - it('is true when the file has at least 1 parallel line but no inline lines for any reason', () => { - const noInlineLines = getDiffFile({ highlighted_diff_lines: undefined }); - const emptyInlineLines = getDiffFile({ highlighted_diff_lines: [] }); - - expect(diffsHelper.isSingleViewStyle(noInlineLines)).toBe(true); - expect(diffsHelper.isSingleViewStyle(emptyInlineLines)).toBe(true); - }); - - it('is true when the file does not have any inline lines or parallel lines for any reason', () => { - const noLines = getDiffFile({ - highlighted_diff_lines: undefined, - parallel_diff_lines: undefined, - }); - const emptyLines = getDiffFile({ - highlighted_diff_lines: [], - parallel_diff_lines: [], - }); - - expect(diffsHelper.isSingleViewStyle(noLines)).toBe(true); - expect(diffsHelper.isSingleViewStyle(emptyLines)).toBe(true); - expect(diffsHelper.isSingleViewStyle()).toBe(true); - }); - - it('is false when the file has both inline and parallel lines', () => { - expect(diffsHelper.isSingleViewStyle(getDiffFile())).toBe(false); - }); - }); - describe.each` context | inline | parallel | expected ${'only has inline lines'} | ${['line']} | ${undefined} | ${true}