diff options
Diffstat (limited to 'spec/frontend/diffs/components/diff_file_header_spec.js')
-rw-r--r-- | spec/frontend/diffs/components/diff_file_header_spec.js | 304 |
1 files changed, 233 insertions, 71 deletions
diff --git a/spec/frontend/diffs/components/diff_file_header_spec.js b/spec/frontend/diffs/components/diff_file_header_spec.js index e9a63e861ed..b16ef8fe6b0 100644 --- a/spec/frontend/diffs/components/diff_file_header_spec.js +++ b/spec/frontend/diffs/components/diff_file_header_spec.js @@ -1,22 +1,29 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; -import Vuex from 'vuex'; import { cloneDeep } from 'lodash'; +import Vuex from 'vuex'; import { mockTracking, triggerEvent } from 'helpers/tracking_helper'; import DiffFileHeader from '~/diffs/components/diff_file_header.vue'; +import { DIFF_FILE_AUTOMATIC_COLLAPSE, DIFF_FILE_MANUAL_COLLAPSE } from '~/diffs/constants'; +import { reviewFile } from '~/diffs/store/actions'; +import { SET_MR_FILE_REVIEWS } from '~/diffs/store/mutation_types'; +import { diffViewerModes } from '~/ide/constants'; +import { scrollToElement } from '~/lib/utils/common_utils'; +import { truncateSha } from '~/lib/utils/text_utility'; +import { __, sprintf } from '~/locale'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue'; + +import testAction from '../../__helpers__/vuex_action_helper'; import diffDiscussionsMockData from '../mock_data/diff_discussions'; -import { truncateSha } from '~/lib/utils/text_utility'; -import { diffViewerModes } from '~/ide/constants'; -import { __, sprintf } from '~/locale'; -import { scrollToElement } from '~/lib/utils/common_utils'; jest.mock('~/lib/utils/common_utils'); const diffFile = Object.freeze( Object.assign(diffDiscussionsMockData.diff_file, { + id: '123', + file_identifier_hash: 'abc', edit_path: 'link:/to/edit/path', blob: { id: '848ed9407c6730ff16edb3dd24485a0eea24292a', @@ -52,6 +59,8 @@ describe('DiffFileHeader component', () => { toggleFileDiscussionWrappers: jest.fn(), toggleFullDiff: jest.fn(), toggleActiveFileByHash: jest.fn(), + setFileCollapsedByUser: jest.fn(), + reviewFile: jest.fn(), }, }, }, @@ -79,10 +88,11 @@ describe('DiffFileHeader component', () => { const findViewFileButton = () => wrapper.find({ ref: 'viewButton' }); const findCollapseIcon = () => wrapper.find({ ref: 'collapseIcon' }); const findEditButton = () => wrapper.find({ ref: 'editButton' }); + const findReviewFileCheckbox = () => wrapper.find("[data-testid='fileReviewCheckbox']"); - const createComponent = (props) => { + const createComponent = ({ props, options = {} } = {}) => { mockStoreConfig = cloneDeep(defaultMockStoreConfig); - const store = new Vuex.Store(mockStoreConfig); + const store = new Vuex.Store({ ...mockStoreConfig, ...(options.store || {}) }); wrapper = shallowMount(DiffFileHeader, { propsData: { @@ -91,6 +101,7 @@ describe('DiffFileHeader component', () => { viewDiffsFileByFile: false, ...props, }, + ...options, localVue, store, }); @@ -101,7 +112,7 @@ describe('DiffFileHeader component', () => { ${'visible'} | ${true} ${'hidden'} | ${false} `('collapse toggle is $visibility if collapsible is $collapsible', ({ collapsible }) => { - createComponent({ collapsible }); + createComponent({ props: { collapsible } }); expect(findCollapseIcon().exists()).toBe(collapsible); }); @@ -110,7 +121,7 @@ describe('DiffFileHeader component', () => { ${true} | ${'chevron-down'} ${false} | ${'chevron-right'} `('collapse icon is $icon if expanded is $expanded', ({ icon, expanded }) => { - createComponent({ expanded, collapsible: true }); + createComponent({ props: { expanded, collapsible: true } }); expect(findCollapseIcon().props('name')).toBe(icon); }); @@ -124,7 +135,7 @@ describe('DiffFileHeader component', () => { }); it('when collapseIcon is clicked emits toggleFile', () => { - createComponent({ collapsible: true }); + createComponent({ props: { collapsible: true } }); findCollapseIcon().vm.$emit('click', new Event('click')); return wrapper.vm.$nextTick().then(() => { expect(wrapper.emitted().toggleFile).toBeDefined(); @@ -132,7 +143,7 @@ describe('DiffFileHeader component', () => { }); it('when other element in header is clicked does not emits toggleFile', () => { - createComponent({ collapsible: true }); + createComponent({ props: { collapsible: true } }); findTitleLink().trigger('click'); return wrapper.vm.$nextTick().then(() => { @@ -171,10 +182,12 @@ describe('DiffFileHeader component', () => { it('prefers submodule_tree_url over submodule_link for href', () => { const submoduleTreeUrl = 'some://tree/url'; createComponent({ - discussionLink: 'discussionLink', - diffFile: { - ...submoduleDiffFile, - submodule_tree_url: 'some://tree/url', + props: { + discussionLink: 'discussionLink', + diffFile: { + ...submoduleDiffFile, + submodule_tree_url: 'some://tree/url', + }, }, }); @@ -184,8 +197,10 @@ describe('DiffFileHeader component', () => { it('uses submodule_link for href if submodule_tree_url does not exists', () => { const submoduleLink = 'link://to/submodule'; createComponent({ - discussionLink: 'discussionLink', - diffFile: submoduleDiffFile, + props: { + discussionLink: 'discussionLink', + diffFile: submoduleDiffFile, + }, }); expect(findTitleLink().attributes('href')).toBe(submoduleLink); @@ -193,7 +208,9 @@ describe('DiffFileHeader component', () => { it('uses file_path + SHA as link text', () => { createComponent({ - diffFile: submoduleDiffFile, + props: { + diffFile: submoduleDiffFile, + }, }); expect(findTitleLink().text()).toContain( @@ -203,15 +220,19 @@ describe('DiffFileHeader component', () => { it('does not render file actions', () => { createComponent({ - diffFile: submoduleDiffFile, - addMergeRequestButtons: true, + props: { + diffFile: submoduleDiffFile, + addMergeRequestButtons: true, + }, }); expect(findFileActions().exists()).toBe(false); }); it('renders submodule icon', () => { createComponent({ - diffFile: submoduleDiffFile, + props: { + diffFile: submoduleDiffFile, + }, }); expect(wrapper.find(FileIcon).props('submodule')).toBe(true); @@ -223,13 +244,15 @@ describe('DiffFileHeader component', () => { it('for mode_changed file mode displays mode changes', () => { createComponent({ - diffFile: { - ...diffFile, - a_mode: 'old-mode', - b_mode: 'new-mode', - viewer: { - ...diffFile.viewer, - name: diffViewerModes.mode_changed, + props: { + diffFile: { + ...diffFile, + a_mode: 'old-mode', + b_mode: 'new-mode', + viewer: { + ...diffFile.viewer, + name: diffViewerModes.mode_changed, + }, }, }, }); @@ -240,13 +263,15 @@ describe('DiffFileHeader component', () => { 'for %s file mode does not display mode changes', (mode) => { createComponent({ - diffFile: { - ...diffFile, - a_mode: 'old-mode', - b_mode: 'new-mode', - viewer: { - ...diffFile.viewer, - name: diffViewerModes[mode], + props: { + diffFile: { + ...diffFile, + a_mode: 'old-mode', + b_mode: 'new-mode', + viewer: { + ...diffFile.viewer, + name: diffViewerModes[mode], + }, }, }, }); @@ -256,32 +281,38 @@ describe('DiffFileHeader component', () => { it('displays the LFS label for files stored in LFS', () => { createComponent({ - diffFile: { ...diffFile, stored_externally: true, external_storage: 'lfs' }, + props: { + diffFile: { ...diffFile, stored_externally: true, external_storage: 'lfs' }, + }, }); expect(findLfsLabel().exists()).toBe(true); }); it('does not display the LFS label for files stored in repository', () => { createComponent({ - diffFile: { ...diffFile, stored_externally: false }, + props: { + diffFile: { ...diffFile, stored_externally: false }, + }, }); expect(findLfsLabel().exists()).toBe(false); }); it('does not render view replaced file button if no replaced view path is present', () => { createComponent({ - diffFile: { ...diffFile, replaced_view_path: null }, + props: { + diffFile: { ...diffFile, replaced_view_path: null }, + }, }); expect(findReplacedFileButton().exists()).toBe(false); }); describe('when addMergeRequestButtons is false', () => { it('does not render file actions', () => { - createComponent({ addMergeRequestButtons: false }); + createComponent({ props: { addMergeRequestButtons: false } }); expect(findFileActions().exists()).toBe(false); }); it('should not render edit button', () => { - createComponent({ addMergeRequestButtons: false }); + createComponent({ props: { addMergeRequestButtons: false } }); expect(findEditButton().exists()).toBe(false); }); }); @@ -290,7 +321,7 @@ describe('DiffFileHeader component', () => { describe('without discussions', () => { it('does not render a toggle discussions button', () => { diffHasDiscussionsResultMock.mockReturnValue(false); - createComponent({ addMergeRequestButtons: true }); + createComponent({ props: { addMergeRequestButtons: true } }); expect(findToggleDiscussionsButton().exists()).toBe(false); }); }); @@ -298,7 +329,7 @@ describe('DiffFileHeader component', () => { describe('with discussions', () => { it('dispatches toggleFileDiscussionWrappers when user clicks on toggle discussions button', () => { diffHasDiscussionsResultMock.mockReturnValue(true); - createComponent({ addMergeRequestButtons: true }); + createComponent({ props: { addMergeRequestButtons: true } }); expect(findToggleDiscussionsButton().exists()).toBe(true); findToggleDiscussionsButton().vm.$emit('click'); expect( @@ -309,7 +340,9 @@ describe('DiffFileHeader component', () => { it('should show edit button', () => { createComponent({ - addMergeRequestButtons: true, + props: { + addMergeRequestButtons: true, + }, }); expect(findEditButton().exists()).toBe(true); }); @@ -319,25 +352,27 @@ describe('DiffFileHeader component', () => { const externalUrl = 'link://to/external'; const formattedExternalUrl = 'link://formatted'; createComponent({ - diffFile: { - ...diffFile, - external_url: externalUrl, - formatted_external_url: formattedExternalUrl, + props: { + diffFile: { + ...diffFile, + external_url: externalUrl, + formatted_external_url: formattedExternalUrl, + }, + addMergeRequestButtons: true, }, - addMergeRequestButtons: true, }); expect(findExternalLink().exists()).toBe(true); }); it('is hidden by default', () => { - createComponent({ addMergeRequestButtons: true }); + createComponent({ props: { addMergeRequestButtons: true } }); expect(findExternalLink().exists()).toBe(false); }); }); describe('without file blob', () => { beforeEach(() => { - createComponent({ diffFile: { ...diffFile, blob: false } }); + createComponent({ props: { diffFile: { ...diffFile, blob: false } } }); }); it('should not render toggle discussions button', () => { @@ -352,8 +387,10 @@ describe('DiffFileHeader component', () => { it('should render correct file view button', () => { const viewPath = 'link://view-path'; createComponent({ - diffFile: { ...diffFile, view_path: viewPath }, - addMergeRequestButtons: true, + props: { + diffFile: { ...diffFile, view_path: viewPath }, + addMergeRequestButtons: true, + }, }); expect(findViewFileButton().attributes('href')).toBe(viewPath); expect(findViewFileButton().text()).toEqual( @@ -367,9 +404,11 @@ describe('DiffFileHeader component', () => { describe('when diff is fully expanded', () => { it('is not rendered', () => { createComponent({ - diffFile: { - ...diffFile, - is_fully_expanded: true, + props: { + diffFile: { + ...diffFile, + is_fully_expanded: true, + }, }, }); expect(findExpandButton().exists()).toBe(false); @@ -387,17 +426,17 @@ describe('DiffFileHeader component', () => { }; it('renders expand to full file button if not showing full file already', () => { - createComponent(fullyNotExpandedFileProps); + createComponent({ props: fullyNotExpandedFileProps }); expect(findExpandButton().exists()).toBe(true); }); it('renders loading icon when loading full file', () => { - createComponent(fullyNotExpandedFileProps); + createComponent({ props: fullyNotExpandedFileProps }); expect(findExpandButton().exists()).toBe(true); }); it('toggles full diff on click', () => { - createComponent(fullyNotExpandedFileProps); + createComponent({ props: fullyNotExpandedFileProps }); findExpandButton().vm.$emit('click'); expect(mockStoreConfig.modules.diffs.actions.toggleFullDiff).toHaveBeenCalled(); }); @@ -407,7 +446,9 @@ describe('DiffFileHeader component', () => { it('uses discussionPath for link if it is defined', () => { const discussionPath = 'link://to/discussion'; createComponent({ - discussionPath, + props: { + discussionPath, + }, }); expect(findTitleLink().attributes('href')).toBe(discussionPath); }); @@ -436,21 +477,21 @@ describe('DiffFileHeader component', () => { describe('for new file', () => { it('displays the path', () => { - createComponent({ diffFile: { ...diffFile, new_file: true } }); + createComponent({ props: { diffFile: { ...diffFile, new_file: true } } }); expect(findTitleLink().text()).toBe(diffFile.file_path); }); }); describe('for deleted file', () => { it('displays the path', () => { - createComponent({ diffFile: { ...diffFile, deleted_file: true } }); + createComponent({ props: { diffFile: { ...diffFile, deleted_file: true } } }); expect(findTitleLink().text()).toBe( sprintf(__('%{filePath} deleted'), { filePath: diffFile.file_path }, false), ); }); it('does not show edit button', () => { - createComponent({ diffFile: { ...diffFile, deleted_file: true } }); + createComponent({ props: { diffFile: { ...diffFile, deleted_file: true } } }); expect(findEditButton().exists()).toBe(false); }); }); @@ -458,11 +499,13 @@ describe('DiffFileHeader component', () => { describe('for renamed file', () => { it('displays old and new path if the file was renamed', () => { createComponent({ - diffFile: { - ...diffFile, - renamed_file: true, - old_path_html: 'old', - new_path_html: 'new', + props: { + diffFile: { + ...diffFile, + renamed_file: true, + old_path_html: 'old', + new_path_html: 'new', + }, }, }); expect(findTitleLink().text()).toMatch(/^old.+new/s); @@ -473,13 +516,132 @@ describe('DiffFileHeader component', () => { it('renders view replaced file button', () => { const replacedViewPath = 'some/path'; createComponent({ - diffFile: { - ...diffFile, - replaced_view_path: replacedViewPath, + props: { + diffFile: { + ...diffFile, + replaced_view_path: replacedViewPath, + }, + addMergeRequestButtons: true, }, - addMergeRequestButtons: true, }); expect(findReplacedFileButton().exists()).toBe(true); }); }); + + describe('file reviews', () => { + it('calls the action to set the new review', () => { + createComponent({ + props: { + diffFile: { + ...diffFile, + viewer: { + ...diffFile.viewer, + automaticallyCollapsed: false, + manuallyCollapsed: null, + }, + }, + showLocalFileReviews: true, + addMergeRequestButtons: true, + }, + }); + + const file = wrapper.vm.diffFile; + + findReviewFileCheckbox().vm.$emit('change', true); + + return testAction( + reviewFile, + { file, reviewed: true }, + {}, + [{ type: SET_MR_FILE_REVIEWS, payload: { [file.file_identifier_hash]: [file.id] } }], + [], + ); + }); + + it.each` + description | newReviewedStatus | collapseType | aCollapse | mCollapse | callAction + ${'does nothing'} | ${true} | ${DIFF_FILE_MANUAL_COLLAPSE} | ${false} | ${true} | ${false} + ${'does nothing'} | ${false} | ${DIFF_FILE_AUTOMATIC_COLLAPSE} | ${true} | ${null} | ${false} + ${'does nothing'} | ${true} | ${'not collapsed'} | ${false} | ${null} | ${false} + ${'does nothing'} | ${false} | ${'not collapsed'} | ${false} | ${null} | ${false} + ${'collapses the file'} | ${true} | ${DIFF_FILE_AUTOMATIC_COLLAPSE} | ${true} | ${null} | ${true} + `( + "$description if the new review status is reviewed = $newReviewedStatus and the file's collapse type is collapse = $collapseType", + ({ newReviewedStatus, aCollapse, mCollapse, callAction }) => { + createComponent({ + props: { + diffFile: { + ...diffFile, + viewer: { + ...diffFile.viewer, + automaticallyCollapsed: aCollapse, + manuallyCollapsed: mCollapse, + }, + }, + showLocalFileReviews: true, + addMergeRequestButtons: true, + }, + }); + + findReviewFileCheckbox().vm.$emit('change', newReviewedStatus); + + if (callAction) { + expect(mockStoreConfig.modules.diffs.actions.setFileCollapsedByUser).toHaveBeenCalled(); + } else { + expect( + mockStoreConfig.modules.diffs.actions.setFileCollapsedByUser, + ).not.toHaveBeenCalled(); + } + }, + ); + + it.each` + description | show | visible + ${'shows'} | ${true} | ${true} + ${'hides'} | ${false} | ${false} + `( + '$description the file review feature given { showLocalFileReviewsProp: $show }', + ({ show, visible }) => { + createComponent({ + props: { + showLocalFileReviews: show, + addMergeRequestButtons: true, + }, + }); + + expect(findReviewFileCheckbox().exists()).toEqual(visible); + }, + ); + + it.each` + open | status | fires + ${true} | ${true} | ${true} + ${false} | ${false} | ${true} + ${true} | ${false} | ${false} + ${false} | ${true} | ${false} + `( + 'toggles appropriately when { fileExpanded: $open, newReviewStatus: $status }', + ({ open, status, fires }) => { + createComponent({ + props: { + diffFile: { + ...diffFile, + viewer: { + ...diffFile.viewer, + automaticallyCollapsed: false, + manuallyCollapsed: null, + }, + }, + showLocalFileReviews: true, + addMergeRequestButtons: true, + expanded: open, + }, + }); + + findReviewFileCheckbox().vm.$emit('change', status); + + expect(Boolean(wrapper.emitted().toggleFile)).toBe(fires); + }, + ); + }); }); |