From 859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 18 Feb 2021 10:34:06 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-9-stable-ee --- spec/frontend/diffs/components/app_spec.js | 24 +- .../components/collapsed_files_warning_spec.js | 4 +- spec/frontend/diffs/components/commit_item_spec.js | 2 +- .../diffs/components/commit_widget_spec.js | 2 +- .../components/compare_dropdown_layout_spec.js | 4 +- .../diffs/components/compare_versions_spec.js | 4 +- .../diffs/components/diff_comment_cell_spec.js | 2 +- .../frontend/diffs/components/diff_content_spec.js | 14 +- .../diffs/components/diff_discussions_spec.js | 8 +- .../diffs/components/diff_expansion_cell_spec.js | 8 +- .../diffs/components/diff_file_header_spec.js | 304 ++++++++++++++++----- .../diffs/components/diff_file_row_spec.js | 2 +- spec/frontend/diffs/components/diff_file_spec.js | 78 +++++- .../diffs/components/diff_line_note_form_spec.js | 5 +- spec/frontend/diffs/components/diff_row_spec.js | 6 +- .../diffs/components/diff_row_utils_spec.js | 11 + spec/frontend/diffs/components/diff_stats_spec.js | 2 +- spec/frontend/diffs/components/diff_view_spec.js | 14 +- .../diffs/components/image_diff_overlay_spec.js | 2 +- .../diffs/components/inline_diff_table_row_spec.js | 8 +- .../diffs/components/inline_diff_view_spec.js | 8 +- spec/frontend/diffs/components/no_changes_spec.js | 4 +- .../components/parallel_diff_table_row_spec.js | 10 +- .../diffs/components/parallel_diff_view_spec.js | 6 +- .../diffs/components/settings_dropdown_spec.js | 2 +- spec/frontend/diffs/components/tree_list_spec.js | 2 +- spec/frontend/diffs/store/actions_spec.js | 8 +- spec/frontend/diffs/store/getters_spec.js | 68 ++++- .../diffs/store/getters_versions_dropdowns_spec.js | 4 +- spec/frontend/diffs/store/mutations_spec.js | 6 +- spec/frontend/diffs/store/utils_spec.js | 4 +- spec/frontend/diffs/utils/diff_file_spec.js | 13 +- spec/frontend/diffs/utils/file_reviews_spec.js | 48 +++- spec/frontend/diffs/utils/preferences_spec.js | 5 +- spec/frontend/diffs/utils/suggestions_spec.js | 15 + 35 files changed, 507 insertions(+), 200 deletions(-) create mode 100644 spec/frontend/diffs/utils/suggestions_spec.js (limited to 'spec/frontend/diffs') diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js index 7fbeb33dd93..d2b5338a0cc 100644 --- a/spec/frontend/diffs/components/app_spec.js +++ b/spec/frontend/diffs/components/app_spec.js @@ -1,26 +1,26 @@ -import Vue, { nextTick } from 'vue'; -import Vuex from 'vuex'; -import { shallowMount } from '@vue/test-utils'; import { GlLoadingIcon, GlPagination } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; -import { TEST_HOST } from 'spec/test_constants'; import Mousetrap from 'mousetrap'; +import Vue, { nextTick } from 'vue'; +import Vuex from 'vuex'; +import { TEST_HOST } from 'spec/test_constants'; import App from '~/diffs/components/app.vue'; -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 CompareVersions from '~/diffs/components/compare_versions.vue'; +import DiffFile from '~/diffs/components/diff_file.vue'; +import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue'; +import NoChanges from '~/diffs/components/no_changes.vue'; import TreeList from '~/diffs/components/tree_list.vue'; -import createDiffsStore from '../create_diffs_store'; -import axios from '~/lib/utils/axios_utils'; -import * as urlUtils from '~/lib/utils/url_utility'; -import diffsMockData from '../mock_data/merge_request_diffs'; import { EVT_VIEW_FILE_BY_FILE } from '~/diffs/constants'; import eventHub from '~/diffs/event_hub'; +import axios from '~/lib/utils/axios_utils'; +import * as urlUtils from '~/lib/utils/url_utility'; +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`; diff --git a/spec/frontend/diffs/components/collapsed_files_warning_spec.js b/spec/frontend/diffs/components/collapsed_files_warning_spec.js index 75e76d88b6b..77c2e19cb68 100644 --- a/spec/frontend/diffs/components/collapsed_files_warning_spec.js +++ b/spec/frontend/diffs/components/collapsed_files_warning_spec.js @@ -1,9 +1,9 @@ -import Vuex from 'vuex'; import { shallowMount, mount, createLocalVue } from '@vue/test-utils'; -import createStore from '~/diffs/store/modules'; +import Vuex from 'vuex'; import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue'; import { CENTERED_LIMITED_CONTAINER_CLASSES, EVT_EXPAND_ALL_FILES } from '~/diffs/constants'; import eventHub from '~/diffs/event_hub'; +import createStore from '~/diffs/store/modules'; const propsData = { limited: true, diff --git a/spec/frontend/diffs/components/commit_item_spec.js b/spec/frontend/diffs/components/commit_item_spec.js index f588f65dafd..8cb4fd20063 100644 --- a/spec/frontend/diffs/components/commit_item_spec.js +++ b/spec/frontend/diffs/components/commit_item_spec.js @@ -1,8 +1,8 @@ import { mount } from '@vue/test-utils'; import { TEST_HOST } from 'helpers/test_constants'; import { trimText } from 'helpers/text_helper'; -import { getTimeago } from '~/lib/utils/datetime_utility'; import Component from '~/diffs/components/commit_item.vue'; +import { getTimeago } from '~/lib/utils/datetime_utility'; import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; import getDiffWithCommit from '../mock_data/diff_with_commit'; diff --git a/spec/frontend/diffs/components/commit_widget_spec.js b/spec/frontend/diffs/components/commit_widget_spec.js index 54e7596b726..fbff473e4df 100644 --- a/spec/frontend/diffs/components/commit_widget_spec.js +++ b/spec/frontend/diffs/components/commit_widget_spec.js @@ -1,6 +1,6 @@ import { shallowMount } from '@vue/test-utils'; -import CommitWidget from '~/diffs/components/commit_widget.vue'; import CommitItem from '~/diffs/components/commit_item.vue'; +import CommitWidget from '~/diffs/components/commit_widget.vue'; describe('diffs/components/commit_widget', () => { let wrapper; diff --git a/spec/frontend/diffs/components/compare_dropdown_layout_spec.js b/spec/frontend/diffs/components/compare_dropdown_layout_spec.js index d99933a1ee9..98f88226742 100644 --- a/spec/frontend/diffs/components/compare_dropdown_layout_spec.js +++ b/spec/frontend/diffs/components/compare_dropdown_layout_spec.js @@ -1,7 +1,7 @@ import { mount } from '@vue/test-utils'; import { trimText } from 'helpers/text_helper'; -import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import CompareDropdownLayout from '~/diffs/components/compare_dropdown_layout.vue'; +import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; const TEST_COMMIT_TEXT = '1 commit'; const TEST_CREATED_AT = '2018-10-23T11:49:16.611Z'; @@ -69,7 +69,7 @@ describe('CompareDropdownLayout', () => { expect(findListItemsData()).toEqual([ { href: 'version/1', - text: 'version 1 (base) abcdef1 1 commit 2 years ago', + text: 'version 1 (base) abcdef1 1 commit 1 year ago', createdAt: TEST_CREATED_AT, isActive: true, }, diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js index 949cc855200..c93a3771ec0 100644 --- a/spec/frontend/diffs/components/compare_versions_spec.js +++ b/spec/frontend/diffs/components/compare_versions_spec.js @@ -1,10 +1,10 @@ -import { trimText } from 'helpers/text_helper'; import { mount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; +import { trimText } from 'helpers/text_helper'; import CompareVersionsComponent from '~/diffs/components/compare_versions.vue'; import { createStore } from '~/mr_notes/stores'; -import diffsMockData from '../mock_data/merge_request_diffs'; import getDiffWithCommit from '../mock_data/diff_with_commit'; +import diffsMockData from '../mock_data/merge_request_diffs'; const localVue = createLocalVue(); localVue.use(Vuex); diff --git a/spec/frontend/diffs/components/diff_comment_cell_spec.js b/spec/frontend/diffs/components/diff_comment_cell_spec.js index d6b68fc52d7..b636a178593 100644 --- a/spec/frontend/diffs/components/diff_comment_cell_spec.js +++ b/spec/frontend/diffs/components/diff_comment_cell_spec.js @@ -1,7 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import DiffCommentCell from '~/diffs/components/diff_comment_cell.vue'; -import DiffDiscussions from '~/diffs/components/diff_discussions.vue'; import DiffDiscussionReply from '~/diffs/components/diff_discussion_reply.vue'; +import DiffDiscussions from '~/diffs/components/diff_discussions.vue'; describe('DiffCommentCell', () => { const createWrapper = (props = {}) => { diff --git a/spec/frontend/diffs/components/diff_content_spec.js b/spec/frontend/diffs/components/diff_content_spec.js index c1cf4793c88..db4d69f0176 100644 --- a/spec/frontend/diffs/components/diff_content_spec.js +++ b/spec/frontend/diffs/components/diff_content_spec.js @@ -1,17 +1,17 @@ +import { GlLoadingIcon } from '@gitlab/ui'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; -import { GlLoadingIcon } from '@gitlab/ui'; import DiffContentComponent from '~/diffs/components/diff_content.vue'; +import DiffDiscussions from '~/diffs/components/diff_discussions.vue'; +import DiffView from '~/diffs/components/diff_view.vue'; import InlineDiffView from '~/diffs/components/inline_diff_view.vue'; -import NotDiffableViewer from '~/vue_shared/components/diff_viewer/viewers/not_diffable.vue'; -import NoPreviewViewer from '~/vue_shared/components/diff_viewer/viewers/no_preview.vue'; import ParallelDiffView from '~/diffs/components/parallel_diff_view.vue'; -import NoteForm from '~/notes/components/note_form.vue'; -import DiffDiscussions from '~/diffs/components/diff_discussions.vue'; import { IMAGE_DIFF_POSITION_TYPE } from '~/diffs/constants'; -import diffFileMockData from '../mock_data/diff_file'; import { diffViewerModes } from '~/ide/constants'; -import DiffView from '~/diffs/components/diff_view.vue'; +import NoteForm from '~/notes/components/note_form.vue'; +import NoPreviewViewer from '~/vue_shared/components/diff_viewer/viewers/no_preview.vue'; +import NotDiffableViewer from '~/vue_shared/components/diff_viewer/viewers/not_diffable.vue'; +import diffFileMockData from '../mock_data/diff_file'; const localVue = createLocalVue(); localVue.use(Vuex); diff --git a/spec/frontend/diffs/components/diff_discussions_spec.js b/spec/frontend/diffs/components/diff_discussions_spec.js index 5c390054247..bd6f4cd2545 100644 --- a/spec/frontend/diffs/components/diff_discussions_spec.js +++ b/spec/frontend/diffs/components/diff_discussions_spec.js @@ -1,10 +1,10 @@ -import { mount, createLocalVue } from '@vue/test-utils'; import { GlIcon } from '@gitlab/ui'; +import { mount, createLocalVue } from '@vue/test-utils'; 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 { createStore } from '~/mr_notes/stores'; +import DiscussionNotes from '~/notes/components/discussion_notes.vue'; +import NoteableDiscussion from '~/notes/components/noteable_discussion.vue'; +import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; import '~/behaviors/markdown/render_gfm'; import discussionsMockData from '../mock_data/diff_discussions'; diff --git a/spec/frontend/diffs/components/diff_expansion_cell_spec.js b/spec/frontend/diffs/components/diff_expansion_cell_spec.js index 62e85b31f76..f53f10d955d 100644 --- a/spec/frontend/diffs/components/diff_expansion_cell_spec.js +++ b/spec/frontend/diffs/components/diff_expansion_cell_spec.js @@ -1,10 +1,10 @@ -import { cloneDeep } from 'lodash'; -import { mount } from '@vue/test-utils'; import { getByText } from '@testing-library/dom'; -import { createStore } from '~/mr_notes/stores'; +import { mount } from '@vue/test-utils'; +import { cloneDeep } from 'lodash'; import DiffExpansionCell from '~/diffs/components/diff_expansion_cell.vue'; -import { getPreviousLineIndex } from '~/diffs/store/utils'; import { INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; +import { getPreviousLineIndex } from '~/diffs/store/utils'; +import { createStore } from '~/mr_notes/stores'; import diffFileMockData from '../mock_data/diff_file'; const EXPAND_UP_CLASS = '.js-unfold'; 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); + }, + ); + }); }); diff --git a/spec/frontend/diffs/components/diff_file_row_spec.js b/spec/frontend/diffs/components/diff_file_row_spec.js index 7403a7918a9..1d1c5fec293 100644 --- a/spec/frontend/diffs/components/diff_file_row_spec.js +++ b/spec/frontend/diffs/components/diff_file_row_spec.js @@ -1,8 +1,8 @@ import { shallowMount } from '@vue/test-utils'; import DiffFileRow from '~/diffs/components/diff_file_row.vue'; -import FileRow from '~/vue_shared/components/file_row.vue'; import FileRowStats from '~/diffs/components/file_row_stats.vue'; import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue'; +import FileRow from '~/vue_shared/components/file_row.vue'; describe('Diff File Row component', () => { let wrapper; diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js index c715d779986..9c3c3e82ad5 100644 --- a/spec/frontend/diffs/components/diff_file_spec.js +++ b/spec/frontend/diffs/components/diff_file_spec.js @@ -1,26 +1,25 @@ -import Vuex from 'vuex'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; +import Vuex from 'vuex'; -import axios from '~/lib/utils/axios_utils'; -import httpStatus from '~/lib/utils/http_status'; -import createDiffsStore from '~/diffs/store/modules'; -import createNotesStore from '~/notes/stores/modules'; -import diffFileMockDataReadable from '../mock_data/diff_file'; -import diffFileMockDataUnreadable from '../mock_data/diff_file_unreadable'; - +import DiffContentComponent from '~/diffs/components/diff_content.vue'; import DiffFileComponent from '~/diffs/components/diff_file.vue'; import DiffFileHeaderComponent from '~/diffs/components/diff_file_header.vue'; -import DiffContentComponent from '~/diffs/components/diff_content.vue'; -import eventHub from '~/diffs/event_hub'; import { EVT_EXPAND_ALL_FILES, EVT_PERF_MARK_DIFF_FILES_END, EVT_PERF_MARK_FIRST_DIFF_FILE_SHOWN, } from '~/diffs/constants'; +import eventHub from '~/diffs/event_hub'; +import createDiffsStore from '~/diffs/store/modules'; import { diffViewerModes, diffViewerErrors } from '~/ide/constants'; +import axios from '~/lib/utils/axios_utils'; +import httpStatus from '~/lib/utils/http_status'; +import createNotesStore from '~/notes/stores/modules'; +import diffFileMockDataReadable from '../mock_data/diff_file'; +import diffFileMockDataUnreadable from '../mock_data/diff_file_unreadable'; function changeViewer(store, index, { automaticallyCollapsed, manuallyCollapsed, name }) { const file = store.state.diffs.diffFiles[index]; @@ -66,7 +65,7 @@ function markFileToBeRendered(store, index = 0) { }); } -function createComponent({ file, first = false, last = false }) { +function createComponent({ file, first = false, last = false, options = {}, props = {} }) { const localVue = createLocalVue(); localVue.use(Vuex); @@ -89,7 +88,9 @@ function createComponent({ file, first = false, last = false }) { viewDiffsFileByFile: false, isFirstFile: first, isLastFile: last, + ...props, }, + ...options, }); return { @@ -220,6 +221,53 @@ describe('DiffFile', () => { }); }); + describe('computed', () => { + describe('showLocalFileReviews', () => { + let gon; + + function setLoggedIn(bool) { + window.gon.current_user_id = bool; + } + + beforeAll(() => { + gon = window.gon; + window.gon = {}; + }); + + afterEach(() => { + window.gon = gon; + }); + + it.each` + loggedIn | featureOn | bool + ${true} | ${true} | ${true} + ${false} | ${true} | ${false} + ${true} | ${false} | ${false} + ${false} | ${false} | ${false} + `( + 'should be $bool when { userIsLoggedIn: $loggedIn, featureEnabled: $featureOn }', + ({ loggedIn, featureOn, bool }) => { + setLoggedIn(loggedIn); + + ({ wrapper } = createComponent({ + options: { + provide: { + glFeatures: { + localFileReviews: featureOn, + }, + }, + }, + props: { + file: store.state.diffs.diffFiles[0], + }, + })); + + expect(wrapper.vm.showLocalFileReviews).toBe(bool); + }, + ); + }); + }); + describe('collapsing', () => { describe(`\`${EVT_EXPAND_ALL_FILES}\` event`, () => { beforeEach(() => { @@ -422,9 +470,11 @@ describe('DiffFile', () => { await wrapper.vm.$nextTick(); - expect(wrapper.vm.$el.innerText).toContain( - 'This source diff could not be displayed because it is too large', - ); + const button = wrapper.find('[data-testid="blob-button"]'); + + expect(wrapper.text()).toContain('Changes are too large to be shown.'); + expect(button.html()).toContain('View file @'); + expect(button.attributes('href')).toBe('/file/view/path'); }); }); }); diff --git a/spec/frontend/diffs/components/diff_line_note_form_spec.js b/spec/frontend/diffs/components/diff_line_note_form_spec.js index faa68159c58..a192f7e2e9a 100644 --- a/spec/frontend/diffs/components/diff_line_note_form_spec.js +++ b/spec/frontend/diffs/components/diff_line_note_form_spec.js @@ -1,9 +1,9 @@ import { shallowMount } from '@vue/test-utils'; import DiffLineNoteForm from '~/diffs/components/diff_line_note_form.vue'; -import NoteForm from '~/notes/components/note_form.vue'; import { createStore } from '~/mr_notes/stores'; -import diffFileMockData from '../mock_data/diff_file'; +import NoteForm from '~/notes/components/note_form.vue'; import { noteableDataMock } from '../../notes/mock_data'; +import diffFileMockData from '../mock_data/diff_file'; describe('DiffLineNoteForm', () => { let wrapper; @@ -17,6 +17,7 @@ describe('DiffLineNoteForm', () => { const store = createStore(); store.state.notes.userData.id = 1; store.state.notes.noteableData = noteableDataMock; + store.state.diffs.diffFiles = [diffFile]; store.replaceState({ ...store.state, ...args.state }); diff --git a/spec/frontend/diffs/components/diff_row_spec.js b/spec/frontend/diffs/components/diff_row_spec.js index c06d8e78316..5682b29d697 100644 --- a/spec/frontend/diffs/components/diff_row_spec.js +++ b/spec/frontend/diffs/components/diff_row_spec.js @@ -1,10 +1,10 @@ -import { shallowMount, createLocalVue } from '@vue/test-utils'; import { getByTestId, fireEvent } from '@testing-library/dom'; +import { shallowMount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; -import diffsModule from '~/diffs/store/modules'; import DiffRow from '~/diffs/components/diff_row.vue'; -import diffFileMockData from '../mock_data/diff_file'; import { mapParallel } from '~/diffs/components/diff_row_utils'; +import diffsModule from '~/diffs/store/modules'; +import diffFileMockData from '../mock_data/diff_file'; describe('DiffRow', () => { const testLines = [ diff --git a/spec/frontend/diffs/components/diff_row_utils_spec.js b/spec/frontend/diffs/components/diff_row_utils_spec.js index d70d6b609ac..47ae3cd5867 100644 --- a/spec/frontend/diffs/components/diff_row_utils_spec.js +++ b/spec/frontend/diffs/components/diff_row_utils_spec.js @@ -143,10 +143,21 @@ describe('addCommentTooltip', () => { 'Commenting on symbolic links that replace or are replaced by files is currently not supported.'; const brokenRealTooltip = 'Commenting on files that replace or are replaced by symbolic links is currently not supported.'; + const commentTooltip = 'Add a comment to this line'; + const dragTooltip = 'Add a comment to this line or drag for multiple lines'; + it('should return default tooltip', () => { expect(utils.addCommentTooltip()).toBeUndefined(); }); + it('should return comment tooltip', () => { + expect(utils.addCommentTooltip({})).toEqual(commentTooltip); + }); + + it('should return drag comment tooltip when dragging is enabled', () => { + expect(utils.addCommentTooltip({}, true)).toEqual(dragTooltip); + }); + it('should return broken symlink tooltip', () => { expect(utils.addCommentTooltip({ commentsDisabled: { wasSymbolic: true } })).toEqual( brokenSymLinkTooltip, diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 0aaec027c0a..504158fb7fc 100644 --- a/spec/frontend/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js @@ -1,5 +1,5 @@ -import { shallowMount } from '@vue/test-utils'; import { GlIcon } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import DiffStats from '~/diffs/components/diff_stats.vue'; const TEST_ADDED_LINES = 100; diff --git a/spec/frontend/diffs/components/diff_view_spec.js b/spec/frontend/diffs/components/diff_view_spec.js index 3d36ebf14a3..83b173c1f5d 100644 --- a/spec/frontend/diffs/components/diff_view_spec.js +++ b/spec/frontend/diffs/components/diff_view_spec.js @@ -1,5 +1,5 @@ -import Vue from 'vue'; import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; import Vuex from 'vuex'; import DiffView from '~/diffs/components/diff_view.vue'; @@ -55,12 +55,12 @@ describe('DiffView', () => { }); it.each` - type | side | container | sides | total - ${'parallel'} | ${'left'} | ${'.old'} | ${{ left: { lineDraft: {} }, right: { lineDraft: {} } }} | ${2} - ${'parallel'} | ${'right'} | ${'.new'} | ${{ left: { lineDraft: {} }, right: { lineDraft: {} } }} | ${2} - ${'inline'} | ${'left'} | ${'.old'} | ${{ left: { lineDraft: {} } }} | ${1} - ${'inline'} | ${'right'} | ${'.new'} | ${{ right: { lineDraft: {} } }} | ${1} - ${'inline'} | ${'left'} | ${'.old'} | ${{ left: { lineDraft: {} }, right: { lineDraft: {} } }} | ${1} + type | side | container | sides | total + ${'parallel'} | ${'left'} | ${'.old'} | ${{ left: { lineDraft: {}, renderDiscussion: true }, right: { lineDraft: {}, renderDiscussion: true } }} | ${2} + ${'parallel'} | ${'right'} | ${'.new'} | ${{ left: { lineDraft: {}, renderDiscussion: true }, right: { lineDraft: {}, renderDiscussion: true } }} | ${2} + ${'inline'} | ${'left'} | ${'.old'} | ${{ left: { lineDraft: {}, renderDiscussion: true } }} | ${1} + ${'inline'} | ${'left'} | ${'.old'} | ${{ left: { lineDraft: {}, renderDiscussion: true } }} | ${1} + ${'inline'} | ${'left'} | ${'.old'} | ${{ left: { lineDraft: {}, renderDiscussion: true } }} | ${1} `( 'renders a $type comment row with comment cell on $side', ({ type, container, sides, total }) => { diff --git a/spec/frontend/diffs/components/image_diff_overlay_spec.js b/spec/frontend/diffs/components/image_diff_overlay_spec.js index 93c9b922fdd..47b144b2387 100644 --- a/spec/frontend/diffs/components/image_diff_overlay_spec.js +++ b/spec/frontend/diffs/components/image_diff_overlay_spec.js @@ -1,5 +1,5 @@ -import { shallowMount } from '@vue/test-utils'; import { GlIcon } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue'; import { createStore } from '~/mr_notes/stores'; import { imageDiffDiscussions } from '../mock_data/diff_discussions'; 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 21e7d7397a0..7e6f75ad6f8 100644 --- a/spec/frontend/diffs/components/inline_diff_table_row_spec.js +++ b/spec/frontend/diffs/components/inline_diff_table_row_spec.js @@ -1,10 +1,10 @@ import { shallowMount } from '@vue/test-utils'; -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'; import { mapInline } from '~/diffs/components/diff_row_utils'; +import InlineDiffTableRow from '~/diffs/components/inline_diff_table_row.vue'; +import { createStore } from '~/mr_notes/stores'; +import discussionsMockData from '../mock_data/diff_discussions'; +import diffFileMockData from '../mock_data/diff_file'; const TEST_USER_ID = 'abc123'; const TEST_USER = { id: TEST_USER_ID }; diff --git a/spec/frontend/diffs/components/inline_diff_view_spec.js b/spec/frontend/diffs/components/inline_diff_view_spec.js index 6a1791509fd..27834804f77 100644 --- a/spec/frontend/diffs/components/inline_diff_view_spec.js +++ b/spec/frontend/diffs/components/inline_diff_view_spec.js @@ -1,11 +1,11 @@ import '~/behaviors/markdown/render_gfm'; -import { mount } from '@vue/test-utils'; import { getByText } from '@testing-library/dom'; -import { createStore } from '~/mr_notes/stores'; -import InlineDiffView from '~/diffs/components/inline_diff_view.vue'; +import { mount } from '@vue/test-utils'; import { mapInline } from '~/diffs/components/diff_row_utils'; -import diffFileMockData from '../mock_data/diff_file'; +import InlineDiffView from '~/diffs/components/inline_diff_view.vue'; +import { createStore } from '~/mr_notes/stores'; import discussionsMockData from '../mock_data/diff_discussions'; +import diffFileMockData from '../mock_data/diff_file'; describe('InlineDiffView', () => { let wrapper; diff --git a/spec/frontend/diffs/components/no_changes_spec.js b/spec/frontend/diffs/components/no_changes_spec.js index df9af51f9cf..164c58dc8e4 100644 --- a/spec/frontend/diffs/components/no_changes_spec.js +++ b/spec/frontend/diffs/components/no_changes_spec.js @@ -1,8 +1,8 @@ +import { GlButton } from '@gitlab/ui'; import { createLocalVue, shallowMount, mount } 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 { createStore } from '~/mr_notes/stores'; import diffsMockData from '../mock_data/merge_request_diffs'; const localVue = createLocalVue(); 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 445553706b7..dbe8303077d 100644 --- a/spec/frontend/diffs/components/parallel_diff_table_row_spec.js +++ b/spec/frontend/diffs/components/parallel_diff_table_row_spec.js @@ -1,12 +1,12 @@ -import Vue from 'vue'; import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; -import { createStore } from '~/mr_notes/stores'; -import ParallelDiffTableRow from '~/diffs/components/parallel_diff_table_row.vue'; -import { mapParallel } from '~/diffs/components/diff_row_utils'; -import diffFileMockData from '../mock_data/diff_file'; import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue'; +import { mapParallel } from '~/diffs/components/diff_row_utils'; +import ParallelDiffTableRow from '~/diffs/components/parallel_diff_table_row.vue'; +import { createStore } from '~/mr_notes/stores'; import discussionsMockData from '../mock_data/diff_discussions'; +import diffFileMockData from '../mock_data/diff_file'; describe('ParallelDiffTableRow', () => { const mockDiffContent = { diff --git a/spec/frontend/diffs/components/parallel_diff_view_spec.js b/spec/frontend/diffs/components/parallel_diff_view_spec.js index 44ed303d0ef..452e1f58551 100644 --- a/spec/frontend/diffs/components/parallel_diff_view_spec.js +++ b/spec/frontend/diffs/components/parallel_diff_view_spec.js @@ -1,8 +1,8 @@ -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 Vuex from 'vuex'; import parallelDiffTableRow from '~/diffs/components/parallel_diff_table_row.vue'; +import ParallelDiffView from '~/diffs/components/parallel_diff_view.vue'; +import { createStore } from '~/mr_notes/stores'; import diffFileMockData from '../mock_data/diff_file'; let wrapper; diff --git a/spec/frontend/diffs/components/settings_dropdown_spec.js b/spec/frontend/diffs/components/settings_dropdown_spec.js index fcb627c570a..99fa83b64f1 100644 --- a/spec/frontend/diffs/components/settings_dropdown_spec.js +++ b/spec/frontend/diffs/components/settings_dropdown_spec.js @@ -1,6 +1,5 @@ import { mount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; -import diffModule from '~/diffs/store/modules'; import SettingsDropdown from '~/diffs/components/settings_dropdown.vue'; import { EVT_VIEW_FILE_BY_FILE, @@ -8,6 +7,7 @@ import { INLINE_DIFF_VIEW_TYPE, } from '~/diffs/constants'; import eventHub from '~/diffs/event_hub'; +import diffModule from '~/diffs/store/modules'; const localVue = createLocalVue(); localVue.use(Vuex); diff --git a/spec/frontend/diffs/components/tree_list_spec.js b/spec/frontend/diffs/components/tree_list_spec.js index 4666321e0c2..f316a9fdf01 100644 --- a/spec/frontend/diffs/components/tree_list_spec.js +++ b/spec/frontend/diffs/components/tree_list_spec.js @@ -1,5 +1,5 @@ -import Vuex from 'vuex'; import { shallowMount, mount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; import TreeList from '~/diffs/components/tree_list.vue'; import createStore from '~/diffs/store/modules'; import FileTree from '~/vue_shared/components/file_tree.vue'; diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js index 056ac23fcf7..ed3210ecfaf 100644 --- a/spec/frontend/diffs/store/actions_spec.js +++ b/spec/frontend/diffs/store/actions_spec.js @@ -1,9 +1,9 @@ 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 'helpers/test_constants'; import testAction from 'helpers/vuex_action_helper'; +import mockDiffFile from 'jest/diffs/mock_data/diff_file'; import { DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE, @@ -52,14 +52,14 @@ import { setFileByFile, reviewFile, } from '~/diffs/store/actions'; -import eventHub from '~/notes/event_hub'; import * as types from '~/diffs/store/mutation_types'; -import axios from '~/lib/utils/axios_utils'; import * as utils from '~/diffs/store/utils'; +import { deprecatedCreateFlash as createFlash } from '~/flash'; +import axios from '~/lib/utils/axios_utils'; import * as commonUtils from '~/lib/utils/common_utils'; import { mergeUrlParams } from '~/lib/utils/url_utility'; +import eventHub from '~/notes/event_hub'; import { diffMetadata } from '../mock_data/diff_metadata'; -import { deprecatedCreateFlash as createFlash } from '~/flash'; jest.mock('~/flash'); diff --git a/spec/frontend/diffs/store/getters_spec.js b/spec/frontend/diffs/store/getters_spec.js index 4d7f861ac22..04606b48662 100644 --- a/spec/frontend/diffs/store/getters_spec.js +++ b/spec/frontend/diffs/store/getters_spec.js @@ -1,6 +1,6 @@ +import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; import * as getters from '~/diffs/store/getters'; import state from '~/diffs/store/modules/diff_state'; -import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; import discussion from '../mock_data/diff_discussions'; describe('Diffs Module Getters', () => { @@ -376,24 +376,62 @@ describe('Diffs Module Getters', () => { }); }); - describe('fileReviews', () => { - const file1 = { id: '123', file_identifier_hash: 'abc' }; - const file2 = { id: '098', file_identifier_hash: 'abc' }; + describe('suggestionCommitMessage', () => { + beforeEach(() => { + Object.assign(localState, { + defaultSuggestionCommitMessage: + '%{branch_name}%{project_path}%{project_name}%{username}%{user_full_name}%{file_paths}%{suggestions_count}%{files_count}', + branchName: 'branch', + projectPath: '/path', + projectName: 'name', + username: 'user', + userFullName: 'user userton', + }); + }); it.each` - reviews | files | fileReviews - ${{}} | ${[file1, file2]} | ${[false, false]} - ${{ abc: ['123'] }} | ${[file1, file2]} | ${[true, false]} - ${{ abc: ['098'] }} | ${[file1, file2]} | ${[false, true]} - ${{ def: ['123'] }} | ${[file1, file2]} | ${[false, false]} - ${{ abc: ['123'], def: ['098'] }} | ${[]} | ${[]} + specialState | output + ${{}} | ${'branch/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ userFullName: null }} | ${'branch/pathnameuser%{user_full_name}%{file_paths}%{suggestions_count}%{files_count}'} + ${{ username: null }} | ${'branch/pathname%{username}user userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ projectName: null }} | ${'branch/path%{project_name}useruser userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ projectPath: null }} | ${'branch%{project_path}nameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ branchName: null }} | ${'%{branch_name}/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'} `( - 'returns $fileReviews based on the diff files in state and the existing reviews $reviews', - ({ reviews, files, fileReviews }) => { - localState.diffFiles = files; - localState.mrReviews = reviews; + 'provides the correct "base" default commit message based on state ($specialState)', + ({ specialState, output }) => { + Object.assign(localState, specialState); + + expect(getters.suggestionCommitMessage(localState)()).toBe(output); + }, + ); - expect(getters.fileReviews(localState)).toStrictEqual(fileReviews); + it.each` + stateOverrides | output + ${{}} | ${'branch/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ user_full_name: null }} | ${'branch/pathnameuser%{user_full_name}%{file_paths}%{suggestions_count}%{files_count}'} + ${{ username: null }} | ${'branch/pathname%{username}user userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ project_name: null }} | ${'branch/path%{project_name}useruser userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ project_path: null }} | ${'branch%{project_path}nameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'} + ${{ branch_name: null }} | ${'%{branch_name}/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'} + `( + "properly overrides state values ($stateOverrides) if they're provided", + ({ stateOverrides, output }) => { + expect(getters.suggestionCommitMessage(localState)(stateOverrides)).toBe(output); + }, + ); + + it.each` + providedValues | output + ${{ file_paths: 'path1, path2', suggestions_count: 1, files_count: 1 }} | ${'branch/pathnameuseruser usertonpath1, path211'} + ${{ suggestions_count: 1, files_count: 1 }} | ${'branch/pathnameuseruser userton%{file_paths}11'} + ${{ file_paths: 'path1, path2', files_count: 1 }} | ${'branch/pathnameuseruser usertonpath1, path2%{suggestions_count}1'} + ${{ file_paths: 'path1, path2', suggestions_count: 1 }} | ${'branch/pathnameuseruser usertonpath1, path21%{files_count}'} + ${{ something_unused: 'CrAzY TeXt' }} | ${'branch/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'} + `( + "fills in any missing interpolations ($providedValues) when they're provided at the getter callsite", + ({ providedValues, output }) => { + expect(getters.suggestionCommitMessage(localState)(providedValues)).toBe(output); }, ); }); diff --git a/spec/frontend/diffs/store/getters_versions_dropdowns_spec.js b/spec/frontend/diffs/store/getters_versions_dropdowns_spec.js index f7954515422..dbef547c297 100644 --- a/spec/frontend/diffs/store/getters_versions_dropdowns_spec.js +++ b/spec/frontend/diffs/store/getters_versions_dropdowns_spec.js @@ -1,9 +1,9 @@ -import * as getters from '~/diffs/store/getters'; -import state from '~/diffs/store/modules/diff_state'; import { DIFF_COMPARE_BASE_VERSION_INDEX, DIFF_COMPARE_HEAD_VERSION_INDEX, } from '~/diffs/constants'; +import * as getters from '~/diffs/store/getters'; +import state from '~/diffs/store/modules/diff_state'; import diffsMockData from '../mock_data/merge_request_diffs'; describe('Compare diff version dropdowns', () => { diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js index 2c342d8e2a5..a8ae759e693 100644 --- a/spec/frontend/diffs/store/mutations_spec.js +++ b/spec/frontend/diffs/store/mutations_spec.js @@ -1,9 +1,9 @@ +import { INLINE_DIFF_VIEW_TYPE, INLINE_DIFF_LINES_KEY } from '~/diffs/constants'; import createState from '~/diffs/store/modules/diff_state'; -import mutations from '~/diffs/store/mutations'; import * as types from '~/diffs/store/mutation_types'; -import { INLINE_DIFF_VIEW_TYPE, INLINE_DIFF_LINES_KEY } from '~/diffs/constants'; -import diffFileMockData from '../mock_data/diff_file'; +import mutations from '~/diffs/store/mutations'; import * as utils from '~/diffs/store/utils'; +import diffFileMockData from '../mock_data/diff_file'; describe('DiffsStoreMutations', () => { describe('SET_BASE_CONFIG', () => { diff --git a/spec/frontend/diffs/store/utils_spec.js b/spec/frontend/diffs/store/utils_spec.js index a19e5e91677..dcb58f7a380 100644 --- a/spec/frontend/diffs/store/utils_spec.js +++ b/spec/frontend/diffs/store/utils_spec.js @@ -1,5 +1,4 @@ import { clone } from 'lodash'; -import * as utils from '~/diffs/store/utils'; import { LINE_POSITION_LEFT, LINE_POSITION_RIGHT, @@ -12,10 +11,11 @@ import { INLINE_DIFF_VIEW_TYPE, INLINE_DIFF_LINES_KEY, } from '~/diffs/constants'; +import * as utils from '~/diffs/store/utils'; import { MERGE_REQUEST_NOTEABLE_TYPE } from '~/notes/constants'; +import { noteableDataMock } from '../../notes/mock_data'; import diffFileMockData from '../mock_data/diff_file'; import { diffMetadata } from '../mock_data/diff_metadata'; -import { noteableDataMock } from '../../notes/mock_data'; const getDiffFileMock = () => JSON.parse(JSON.stringify(diffFileMockData)); const getDiffMetadataMock = () => JSON.parse(JSON.stringify(diffMetadata)); diff --git a/spec/frontend/diffs/utils/diff_file_spec.js b/spec/frontend/diffs/utils/diff_file_spec.js index 2de8db28e71..c6cfdfced65 100644 --- a/spec/frontend/diffs/utils/diff_file_spec.js +++ b/spec/frontend/diffs/utils/diff_file_spec.js @@ -1,4 +1,4 @@ -import { prepareRawDiffFile } from '~/diffs/utils/diff_file'; +import { prepareRawDiffFile, getShortShaFromFile } from '~/diffs/utils/diff_file'; function getDiffFiles() { const loadFull = 'namespace/project/-/merge_requests/12345/diff_for_path?file_identifier=abc'; @@ -143,4 +143,15 @@ describe('diff_file utilities', () => { expect(preppedFile).not.toHaveProp('id'); }); }); + + describe('getShortShaFromFile', () => { + it.each` + response | cs + ${'12345678'} | ${'12345678abcdogcat'} + ${null} | ${undefined} + ${'hidogcat'} | ${'hidogcatmorethings'} + `('returns $response for a file with { content_sha: $cs }', ({ response, cs }) => { + expect(getShortShaFromFile({ content_sha: cs })).toBe(response); + }); + }); }); diff --git a/spec/frontend/diffs/utils/file_reviews_spec.js b/spec/frontend/diffs/utils/file_reviews_spec.js index 819426ee75f..a58c19a7245 100644 --- a/spec/frontend/diffs/utils/file_reviews_spec.js +++ b/spec/frontend/diffs/utils/file_reviews_spec.js @@ -5,6 +5,7 @@ import { setReviewsForMergeRequest, isFileReviewed, markFileReview, + reviewStatuses, reviewable, } from '~/diffs/utils/file_reviews'; @@ -28,6 +29,39 @@ describe('File Review(s) utilities', () => { localStorage.clear(); }); + describe('isFileReviewed', () => { + it.each` + description | diffFile | fileReviews + ${'the file does not have an `id`'} | ${{ ...file, id: undefined }} | ${getDefaultReviews()} + ${'there are no reviews for the file'} | ${file} | ${{ ...getDefaultReviews(), abc: undefined }} + `('returns `false` if $description', ({ diffFile, fileReviews }) => { + expect(isFileReviewed(fileReviews, diffFile)).toBe(false); + }); + + it("returns `true` for a file if it's available in the provided reviews", () => { + expect(isFileReviewed(reviews, file)).toBe(true); + }); + }); + + describe('reviewStatuses', () => { + const file1 = { id: '123', file_identifier_hash: 'abc' }; + const file2 = { id: '098', file_identifier_hash: 'abc' }; + + it.each` + mrReviews | files | fileReviews + ${{}} | ${[file1, file2]} | ${[false, false]} + ${{ abc: ['123'] }} | ${[file1, file2]} | ${[true, false]} + ${{ abc: ['098'] }} | ${[file1, file2]} | ${[false, true]} + ${{ def: ['123'] }} | ${[file1, file2]} | ${[false, false]} + ${{ abc: ['123'], def: ['098'] }} | ${[]} | ${[]} + `( + 'returns $fileReviews based on the diff files in state and the existing reviews $reviews', + ({ mrReviews, files, fileReviews }) => { + expect(reviewStatuses(files, mrReviews)).toStrictEqual(fileReviews); + }, + ); + }); + describe('getReviewsForMergeRequest', () => { it('fetches the appropriate stored reviews from localStorage', () => { getReviewsForMergeRequest(mrPath); @@ -73,20 +107,6 @@ describe('File Review(s) utilities', () => { }); }); - describe('isFileReviewed', () => { - it.each` - description | diffFile | fileReviews - ${'the file does not have an `id`'} | ${{ ...file, id: undefined }} | ${getDefaultReviews()} - ${'there are no reviews for the file'} | ${file} | ${{ ...getDefaultReviews(), abc: undefined }} - `('returns `false` if $description', ({ diffFile, fileReviews }) => { - expect(isFileReviewed(fileReviews, diffFile)).toBe(false); - }); - - it("returns `true` for a file if it's available in the provided reviews", () => { - expect(isFileReviewed(reviews, file)).toBe(true); - }); - }); - describe('reviewable', () => { it.each` response | diffFile | description diff --git a/spec/frontend/diffs/utils/preferences_spec.js b/spec/frontend/diffs/utils/preferences_spec.js index a48db1d7512..b09db2c1003 100644 --- a/spec/frontend/diffs/utils/preferences_spec.js +++ b/spec/frontend/diffs/utils/preferences_spec.js @@ -1,12 +1,11 @@ import Cookies from 'js-cookie'; -import { getParameterValues } from '~/lib/utils/url_utility'; - -import { fileByFile } from '~/diffs/utils/preferences'; import { DIFF_FILE_BY_FILE_COOKIE_NAME, DIFF_VIEW_FILE_BY_FILE, DIFF_VIEW_ALL_FILES, } from '~/diffs/constants'; +import { fileByFile } from '~/diffs/utils/preferences'; +import { getParameterValues } from '~/lib/utils/url_utility'; jest.mock('~/lib/utils/url_utility'); diff --git a/spec/frontend/diffs/utils/suggestions_spec.js b/spec/frontend/diffs/utils/suggestions_spec.js new file mode 100644 index 00000000000..fbfe9cef857 --- /dev/null +++ b/spec/frontend/diffs/utils/suggestions_spec.js @@ -0,0 +1,15 @@ +import { computeSuggestionCommitMessage } from '~/diffs/utils/suggestions'; + +describe('Diff Suggestions utilities', () => { + describe('computeSuggestionCommitMessage', () => { + it.each` + description | input | values | output + ${'makes the appropriate replacements'} | ${'%{foo} %{bar}'} | ${{ foo: 'foo', bar: 'bar' }} | ${'foo bar'} + ${"skips replacing values that aren't passed"} | ${'%{foo} %{bar}'} | ${{ foo: 'foo' }} | ${'foo %{bar}'} + ${'treats the number 0 as a valid value (not falsey)'} | ${'%{foo} %{bar}'} | ${{ foo: 'foo', bar: 0 }} | ${'foo 0'} + ${"works when the variables don't have any space between them"} | ${'%{foo}%{bar}'} | ${{ foo: 'foo', bar: 'bar' }} | ${'foobar'} + `('$description', ({ input, output, values }) => { + expect(computeSuggestionCommitMessage({ message: input, values })).toBe(output); + }); + }); +}); -- cgit v1.2.3