Commit 169a242d authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'ph/diffRowFunctionalComponent' into 'master'

Converts the diff row component into a functional component [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!63854
parents d1fbc9e1 81b9b785
...@@ -6,13 +6,17 @@ import { ...@@ -6,13 +6,17 @@ import {
OLD_NO_NEW_LINE_TYPE, OLD_NO_NEW_LINE_TYPE,
NEW_NO_NEW_LINE_TYPE, NEW_NO_NEW_LINE_TYPE,
EMPTY_CELL_TYPE, EMPTY_CELL_TYPE,
CONFLICT_MARKER_OUR,
CONFLICT_MARKER_THEIR,
CONFLICT_THEIR,
CONFLICT_OUR,
} from '../constants'; } from '../constants';
export const isHighlighted = (state, line, isCommented) => { export const isHighlighted = (highlightedRow, line, isCommented) => {
if (isCommented) return true; if (isCommented) return true;
const lineCode = line?.line_code; const lineCode = line?.line_code;
return lineCode ? lineCode === state.diffs.highlightedRow : false; return lineCode ? lineCode === highlightedRow : false;
}; };
export const isContextLine = (type) => type === CONTEXT_LINE_TYPE; export const isContextLine = (type) => type === CONTEXT_LINE_TYPE;
...@@ -50,13 +54,11 @@ export const classNameMapCell = ({ line, hll, isLoggedIn, isHover }) => { ...@@ -50,13 +54,11 @@ export const classNameMapCell = ({ line, hll, isLoggedIn, isHover }) => {
]; ];
}; };
export const addCommentTooltip = (line, dragCommentSelectionEnabled = false) => { export const addCommentTooltip = (line) => {
let tooltip; let tooltip;
if (!line) return tooltip; if (!line) return tooltip;
tooltip = dragCommentSelectionEnabled tooltip = __('Add a comment to this line or drag for multiple lines');
? __('Add a comment to this line or drag for multiple lines')
: __('Add a comment to this line');
const brokenSymlinks = line.commentsDisabled; const brokenSymlinks = line.commentsDisabled;
if (brokenSymlinks) { if (brokenSymlinks) {
...@@ -107,6 +109,10 @@ export const mapParallel = (content) => (line) => { ...@@ -107,6 +109,10 @@ export const mapParallel = (content) => (line) => {
hasDraft: content.hasParallelDraftLeft(content.diffFile.file_hash, line), hasDraft: content.hasParallelDraftLeft(content.diffFile.file_hash, line),
lineDraft: content.draftForLine(content.diffFile.file_hash, line, 'left'), lineDraft: content.draftForLine(content.diffFile.file_hash, line, 'left'),
hasCommentForm: left.hasForm, hasCommentForm: left.hasForm,
isConflictMarker:
line.left.type === CONFLICT_MARKER_OUR || line.left.type === CONFLICT_MARKER_THEIR,
emptyCellClassMap: { conflict_our: line.right?.type === CONFLICT_THEIR },
addCommentTooltip: addCommentTooltip(line.left),
}; };
} }
if (right) { if (right) {
...@@ -116,6 +122,8 @@ export const mapParallel = (content) => (line) => { ...@@ -116,6 +122,8 @@ export const mapParallel = (content) => (line) => {
hasDraft: content.hasParallelDraftRight(content.diffFile.file_hash, line), hasDraft: content.hasParallelDraftRight(content.diffFile.file_hash, line),
lineDraft: content.draftForLine(content.diffFile.file_hash, line, 'right'), lineDraft: content.draftForLine(content.diffFile.file_hash, line, 'right'),
hasCommentForm: Boolean(right.hasForm && right.type), hasCommentForm: Boolean(right.hasForm && right.type),
emptyCellClassMap: { conflict_their: line.left?.type === CONFLICT_OUR },
addCommentTooltip: addCommentTooltip(line.right),
}; };
} }
......
...@@ -3,10 +3,12 @@ import { mapGetters, mapState, mapActions } from 'vuex'; ...@@ -3,10 +3,12 @@ import { mapGetters, mapState, mapActions } from 'vuex';
import DraftNote from '~/batch_comments/components/draft_note.vue'; import DraftNote from '~/batch_comments/components/draft_note.vue';
import draftCommentsMixin from '~/diffs/mixins/draft_comments'; import draftCommentsMixin from '~/diffs/mixins/draft_comments';
import { getCommentedLines } from '~/notes/components/multiline_comment_utils'; import { getCommentedLines } from '~/notes/components/multiline_comment_utils';
import { hide } from '~/tooltips';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import DiffCommentCell from './diff_comment_cell.vue'; import DiffCommentCell from './diff_comment_cell.vue';
import DiffExpansionCell from './diff_expansion_cell.vue'; import DiffExpansionCell from './diff_expansion_cell.vue';
import DiffRow from './diff_row.vue'; import DiffRow from './diff_row.vue';
import { isHighlighted } from './diff_row_utils';
export default { export default {
components: { components: {
...@@ -43,8 +45,8 @@ export default { ...@@ -43,8 +45,8 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters('diffs', ['commitId']), ...mapGetters('diffs', ['commitId', 'fileLineCoverage']),
...mapState('diffs', ['codequalityDiff']), ...mapState('diffs', ['codequalityDiff', 'highlightedRow']),
...mapState({ ...mapState({
selectedCommentPosition: ({ notes }) => notes.selectedCommentPosition, selectedCommentPosition: ({ notes }) => notes.selectedCommentPosition,
selectedCommentPositionHover: ({ notes }) => notes.selectedCommentPositionHover, selectedCommentPositionHover: ({ notes }) => notes.selectedCommentPositionHover,
...@@ -67,14 +69,17 @@ export default { ...@@ -67,14 +69,17 @@ export default {
}, },
methods: { methods: {
...mapActions(['setSelectedCommentPosition']), ...mapActions(['setSelectedCommentPosition']),
...mapActions('diffs', ['showCommentForm']), ...mapActions('diffs', ['showCommentForm', 'setHighlightedRow', 'toggleLineDiscussions']),
showCommentLeft(line) { showCommentLeft(line) {
return line.left && !line.right; return line.left && !line.right;
}, },
showCommentRight(line) { showCommentRight(line) {
return line.right && !line.left; return line.right && !line.left;
}, },
onStartDragging(line) { onStartDragging({ event = {}, line }) {
if (event.target?.parentNode) {
hide(event.target.parentNode);
}
this.dragStart = line; this.dragStart = line;
}, },
onDragOver(line) { onDragOver(line) {
...@@ -99,6 +104,26 @@ export default { ...@@ -99,6 +104,26 @@ export default {
}); });
this.dragStart = null; this.dragStart = null;
}, },
isHighlighted(line) {
return isHighlighted(
this.highlightedRow,
line.left?.line_code ? line.left : line.right,
false,
);
},
handleParallelLineMouseDown(e) {
const line = e.target.closest('.diff-td');
const table = line.closest('.diff-table');
table.classList.remove('left-side-selected', 'right-side-selected');
const [lineClass] = ['left-side', 'right-side'].filter((name) =>
line.classList.contains(name),
);
if (lineClass) {
table.classList.add(`${lineClass}-selected`);
}
},
}, },
userColorScheme: window.gon.user_color_scheme, userColorScheme: window.gon.user_color_scheme,
}; };
...@@ -109,6 +134,7 @@ export default { ...@@ -109,6 +134,7 @@ export default {
:class="[$options.userColorScheme, { inline, 'with-codequality': hasCodequalityChanges }]" :class="[$options.userColorScheme, { inline, 'with-codequality': hasCodequalityChanges }]"
:data-commit-id="commitId" :data-commit-id="commitId"
class="diff-grid diff-table code diff-wrap-lines js-syntax-highlight text-file" class="diff-grid diff-table code diff-wrap-lines js-syntax-highlight text-file"
@mousedown="handleParallelLineMouseDown"
> >
<template v-for="(line, index) in diffLines"> <template v-for="(line, index) in diffLines">
<div <div
...@@ -136,6 +162,14 @@ export default { ...@@ -136,6 +162,14 @@ export default {
:is-commented="index >= commentedLines.startLine && index <= commentedLines.endLine" :is-commented="index >= commentedLines.startLine && index <= commentedLines.endLine"
:inline="inline" :inline="inline"
:index="index" :index="index"
:is-highlighted="isHighlighted(line)"
:file-line-coverage="fileLineCoverage"
@showCommentForm="(lineCode) => showCommentForm({ lineCode, fileHash: diffFile.file_hash })"
@setHighlightedRow="setHighlightedRow"
@toggleLineDiscussions="
({ lineCode, expanded }) =>
toggleLineDiscussions({ lineCode, fileHash: diffFile.file_hash, expanded })
"
@enterdragging="onDragOver" @enterdragging="onDragOver"
@startdragging="onStartDragging" @startdragging="onStartDragging"
@stopdragging="onStopDragging" @stopdragging="onStopDragging"
......
...@@ -235,6 +235,8 @@ export const setHighlightedRow = ({ commit }, lineCode) => { ...@@ -235,6 +235,8 @@ export const setHighlightedRow = ({ commit }, lineCode) => {
const fileHash = lineCode.split('_')[0]; const fileHash = lineCode.split('_')[0];
commit(types.SET_HIGHLIGHTED_ROW, lineCode); commit(types.SET_HIGHLIGHTED_ROW, lineCode);
commit(types.VIEW_DIFF_FILE, fileHash); commit(types.VIEW_DIFF_FILE, fileHash);
handleLocationHash();
}; };
// This is adding line discussions to the actual lines in the diff tree // This is adding line discussions to the actual lines in the diff tree
......
import AccessorUtilities from '~/lib/utils/accessor'; import AccessorUtilities from '~/lib/utils/accessor';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { getGroups, getProjects } from '~/rest_api'; import { getGroups, getProjects } from '~/rest_api';
import { getTopFrequentItems } from '../utils'; import { getTopFrequentItems } from '../utils';
import * as types from './mutation_types'; import * as types from './mutation_types';
...@@ -51,7 +52,7 @@ export const fetchSearchedItems = ({ state, dispatch }, searchQuery) => { ...@@ -51,7 +52,7 @@ export const fetchSearchedItems = ({ state, dispatch }, searchQuery) => {
const params = { const params = {
simple: true, simple: true,
per_page: 20, per_page: 20,
membership: Boolean(gon.current_user_id), membership: isLoggedIn(),
}; };
let searchFunction; let searchFunction;
......
...@@ -763,3 +763,5 @@ export const isFeatureFlagEnabled = (flag) => window.gon.features?.[flag]; ...@@ -763,3 +763,5 @@ export const isFeatureFlagEnabled = (flag) => window.gon.features?.[flag];
* @returns {Array[String]} Converted array * @returns {Array[String]} Converted array
*/ */
export const convertArrayToCamelCase = (array) => array.map((i) => convertToCamelCase(i)); export const convertArrayToCamelCase = (array) => array.map((i) => convertToCamelCase(i));
export const isLoggedIn = () => Boolean(window.gon?.current_user_id);
...@@ -4,6 +4,7 @@ import { mapActions, mapGetters } from 'vuex'; ...@@ -4,6 +4,7 @@ import { mapActions, mapGetters } from 'vuex';
import DraftNote from '~/batch_comments/components/draft_note.vue'; import DraftNote from '~/batch_comments/components/draft_note.vue';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { clearDraft, getDiscussionReplyKey } from '~/lib/utils/autosave'; import { clearDraft, getDiscussionReplyKey } from '~/lib/utils/autosave';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import diffLineNoteFormMixin from '~/notes/mixins/diff_line_note_form'; import diffLineNoteFormMixin from '~/notes/mixins/diff_line_note_form';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
...@@ -85,7 +86,7 @@ export default { ...@@ -85,7 +86,7 @@ export default {
return this.getUserData; return this.getUserData;
}, },
isLoggedIn() { isLoggedIn() {
return Boolean(gon.current_user_id); return isLoggedIn();
}, },
autosaveKey() { autosaveKey() {
return getDiscussionReplyKey(this.firstNote.noteable_type, this.discussion.id); return getDiscussionReplyKey(this.firstNote.noteable_type, this.discussion.id);
......
...@@ -5,6 +5,7 @@ import BlobContent from '~/blob/components/blob_content.vue'; ...@@ -5,6 +5,7 @@ import BlobContent from '~/blob/components/blob_content.vue';
import BlobHeader from '~/blob/components/blob_header.vue'; import BlobHeader from '~/blob/components/blob_header.vue';
import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants'; import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import blobInfoQuery from '../queries/blob_info.query.graphql'; import blobInfoQuery from '../queries/blob_info.query.graphql';
import BlobButtonGroup from './blob_button_group.vue'; import BlobButtonGroup from './blob_button_group.vue';
...@@ -90,7 +91,7 @@ export default { ...@@ -90,7 +91,7 @@ export default {
}, },
computed: { computed: {
isLoggedIn() { isLoggedIn() {
return Boolean(gon.current_user_id); return isLoggedIn();
}, },
isLoading() { isLoading() {
return this.$apollo.queries.project.loading; return this.$apollo.queries.project.loading;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { GlIcon, GlLoadingIcon, GlToggle, GlTooltipDirective } from '@gitlab/ui'; import { GlIcon, GlLoadingIcon, GlToggle, GlTooltipDirective } from '@gitlab/ui';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { IssuableType } from '~/issue_show/constants'; import { IssuableType } from '~/issue_show/constants';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import { subscribedQueries } from '~/sidebar/constants'; import { subscribedQueries } from '~/sidebar/constants';
...@@ -102,7 +103,7 @@ export default { ...@@ -102,7 +103,7 @@ export default {
}); });
}, },
isLoggedIn() { isLoggedIn() {
return Boolean(gon.current_user_id); return isLoggedIn();
}, },
canSubscribe() { canSubscribe() {
return this.emailsDisabled || !this.isLoggedIn; return this.emailsDisabled || !this.isLoggedIn;
......
<script> <script>
import { GlButton, GlLoadingIcon, GlTooltipDirective, GlIcon } from '@gitlab/ui'; import { GlButton, GlLoadingIcon, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import ApplySuggestion from './apply_suggestion.vue'; import ApplySuggestion from './apply_suggestion.vue';
...@@ -73,7 +74,7 @@ export default { ...@@ -73,7 +74,7 @@ export default {
return __('Applying suggestions...'); return __('Applying suggestions...');
}, },
isLoggedIn() { isLoggedIn() {
return Boolean(gon.current_user_id); return isLoggedIn();
}, },
}, },
methods: { methods: {
......
...@@ -763,6 +763,7 @@ $system-note-svg-size: 16px; ...@@ -763,6 +763,7 @@ $system-note-svg-size: 16px;
.note-button.add-diff-note { .note-button.add-diff-note {
@include btn-comment-icon; @include btn-comment-icon;
opacity: 0; opacity: 0;
will-change: opacity;
&[disabled] { &[disabled] {
background: $white; background: $white;
......
...@@ -32,7 +32,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -32,7 +32,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:file_identifier_hash) push_frontend_feature_flag(:file_identifier_hash)
push_frontend_feature_flag(:approvals_commented_by, @project, default_enabled: true) push_frontend_feature_flag(:approvals_commented_by, @project, default_enabled: true)
push_frontend_feature_flag(:merge_request_widget_graphql, @project, default_enabled: :yaml) push_frontend_feature_flag(:merge_request_widget_graphql, @project, default_enabled: :yaml)
push_frontend_feature_flag(:drag_comment_selection, @project, default_enabled: true)
push_frontend_feature_flag(:default_merge_ref_for_diffs, @project, default_enabled: :yaml) push_frontend_feature_flag(:default_merge_ref_for_diffs, @project, default_enabled: :yaml)
push_frontend_feature_flag(:core_security_mr_widget_counts, @project) push_frontend_feature_flag(:core_security_mr_widget_counts, @project)
push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml) push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml)
......
---
name: drag_comment_selection
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49875
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/293945
milestone: '13.7'
type: development
group: group::source code
default_enabled: true
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import CodeQualityGutterIcon from 'ee/diffs/components/code_quality_gutter_icon.vue';
import DiffRow from '~/diffs/components/diff_row.vue'; import DiffRow from '~/diffs/components/diff_row.vue';
import diffsModule from '~/diffs/store/modules'; import diffsModule from '~/diffs/store/modules';
...@@ -10,16 +9,24 @@ Vue.use(Vuex); ...@@ -10,16 +9,24 @@ Vue.use(Vuex);
describe('EE DiffRow', () => { describe('EE DiffRow', () => {
let wrapper; let wrapper;
const findIcon = () => wrapper.findComponent(CodeQualityGutterIcon); const findIcon = () => wrapper.find('[data-testid="codeQualityIcon"]');
const defaultProps = { const defaultProps = {
fileHash: 'abc', fileHash: 'abc',
filePath: 'abc', filePath: 'abc',
line: {}, line: {},
index: 0, index: 0,
isHighlighted: false,
fileLineCoverage: () => ({}),
}; };
const createComponent = ({ props, state, actions, isLoggedIn = true, provide }) => { const createComponent = ({
props,
state,
actions,
isLoggedIn = true,
codequalityMrDiffAnnotations,
}) => {
const diffs = diffsModule(); const diffs = diffsModule();
diffs.state = { ...diffs.state, ...state }; diffs.state = { ...diffs.state, ...state };
diffs.actions = { ...diffs.actions, ...actions }; diffs.actions = { ...diffs.actions, ...actions };
...@@ -31,18 +38,38 @@ describe('EE DiffRow', () => { ...@@ -31,18 +38,38 @@ describe('EE DiffRow', () => {
getters, getters,
}); });
wrapper = shallowMount(DiffRow, { propsData: { ...defaultProps, ...props }, store, provide }); window.gon = { features: { codequalityMrDiffAnnotations } };
wrapper = shallowMount(DiffRow, {
propsData: { ...defaultProps, ...props },
store,
listeners: {
enterdragging: () => {},
stopdragging: () => {},
showCommentForm: () => {},
setHighlightedRow: () => {},
},
});
}; };
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
window.gon = {};
Object.values(DiffRow).forEach(({ cache }) => {
if (cache) {
cache.clear();
}
});
}); });
describe('with feature flag enabled', () => { describe('with feature flag enabled', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
props: { line: { right: { codequality: [{ severity: 'critical' }] } } }, props: { line: { right: { codequality: [{ severity: 'critical' }] } } },
provide: { glFeatures: { codequalityMrDiffAnnotations: true } }, codequalityMrDiffAnnotations: true,
}); });
}); });
...@@ -55,7 +82,7 @@ describe('EE DiffRow', () => { ...@@ -55,7 +82,7 @@ describe('EE DiffRow', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
props: { line: { right: { codequality: [{ severity: 'critical' }] } } }, props: { line: { right: { codequality: [{ severity: 'critical' }] } } },
provide: { glFeatures: { codequalityMrDiffAnnotations: false } }, codequalityMrDiffAnnotations: false,
}); });
}); });
......
...@@ -8,6 +8,12 @@ import diffsModule from '~/diffs/store/modules'; ...@@ -8,6 +8,12 @@ import diffsModule from '~/diffs/store/modules';
import { findInteropAttributes } from '../find_interop_attributes'; import { findInteropAttributes } from '../find_interop_attributes';
import diffFileMockData from '../mock_data/diff_file'; import diffFileMockData from '../mock_data/diff_file';
const showCommentForm = jest.fn();
const enterdragging = jest.fn();
const stopdragging = jest.fn();
const setHighlightedRow = jest.fn();
let wrapper;
describe('DiffRow', () => { describe('DiffRow', () => {
const testLines = [ const testLines = [
{ {
...@@ -29,7 +35,7 @@ describe('DiffRow', () => { ...@@ -29,7 +35,7 @@ describe('DiffRow', () => {
}, },
]; ];
const createWrapper = ({ props, state, actions, isLoggedIn = true }) => { const createWrapper = ({ props, state = {}, actions, isLoggedIn = true }) => {
Vue.use(Vuex); Vue.use(Vuex);
const diffs = diffsModule(); const diffs = diffsModule();
...@@ -43,11 +49,25 @@ describe('DiffRow', () => { ...@@ -43,11 +49,25 @@ describe('DiffRow', () => {
getters, getters,
}); });
window.gon = { current_user_id: isLoggedIn ? 1 : 0 };
const coverageFileData = state.coverageFiles?.files ? state.coverageFiles.files : {};
const propsData = { const propsData = {
fileHash: 'abc', fileHash: 'abc',
filePath: 'abc', filePath: 'abc',
line: {}, line: {},
index: 0, index: 0,
isHighlighted: false,
fileLineCoverage: (file, line) => {
const hits = coverageFileData[file]?.[line];
if (hits) {
return { text: `Test coverage: ${hits} hits`, class: 'coverage' };
} else if (hits === 0) {
return { text: 'No test coverage', class: 'no-coverage' };
}
return {};
},
...props, ...props,
}; };
...@@ -55,49 +75,37 @@ describe('DiffRow', () => { ...@@ -55,49 +75,37 @@ describe('DiffRow', () => {
glFeatures: { dragCommentSelection: true }, glFeatures: { dragCommentSelection: true },
}; };
return shallowMount(DiffRow, { propsData, store, provide }); return shallowMount(DiffRow, {
propsData,
store,
provide,
listeners: {
enterdragging,
stopdragging,
setHighlightedRow,
showCommentForm,
},
});
}; };
it('isHighlighted returns true given line.left', () => { afterEach(() => {
const props = { wrapper.destroy();
line: { wrapper = null;
left: {
line_code: 'abc',
},
},
};
const state = { highlightedRow: 'abc' };
const wrapper = createWrapper({ props, state });
expect(wrapper.vm.isHighlighted).toBe(true);
});
it('isHighlighted returns true given line.right', () => { window.gon = {};
const props = { showCommentForm.mockReset();
line: { enterdragging.mockReset();
right: { stopdragging.mockReset();
line_code: 'abc', setHighlightedRow.mockReset();
},
},
};
const state = { highlightedRow: 'abc' };
const wrapper = createWrapper({ props, state });
expect(wrapper.vm.isHighlighted).toBe(true);
});
it('isHighlighted returns false given line.left', () => { Object.values(DiffRow).forEach(({ cache }) => {
const props = { if (cache) {
line: { cache.clear();
left: { }
line_code: 'abc', });
},
},
};
const wrapper = createWrapper({ props });
expect(wrapper.vm.isHighlighted).toBe(false);
}); });
const getCommentButton = (wrapper, side) => const getCommentButton = (side) => wrapper.find(`[data-testid="${side}-comment-button"]`);
wrapper.find(`[data-testid="${side}-comment-button"]`);
describe.each` describe.each`
side side
...@@ -105,33 +113,30 @@ describe('DiffRow', () => { ...@@ -105,33 +113,30 @@ describe('DiffRow', () => {
${'right'} ${'right'}
`('$side side', ({ side }) => { `('$side side', ({ side }) => {
it(`renders empty cells if ${side} is unavailable`, () => { it(`renders empty cells if ${side} is unavailable`, () => {
const wrapper = createWrapper({ props: { line: testLines[2], inline: false } }); wrapper = createWrapper({ props: { line: testLines[2], inline: false } });
expect(wrapper.find(`[data-testid="${side}-line-number"]`).exists()).toBe(false); expect(wrapper.find(`[data-testid="${side}-line-number"]`).exists()).toBe(false);
expect(wrapper.find(`[data-testid="${side}-empty-cell"]`).exists()).toBe(true); expect(wrapper.find(`[data-testid="${side}-empty-cell"]`).exists()).toBe(true);
}); });
describe('comment button', () => { describe('comment button', () => {
const showCommentForm = jest.fn();
let line; let line;
beforeEach(() => { beforeEach(() => {
showCommentForm.mockReset();
// https://eslint.org/docs/rules/prefer-destructuring#when-not-to-use-it // https://eslint.org/docs/rules/prefer-destructuring#when-not-to-use-it
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
line = testLines[3]; line = testLines[3];
}); });
it('renders', () => { it('renders', () => {
const wrapper = createWrapper({ props: { line, inline: false } }); wrapper = createWrapper({ props: { line, inline: false } });
expect(getCommentButton(wrapper, side).exists()).toBe(true); expect(getCommentButton(side).exists()).toBe(true);
}); });
it('responds to click and keyboard events', async () => { it('responds to click and keyboard events', async () => {
const wrapper = createWrapper({ wrapper = createWrapper({
props: { line, inline: false }, props: { line, inline: false },
actions: { showCommentForm },
}); });
const commentButton = getCommentButton(wrapper, side); const commentButton = getCommentButton(side);
await commentButton.trigger('click'); await commentButton.trigger('click');
await commentButton.trigger('keydown.enter'); await commentButton.trigger('keydown.enter');
...@@ -142,11 +147,10 @@ describe('DiffRow', () => { ...@@ -142,11 +147,10 @@ describe('DiffRow', () => {
it('ignores click and keyboard events when comments are disabled', async () => { it('ignores click and keyboard events when comments are disabled', async () => {
line[side].commentsDisabled = true; line[side].commentsDisabled = true;
const wrapper = createWrapper({ wrapper = createWrapper({
props: { line, inline: false }, props: { line, inline: false },
actions: { showCommentForm },
}); });
const commentButton = getCommentButton(wrapper, side); const commentButton = getCommentButton(side);
await commentButton.trigger('click'); await commentButton.trigger('click');
await commentButton.trigger('keydown.enter'); await commentButton.trigger('keydown.enter');
...@@ -157,19 +161,20 @@ describe('DiffRow', () => { ...@@ -157,19 +161,20 @@ describe('DiffRow', () => {
}); });
it('renders avatars', () => { it('renders avatars', () => {
const wrapper = createWrapper({ props: { line: testLines[0], inline: false } }); wrapper = createWrapper({ props: { line: testLines[0], inline: false } });
expect(wrapper.find(`[data-testid="${side}-discussions"]`).exists()).toBe(true); expect(wrapper.find(`[data-testid="${side}-discussions"]`).exists()).toBe(true);
}); });
}); });
it('renders left line numbers', () => { it('renders left line numbers', () => {
const wrapper = createWrapper({ props: { line: testLines[0] } }); wrapper = createWrapper({ props: { line: testLines[0] } });
const lineNumber = testLines[0].left.old_line; const lineNumber = testLines[0].left.old_line;
expect(wrapper.find(`[data-linenumber="${lineNumber}"]`).exists()).toBe(true); expect(wrapper.find(`[data-linenumber="${lineNumber}"]`).exists()).toBe(true);
}); });
it('renders right line numbers', () => { it('renders right line numbers', () => {
const wrapper = createWrapper({ props: { line: testLines[0] } }); wrapper = createWrapper({ props: { line: testLines[0] } });
const lineNumber = testLines[0].right.new_line; const lineNumber = testLines[0].right.new_line;
expect(wrapper.find(`[data-linenumber="${lineNumber}"]`).exists()).toBe(true); expect(wrapper.find(`[data-linenumber="${lineNumber}"]`).exists()).toBe(true);
}); });
...@@ -186,12 +191,10 @@ describe('DiffRow', () => { ...@@ -186,12 +191,10 @@ describe('DiffRow', () => {
${'left'} ${'left'}
${'right'} ${'right'}
`('emits `enterdragging` onDragEnter $side side', ({ side }) => { `('emits `enterdragging` onDragEnter $side side', ({ side }) => {
const expectation = { ...line[side], index: 0 }; wrapper = createWrapper({ props: { line } });
const wrapper = createWrapper({ props: { line } });
fireEvent.dragEnter(getByTestId(wrapper.element, `${side}-side`)); fireEvent.dragEnter(getByTestId(wrapper.element, `${side}-side`));
expect(wrapper.emitted().enterdragging).toBeTruthy(); expect(enterdragging).toHaveBeenCalledWith({ ...line[side], index: 0 });
expect(wrapper.emitted().enterdragging[0]).toEqual([expectation]);
}); });
it.each` it.each`
...@@ -199,10 +202,10 @@ describe('DiffRow', () => { ...@@ -199,10 +202,10 @@ describe('DiffRow', () => {
${'left'} ${'left'}
${'right'} ${'right'}
`('emits `stopdragging` onDrop $side side', ({ side }) => { `('emits `stopdragging` onDrop $side side', ({ side }) => {
const wrapper = createWrapper({ props: { line } }); wrapper = createWrapper({ props: { line } });
fireEvent.dragEnd(getByTestId(wrapper.element, `${side}-side`)); fireEvent.dragEnd(getByTestId(wrapper.element, `${side}-side`));
expect(wrapper.emitted().stopdragging).toBeTruthy(); expect(stopdragging).toHaveBeenCalled();
}); });
}); });
...@@ -231,7 +234,7 @@ describe('DiffRow', () => { ...@@ -231,7 +234,7 @@ describe('DiffRow', () => {
it('for lines with coverage', () => { it('for lines with coverage', () => {
const coverageFiles = { files: { [name]: { [line]: 5 } } }; const coverageFiles = { files: { [name]: { [line]: 5 } } };
const wrapper = createWrapper({ props, state: { coverageFiles } }); wrapper = createWrapper({ props, state: { coverageFiles } });
const coverage = wrapper.find('.line-coverage.right-side'); const coverage = wrapper.find('.line-coverage.right-side');
expect(coverage.attributes('title')).toContain('Test coverage: 5 hits'); expect(coverage.attributes('title')).toContain('Test coverage: 5 hits');
...@@ -240,7 +243,7 @@ describe('DiffRow', () => { ...@@ -240,7 +243,7 @@ describe('DiffRow', () => {
it('for lines without coverage', () => { it('for lines without coverage', () => {
const coverageFiles = { files: { [name]: { [line]: 0 } } }; const coverageFiles = { files: { [name]: { [line]: 0 } } };
const wrapper = createWrapper({ props, state: { coverageFiles } }); wrapper = createWrapper({ props, state: { coverageFiles } });
const coverage = wrapper.find('.line-coverage.right-side'); const coverage = wrapper.find('.line-coverage.right-side');
expect(coverage.attributes('title')).toContain('No test coverage'); expect(coverage.attributes('title')).toContain('No test coverage');
...@@ -249,7 +252,7 @@ describe('DiffRow', () => { ...@@ -249,7 +252,7 @@ describe('DiffRow', () => {
it('for unknown lines', () => { it('for unknown lines', () => {
const coverageFiles = {}; const coverageFiles = {};
const wrapper = createWrapper({ props, state: { coverageFiles } }); wrapper = createWrapper({ props, state: { coverageFiles } });
const coverage = wrapper.find('.line-coverage.right-side'); const coverage = wrapper.find('.line-coverage.right-side');
expect(coverage.attributes('title')).toBeFalsy(); expect(coverage.attributes('title')).toBeFalsy();
...@@ -267,7 +270,7 @@ describe('DiffRow', () => { ...@@ -267,7 +270,7 @@ describe('DiffRow', () => {
${'with parallel and no left side'} | ${{ right: { old_line: 3, new_line: 5 } }} | ${false} | ${null} | ${{ type: 'new', line: '5', newLine: '5' }} ${'with parallel and no left side'} | ${{ right: { old_line: 3, new_line: 5 } }} | ${false} | ${null} | ${{ type: 'new', line: '5', newLine: '5' }}
${'with parallel and right side'} | ${{ left: { old_line: 3 }, right: { new_line: 5 } }} | ${false} | ${{ type: 'old', line: '3', oldLine: '3' }} | ${{ type: 'new', line: '5', newLine: '5' }} ${'with parallel and right side'} | ${{ left: { old_line: 3 }, right: { new_line: 5 } }} | ${false} | ${{ type: 'old', line: '3', oldLine: '3' }} | ${{ type: 'new', line: '5', newLine: '5' }}
`('$desc, sets interop data attributes', ({ line, inline, leftSide, rightSide }) => { `('$desc, sets interop data attributes', ({ line, inline, leftSide, rightSide }) => {
const wrapper = createWrapper({ props: { line, inline } }); wrapper = createWrapper({ props: { line, inline } });
expect(findInteropAttributes(wrapper, '[data-testid="left-side"]')).toEqual(leftSide); expect(findInteropAttributes(wrapper, '[data-testid="left-side"]')).toEqual(leftSide);
expect(findInteropAttributes(wrapper, '[data-testid="right-side"]')).toEqual(rightSide); expect(findInteropAttributes(wrapper, '[data-testid="right-side"]')).toEqual(rightSide);
......
...@@ -11,24 +11,21 @@ const LINE_CODE = 'abc123'; ...@@ -11,24 +11,21 @@ const LINE_CODE = 'abc123';
describe('isHighlighted', () => { describe('isHighlighted', () => {
it('should return true if line is highlighted', () => { it('should return true if line is highlighted', () => {
const state = { diffs: { highlightedRow: LINE_CODE } };
const line = { line_code: LINE_CODE }; const line = { line_code: LINE_CODE };
const isCommented = false; const isCommented = false;
expect(utils.isHighlighted(state, line, isCommented)).toBe(true); expect(utils.isHighlighted(LINE_CODE, line, isCommented)).toBe(true);
}); });
it('should return false if line is not highlighted', () => { it('should return false if line is not highlighted', () => {
const state = { diffs: { highlightedRow: 'xxx' } };
const line = { line_code: LINE_CODE }; const line = { line_code: LINE_CODE };
const isCommented = false; const isCommented = false;
expect(utils.isHighlighted(state, line, isCommented)).toBe(false); expect(utils.isHighlighted('xxx', line, isCommented)).toBe(false);
}); });
it('should return true if isCommented is true', () => { it('should return true if isCommented is true', () => {
const state = { diffs: { highlightedRow: 'xxx' } };
const line = { line_code: LINE_CODE }; const line = { line_code: LINE_CODE };
const isCommented = true; const isCommented = true;
expect(utils.isHighlighted(state, line, isCommented)).toBe(true); expect(utils.isHighlighted('xxx', line, isCommented)).toBe(true);
}); });
}); });
...@@ -143,19 +140,14 @@ describe('addCommentTooltip', () => { ...@@ -143,19 +140,14 @@ describe('addCommentTooltip', () => {
'Commenting on symbolic links that replace or are replaced by files is currently not supported.'; 'Commenting on symbolic links that replace or are replaced by files is currently not supported.';
const brokenRealTooltip = const brokenRealTooltip =
'Commenting on files that replace or are replaced by symbolic links is currently not supported.'; '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'; const dragTooltip = 'Add a comment to this line or drag for multiple lines';
it('should return default tooltip', () => { it('should return default tooltip', () => {
expect(utils.addCommentTooltip()).toBeUndefined(); expect(utils.addCommentTooltip()).toBeUndefined();
}); });
it('should return comment tooltip', () => {
expect(utils.addCommentTooltip({})).toEqual(commentTooltip);
});
it('should return drag comment tooltip when dragging is enabled', () => { it('should return drag comment tooltip when dragging is enabled', () => {
expect(utils.addCommentTooltip({}, true)).toEqual(dragTooltip); expect(utils.addCommentTooltip({})).toEqual(dragTooltip);
}); });
it('should return broken symlink tooltip', () => { it('should return broken symlink tooltip', () => {
......
...@@ -28,7 +28,7 @@ describe('DiffView', () => { ...@@ -28,7 +28,7 @@ describe('DiffView', () => {
}; };
const diffs = { const diffs = {
actions: { showCommentForm }, actions: { showCommentForm },
getters: { commitId: () => 'abc123' }, getters: { commitId: () => 'abc123', fileLineCoverage: () => ({}) },
namespaced: true, namespaced: true,
}; };
const notes = { const notes = {
...@@ -84,7 +84,7 @@ describe('DiffView', () => { ...@@ -84,7 +84,7 @@ describe('DiffView', () => {
it('sets `dragStart` onStartDragging', () => { it('sets `dragStart` onStartDragging', () => {
const wrapper = createWrapper({ diffLines: [{}] }); const wrapper = createWrapper({ diffLines: [{}] });
wrapper.findComponent(DiffRow).vm.$emit('startdragging', { test: true }); wrapper.findComponent(DiffRow).vm.$emit('startdragging', { line: { test: true } });
expect(wrapper.vm.dragStart).toEqual({ test: true }); expect(wrapper.vm.dragStart).toEqual({ test: true });
}); });
...@@ -92,7 +92,7 @@ describe('DiffView', () => { ...@@ -92,7 +92,7 @@ describe('DiffView', () => {
const wrapper = createWrapper({ diffLines: [{}] }); const wrapper = createWrapper({ diffLines: [{}] });
const diffRow = getDiffRow(wrapper); const diffRow = getDiffRow(wrapper);
diffRow.$emit('startdragging', { chunk: 0 }); diffRow.$emit('startdragging', { line: { chunk: 0 } });
diffRow.$emit('enterdragging', { chunk: 1 }); diffRow.$emit('enterdragging', { chunk: 1 });
expect(setSelectedCommentPosition).not.toHaveBeenCalled(); expect(setSelectedCommentPosition).not.toHaveBeenCalled();
...@@ -109,7 +109,7 @@ describe('DiffView', () => { ...@@ -109,7 +109,7 @@ describe('DiffView', () => {
const wrapper = createWrapper({ diffLines: [{}] }); const wrapper = createWrapper({ diffLines: [{}] });
const diffRow = getDiffRow(wrapper); const diffRow = getDiffRow(wrapper);
diffRow.$emit('startdragging', { chunk: 1, index: start }); diffRow.$emit('startdragging', { line: { chunk: 1, index: start } });
diffRow.$emit('enterdragging', { chunk: 1, index: end }); diffRow.$emit('enterdragging', { chunk: 1, index: end });
const arg = setSelectedCommentPosition.mock.calls[0][1]; const arg = setSelectedCommentPosition.mock.calls[0][1];
...@@ -122,7 +122,7 @@ describe('DiffView', () => { ...@@ -122,7 +122,7 @@ describe('DiffView', () => {
const wrapper = createWrapper({ diffLines: [{}] }); const wrapper = createWrapper({ diffLines: [{}] });
const diffRow = getDiffRow(wrapper); const diffRow = getDiffRow(wrapper);
diffRow.$emit('startdragging', { test: true }); diffRow.$emit('startdragging', { line: { test: true } });
expect(wrapper.vm.dragStart).toEqual({ test: true }); expect(wrapper.vm.dragStart).toEqual({ test: true });
diffRow.$emit('stopdragging'); diffRow.$emit('stopdragging');
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment