Commit ef1b4bd4 authored by Miranda Fluharty's avatar Miranda Fluharty Committed by Scott Hampton

Show code quality badge on files in MR diff view

parent a3cf10c2
...@@ -84,6 +84,11 @@ export default { ...@@ -84,6 +84,11 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
endpointCodequality: {
type: String,
required: false,
default: '',
},
projectPath: { projectPath: {
type: String, type: String,
required: true, required: true,
...@@ -160,6 +165,7 @@ export default { ...@@ -160,6 +165,7 @@ export default {
plainDiffPath: (state) => state.diffs.plainDiffPath, plainDiffPath: (state) => state.diffs.plainDiffPath,
emailPatchPath: (state) => state.diffs.emailPatchPath, emailPatchPath: (state) => state.diffs.emailPatchPath,
retrievingBatches: (state) => state.diffs.retrievingBatches, retrievingBatches: (state) => state.diffs.retrievingBatches,
codequalityDiff: (state) => state.diffs.codequalityDiff,
}), }),
...mapState('diffs', [ ...mapState('diffs', [
'showTreeList', 'showTreeList',
...@@ -173,7 +179,12 @@ export default { ...@@ -173,7 +179,12 @@ export default {
'viewDiffsFileByFile', 'viewDiffsFileByFile',
'mrReviews', 'mrReviews',
]), ]),
...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']), ...mapGetters('diffs', [
'whichCollapsedTypes',
'isParallelView',
'currentDiffIndex',
'fileCodequalityDiff',
]),
...mapGetters(['isNotesFetched', 'getNoteableData']), ...mapGetters(['isNotesFetched', 'getNoteableData']),
diffs() { diffs() {
if (!this.viewDiffsFileByFile) { if (!this.viewDiffsFileByFile) {
...@@ -271,6 +282,7 @@ export default { ...@@ -271,6 +282,7 @@ export default {
endpointMetadata: this.endpointMetadata, endpointMetadata: this.endpointMetadata,
endpointBatch: this.endpointBatch, endpointBatch: this.endpointBatch,
endpointCoverage: this.endpointCoverage, endpointCoverage: this.endpointCoverage,
endpointCodequality: this.endpointCodequality,
projectPath: this.projectPath, projectPath: this.projectPath,
dismissEndpoint: this.dismissEndpoint, dismissEndpoint: this.dismissEndpoint,
showSuggestPopover: this.showSuggestPopover, showSuggestPopover: this.showSuggestPopover,
...@@ -326,6 +338,7 @@ export default { ...@@ -326,6 +338,7 @@ export default {
'fetchDiffFilesMeta', 'fetchDiffFilesMeta',
'fetchDiffFilesBatch', 'fetchDiffFilesBatch',
'fetchCoverageFiles', 'fetchCoverageFiles',
'fetchCodequality',
'startRenderDiffsQueue', 'startRenderDiffsQueue',
'assignDiscussionsToDiff', 'assignDiscussionsToDiff',
'setHighlightedRow', 'setHighlightedRow',
...@@ -382,6 +395,10 @@ export default { ...@@ -382,6 +395,10 @@ export default {
this.fetchCoverageFiles(); this.fetchCoverageFiles();
} }
if (this.endpointCodequality) {
this.fetchCodequality();
}
if (!this.isNotesFetched) { if (!this.isNotesFetched) {
notesEventHub.$emit('fetchNotesData'); notesEventHub.$emit('fetchNotesData');
} }
...@@ -509,6 +526,7 @@ export default { ...@@ -509,6 +526,7 @@ export default {
:help-page-path="helpPagePath" :help-page-path="helpPagePath"
:can-current-user-fork="canCurrentUserFork" :can-current-user-fork="canCurrentUserFork"
:view-diffs-file-by-file="viewDiffsFileByFile" :view-diffs-file-by-file="viewDiffsFileByFile"
:codequality-diff="fileCodequalityDiff(file.file_path)"
/> />
<div <div
v-if="showFileByFileNavigation" v-if="showFileByFileNavigation"
......
...@@ -67,6 +67,11 @@ export default { ...@@ -67,6 +67,11 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
codequalityDiff: {
type: Array,
required: false,
default: () => [],
},
}, },
data() { data() {
return { return {
...@@ -148,6 +153,9 @@ export default { ...@@ -148,6 +153,9 @@ export default {
return loggedIn && featureOn; return loggedIn && featureOn;
}, },
hasCodequalityChanges() {
return this.codequalityDiff.length > 0;
},
}, },
watch: { watch: {
'file.id': { 'file.id': {
...@@ -294,6 +302,7 @@ export default { ...@@ -294,6 +302,7 @@ export default {
:add-merge-request-buttons="true" :add-merge-request-buttons="true"
:view-diffs-file-by-file="viewDiffsFileByFile" :view-diffs-file-by-file="viewDiffsFileByFile"
:show-local-file-reviews="showLocalFileReviews" :show-local-file-reviews="showLocalFileReviews"
:has-codequality-changes="hasCodequalityChanges"
class="js-file-title file-title gl-border-1 gl-border-solid gl-border-gray-100" class="js-file-title file-title gl-border-1 gl-border-solid gl-border-gray-100"
:class="hasBodyClasses.header" :class="hasBodyClasses.header"
@toggleFile="handleToggle" @toggleFile="handleToggle"
......
...@@ -41,6 +41,7 @@ export default { ...@@ -41,6 +41,7 @@ export default {
GlDropdownDivider, GlDropdownDivider,
GlFormCheckbox, GlFormCheckbox,
GlLoadingIcon, GlLoadingIcon,
CodeQualityBadge: () => import('ee_component/diffs/components/code_quality_badge.vue'),
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
...@@ -95,6 +96,11 @@ export default { ...@@ -95,6 +96,11 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
hasCodequalityChanges: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
...@@ -327,6 +333,8 @@ export default { ...@@ -327,6 +333,8 @@ export default {
data-track-property="diff_copy_file" data-track-property="diff_copy_file"
/> />
<code-quality-badge v-if="hasCodequalityChanges" class="gl-mr-2" />
<small v-if="isModeChanged" ref="fileMode" class="mr-1"> <small v-if="isModeChanged" ref="fileMode" class="mr-1">
{{ diffFile.a_mode }}{{ diffFile.b_mode }} {{ diffFile.a_mode }}{{ diffFile.b_mode }}
</small> </small>
......
...@@ -73,6 +73,7 @@ export default function initDiffsApp(store) { ...@@ -73,6 +73,7 @@ export default function initDiffsApp(store) {
endpointMetadata: dataset.endpointMetadata || '', endpointMetadata: dataset.endpointMetadata || '',
endpointBatch: dataset.endpointBatch || '', endpointBatch: dataset.endpointBatch || '',
endpointCoverage: dataset.endpointCoverage || '', endpointCoverage: dataset.endpointCoverage || '',
endpointCodequality: dataset.endpointCodequality || '',
projectPath: dataset.projectPath, projectPath: dataset.projectPath,
helpPagePath: dataset.helpPagePath, helpPagePath: dataset.helpPagePath,
currentUser: JSON.parse(dataset.currentUserData) || {}, currentUser: JSON.parse(dataset.currentUserData) || {},
...@@ -114,6 +115,7 @@ export default function initDiffsApp(store) { ...@@ -114,6 +115,7 @@ export default function initDiffsApp(store) {
endpointMetadata: this.endpointMetadata, endpointMetadata: this.endpointMetadata,
endpointBatch: this.endpointBatch, endpointBatch: this.endpointBatch,
endpointCoverage: this.endpointCoverage, endpointCoverage: this.endpointCoverage,
endpointCodequality: this.endpointCodequality,
currentUser: this.currentUser, currentUser: this.currentUser,
projectPath: this.projectPath, projectPath: this.projectPath,
helpPagePath: this.helpPagePath, helpPagePath: this.helpPagePath,
......
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Visibility from 'visibilityjs';
import Vue from 'vue'; import Vue from 'vue';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import { diffViewerModes } from '~/ide/constants'; import { diffViewerModes } from '~/ide/constants';
...@@ -52,12 +53,15 @@ import { ...@@ -52,12 +53,15 @@ import {
prepareLineForRenamedFile, prepareLineForRenamedFile,
} from './utils'; } from './utils';
let eTagPoll;
export const setBaseConfig = ({ commit }, options) => { export const setBaseConfig = ({ commit }, options) => {
const { const {
endpoint, endpoint,
endpointMetadata, endpointMetadata,
endpointBatch, endpointBatch,
endpointCoverage, endpointCoverage,
endpointCodequality,
projectPath, projectPath,
dismissEndpoint, dismissEndpoint,
showSuggestPopover, showSuggestPopover,
...@@ -70,6 +74,7 @@ export const setBaseConfig = ({ commit }, options) => { ...@@ -70,6 +74,7 @@ export const setBaseConfig = ({ commit }, options) => {
endpointMetadata, endpointMetadata,
endpointBatch, endpointBatch,
endpointCoverage, endpointCoverage,
endpointCodequality,
projectPath, projectPath,
dismissEndpoint, dismissEndpoint,
showSuggestPopover, showSuggestPopover,
...@@ -231,6 +236,48 @@ export const fetchCoverageFiles = ({ commit, state }) => { ...@@ -231,6 +236,48 @@ export const fetchCoverageFiles = ({ commit, state }) => {
coveragePoll.makeRequest(); coveragePoll.makeRequest();
}; };
export const clearEtagPoll = () => {
eTagPoll = null;
};
export const stopCodequalityPolling = () => {
if (eTagPoll) eTagPoll.stop();
};
export const restartCodequalityPolling = () => {
if (eTagPoll) eTagPoll.restart();
};
export const fetchCodequality = ({ commit, state, dispatch }) => {
eTagPoll = new Poll({
resource: {
getCodequalityDiffReports: (endpoint) => axios.get(endpoint),
},
data: state.endpointCodequality,
method: 'getCodequalityDiffReports',
successCallback: ({ status, data }) => {
if (status === httpStatusCodes.OK) {
commit(types.SET_CODEQUALITY_DATA, data);
eTagPoll.stop();
}
},
errorCallback: () => createFlash(__('Something went wrong on our end. Please try again!')),
});
if (!Visibility.hidden()) {
eTagPoll.makeRequest();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
dispatch('restartCodequalityPolling');
} else {
dispatch('stopCodequalityPolling');
}
});
};
export const setHighlightedRow = ({ commit }, lineCode) => { 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);
......
...@@ -135,6 +135,16 @@ export const fileLineCoverage = (state) => (file, line) => { ...@@ -135,6 +135,16 @@ export const fileLineCoverage = (state) => (file, line) => {
return {}; return {};
}; };
/**
* Returns the codequality diff data for a given file
* @param {string} filePath
* @returns {Array}
*/
export const fileCodequalityDiff = (state) => (filePath) => {
if (!state.codequalityDiff.files || !state.codequalityDiff.files[filePath]) return [];
return state.codequalityDiff.files[filePath];
};
/** /**
* Returns index of a currently selected diff in diffFiles * Returns index of a currently selected diff in diffFiles
* @returns {number} * @returns {number}
......
...@@ -28,6 +28,7 @@ export default () => ({ ...@@ -28,6 +28,7 @@ export default () => ({
startVersion: null, // Null unless a target diff is selected for comparison that is not the "base" diff startVersion: null, // Null unless a target diff is selected for comparison that is not the "base" diff
diffFiles: [], diffFiles: [],
coverageFiles: {}, coverageFiles: {},
codequalityDiff: {},
mergeRequestDiffs: [], mergeRequestDiffs: [],
mergeRequestDiff: null, mergeRequestDiff: null,
diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType, diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType,
......
...@@ -11,6 +11,7 @@ export const SET_MR_FILE_REVIEWS = 'SET_MR_FILE_REVIEWS'; ...@@ -11,6 +11,7 @@ export const SET_MR_FILE_REVIEWS = 'SET_MR_FILE_REVIEWS';
export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE'; export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE';
export const SET_COVERAGE_DATA = 'SET_COVERAGE_DATA'; export const SET_COVERAGE_DATA = 'SET_COVERAGE_DATA';
export const SET_CODEQUALITY_DATA = 'SET_CODEQUALITY_DATA';
export const SET_MERGE_REQUEST_DIFFS = 'SET_MERGE_REQUEST_DIFFS'; export const SET_MERGE_REQUEST_DIFFS = 'SET_MERGE_REQUEST_DIFFS';
export const TOGGLE_LINE_HAS_FORM = 'TOGGLE_LINE_HAS_FORM'; export const TOGGLE_LINE_HAS_FORM = 'TOGGLE_LINE_HAS_FORM';
export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES'; export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES';
......
...@@ -33,6 +33,7 @@ export default { ...@@ -33,6 +33,7 @@ export default {
endpointMetadata, endpointMetadata,
endpointBatch, endpointBatch,
endpointCoverage, endpointCoverage,
endpointCodequality,
projectPath, projectPath,
dismissEndpoint, dismissEndpoint,
showSuggestPopover, showSuggestPopover,
...@@ -45,6 +46,7 @@ export default { ...@@ -45,6 +46,7 @@ export default {
endpointMetadata, endpointMetadata,
endpointBatch, endpointBatch,
endpointCoverage, endpointCoverage,
endpointCodequality,
projectPath, projectPath,
dismissEndpoint, dismissEndpoint,
showSuggestPopover, showSuggestPopover,
...@@ -87,6 +89,10 @@ export default { ...@@ -87,6 +89,10 @@ export default {
Object.assign(state, { coverageFiles }); Object.assign(state, { coverageFiles });
}, },
[types.SET_CODEQUALITY_DATA](state, codequalityDiffData) {
Object.assign(state, { codequalityDiff: codequalityDiffData });
},
[types.RENDER_FILE](state, file) { [types.RENDER_FILE](state, file) {
renderFile(file); renderFile(file);
}, },
......
...@@ -185,6 +185,27 @@ module MergeRequestsHelper ...@@ -185,6 +185,27 @@ module MergeRequestsHelper
end end
end end
def diffs_tab_pane_data(project, merge_request, params)
{
"is-locked": merge_request.discussion_locked?,
endpoint: diffs_project_merge_request_path(project, merge_request, 'json', params),
endpoint_metadata: @endpoint_metadata_url,
endpoint_batch: diffs_batch_project_json_merge_request_path(project, merge_request, 'json', params),
endpoint_coverage: @coverage_path,
help_page_path: help_page_path('user/discussions/index.md', anchor: 'suggest-changes'),
current_user_data: @current_user_data,
update_current_user_path: @update_current_user_path,
project_path: project_path(merge_request.project),
changes_empty_state_illustration: image_path('illustrations/merge_request_changes_empty.svg'),
is_fluid_layout: fluid_layout.to_s,
dismiss_endpoint: user_callouts_path,
show_suggest_popover: show_suggest_popover?.to_s,
show_whitespace_default: @show_whitespace_default.to_s,
file_by_file_default: @file_by_file_default.to_s,
default_suggestion_commit_message: default_suggestion_commit_message
}
end
private private
def review_requested_merge_requests_count def review_requested_merge_requests_count
......
...@@ -81,22 +81,7 @@ ...@@ -81,22 +81,7 @@
- params = request.query_parameters - params = request.query_parameters
- if Feature.enabled?(:default_merge_ref_for_diffs, @project, default_enabled: :yaml) - if Feature.enabled?(:default_merge_ref_for_diffs, @project, default_enabled: :yaml)
- params = params.merge(diff_head: true) - params = params.merge(diff_head: true)
= render "projects/merge_requests/tabs/pane", name: "diffs", id: "js-diffs-app", class: "diffs", data: { "is-locked": @merge_request.discussion_locked?, = render "projects/merge_requests/tabs/pane", name: "diffs", id: "js-diffs-app", class: "diffs", data: diffs_tab_pane_data(@project, @merge_request, params)
endpoint: diffs_project_merge_request_path(@project, @merge_request, 'json', params),
endpoint_metadata: @endpoint_metadata_url,
endpoint_batch: diffs_batch_project_json_merge_request_path(@project, @merge_request, 'json', params),
endpoint_coverage: @coverage_path,
help_page_path: suggest_changes_help_path,
current_user_data: @current_user_data,
update_current_user_path: @update_current_user_path,
project_path: project_path(@merge_request.project),
changes_empty_state_illustration: image_path('illustrations/merge_request_changes_empty.svg'),
is_fluid_layout: fluid_layout.to_s,
dismiss_endpoint: user_callouts_path,
show_suggest_popover: show_suggest_popover?.to_s,
show_whitespace_default: @show_whitespace_default.to_s,
file_by_file_default: @file_by_file_default.to_s,
default_suggestion_commit_message: default_suggestion_commit_message }
.mr-loading-status .mr-loading-status
.loading.hide .loading.hide
......
<script>
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: {
GlBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
},
i18n: {
badgeTitle: __('Code Quality'),
badgeTooltip: __(
'The merge request has been updated, and the number of code quality violations in this file has changed.',
),
},
};
</script>
<template>
<gl-badge
v-gl-tooltip
:title="$options.i18n.badgeTooltip"
icon="information"
class="gl-display-inline-block"
>
{{ $options.i18n.badgeTitle }}
</gl-badge>
</template>
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
module EE module EE
module MergeRequestsHelper module MergeRequestsHelper
extend ::Gitlab::Utils::Override
def render_items_list(items, separator = "and") def render_items_list(items, separator = "and")
items_cnt = items.size items_cnt = items.size
...@@ -15,5 +17,12 @@ module EE ...@@ -15,5 +17,12 @@ module EE
"#{items.join(", ")} #{separator} #{last_item}" "#{items.join(", ")} #{separator} #{last_item}"
end end
end end
override :diffs_tab_pane_data
def diffs_tab_pane_data(project, merge_request, params)
super.merge(
endpoint_codequality: (codequality_mr_diff_reports_project_merge_request_path(@project, @merge_request, 'json') if project.licensed_feature_available?(:inline_codequality) && @merge_request.has_codequality_mr_diff_report?)
)
end
end end
end end
...@@ -157,6 +157,7 @@ class License < ApplicationRecord ...@@ -157,6 +157,7 @@ class License < ApplicationRecord
group_ci_cd_analytics group_ci_cd_analytics
group_level_compliance_dashboard group_level_compliance_dashboard
incident_management incident_management
inline_codequality
insights insights
issuable_health_status issuable_health_status
jira_vulnerabilities_integration jira_vulnerabilities_integration
......
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import CodeQualityBadge from 'ee/diffs/components/code_quality_badge.vue';
import diffFileMockDataReadable from 'jest/diffs/mock_data/diff_file';
import DiffFileComponent from '~/diffs/components/diff_file.vue';
import createDiffsStore from '~/diffs/store/modules';
const getReadableFile = () => JSON.parse(JSON.stringify(diffFileMockDataReadable));
function createComponent({ first = false, last = false, options = {}, props = {} }) {
const file = getReadableFile();
const localVue = createLocalVue();
localVue.use(Vuex);
const store = new Vuex.Store({
modules: {
diffs: createDiffsStore(),
},
});
store.state.diffs.diffFiles = [file];
const wrapper = shallowMount(DiffFileComponent, {
store,
localVue,
propsData: {
file,
canCurrentUserFork: false,
viewDiffsFileByFile: false,
isFirstFile: first,
isLastFile: last,
...props,
},
...options,
});
return {
localVue,
wrapper,
store,
};
}
describe('EE DiffFile', () => {
let wrapper;
afterEach(() => {
wrapper.destroy();
});
describe('code quality badge', () => {
it('is shown when there is diff data for the file', () => {
({ wrapper } = createComponent({
props: {
codequalityDiff: [
{ line: 1, description: 'Unexpected alert.', severity: 'minor' },
{
line: 3,
description: 'Arrow function has too many statements (52). Maximum allowed is 30.',
severity: 'minor',
},
],
},
}));
expect(wrapper.find(CodeQualityBadge)).toExist();
});
it('is not shown when there is no diff data for the file', () => {
({ wrapper } = createComponent({}));
expect(wrapper.find(CodeQualityBadge)).toExist();
});
});
});
...@@ -30516,6 +30516,9 @@ msgstr "" ...@@ -30516,6 +30516,9 @@ msgstr ""
msgid "The merge request can now be merged." msgid "The merge request can now be merged."
msgstr "" msgstr ""
msgid "The merge request has been updated, and the number of code quality violations in this file has changed."
msgstr ""
msgid "The metric must be one of %{metrics}." msgid "The metric must be one of %{metrics}."
msgstr "" msgstr ""
......
...@@ -56,6 +56,7 @@ describe('diffs/components/app', () => { ...@@ -56,6 +56,7 @@ describe('diffs/components/app', () => {
endpointMetadata: `${TEST_HOST}/diff/endpointMetadata`, endpointMetadata: `${TEST_HOST}/diff/endpointMetadata`,
endpointBatch: `${TEST_HOST}/diff/endpointBatch`, endpointBatch: `${TEST_HOST}/diff/endpointBatch`,
endpointCoverage: `${TEST_HOST}/diff/endpointCoverage`, endpointCoverage: `${TEST_HOST}/diff/endpointCoverage`,
endpointCodequality: `${TEST_HOST}/diff/endpointCodequality`,
projectPath: 'namespace/project', projectPath: 'namespace/project',
currentUser: {}, currentUser: {},
changesEmptyStateIllustration: '', changesEmptyStateIllustration: '',
...@@ -141,6 +142,24 @@ describe('diffs/components/app', () => { ...@@ -141,6 +142,24 @@ describe('diffs/components/app', () => {
}); });
}); });
describe('codequality diff', () => {
it('fetches code quality data when endpoint is provided', () => {
createComponent();
jest.spyOn(wrapper.vm, 'fetchCodequality');
wrapper.vm.fetchData(false);
expect(wrapper.vm.fetchCodequality).toHaveBeenCalled();
});
it('does not fetch code quality data when endpoint is blank', async () => {
createComponent({ endpointCodequality: '' });
jest.spyOn(wrapper.vm, 'fetchCodequality');
wrapper.vm.fetchData(false);
expect(wrapper.vm.fetchCodequality).not.toHaveBeenCalled();
});
});
it.each` it.each`
props | state | expected props | state | expected
${{ isFluidLayout: true }} | ${{ isParallelView: false }} | ${false} ${{ isFluidLayout: true }} | ${{ isParallelView: false }} | ${false}
......
...@@ -17,6 +17,9 @@ import { ...@@ -17,6 +17,9 @@ import {
fetchDiffFilesBatch, fetchDiffFilesBatch,
fetchDiffFilesMeta, fetchDiffFilesMeta,
fetchCoverageFiles, fetchCoverageFiles,
clearEtagPoll,
stopCodequalityPolling,
fetchCodequality,
assignDiscussionsToDiff, assignDiscussionsToDiff,
removeDiscussionsFromDiff, removeDiscussionsFromDiff,
startRenderDiffsQueue, startRenderDiffsQueue,
...@@ -98,6 +101,7 @@ describe('DiffsStoreActions', () => { ...@@ -98,6 +101,7 @@ describe('DiffsStoreActions', () => {
const endpointMetadata = '/diffs/set/endpoint/metadata'; const endpointMetadata = '/diffs/set/endpoint/metadata';
const endpointBatch = '/diffs/set/endpoint/batch'; const endpointBatch = '/diffs/set/endpoint/batch';
const endpointCoverage = '/diffs/set/coverage_reports'; const endpointCoverage = '/diffs/set/coverage_reports';
const endpointCodequality = '/diffs/set/codequality_diff';
const projectPath = '/root/project'; const projectPath = '/root/project';
const dismissEndpoint = '/-/user_callouts'; const dismissEndpoint = '/-/user_callouts';
const showSuggestPopover = false; const showSuggestPopover = false;
...@@ -109,6 +113,7 @@ describe('DiffsStoreActions', () => { ...@@ -109,6 +113,7 @@ describe('DiffsStoreActions', () => {
endpointBatch, endpointBatch,
endpointMetadata, endpointMetadata,
endpointCoverage, endpointCoverage,
endpointCodequality,
projectPath, projectPath,
dismissEndpoint, dismissEndpoint,
showSuggestPopover, showSuggestPopover,
...@@ -118,6 +123,7 @@ describe('DiffsStoreActions', () => { ...@@ -118,6 +123,7 @@ describe('DiffsStoreActions', () => {
endpointBatch: '', endpointBatch: '',
endpointMetadata: '', endpointMetadata: '',
endpointCoverage: '', endpointCoverage: '',
endpointCodequality: '',
projectPath: '', projectPath: '',
dismissEndpoint: '', dismissEndpoint: '',
showSuggestPopover: true, showSuggestPopover: true,
...@@ -130,6 +136,7 @@ describe('DiffsStoreActions', () => { ...@@ -130,6 +136,7 @@ describe('DiffsStoreActions', () => {
endpointMetadata, endpointMetadata,
endpointBatch, endpointBatch,
endpointCoverage, endpointCoverage,
endpointCodequality,
projectPath, projectPath,
dismissEndpoint, dismissEndpoint,
showSuggestPopover, showSuggestPopover,
...@@ -297,6 +304,47 @@ describe('DiffsStoreActions', () => { ...@@ -297,6 +304,47 @@ describe('DiffsStoreActions', () => {
}); });
}); });
describe('fetchCodequality', () => {
let mock;
const endpointCodequality = '/fetch';
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
stopCodequalityPolling();
clearEtagPoll();
});
it('should commit SET_CODEQUALITY_DATA with received response', (done) => {
const data = {
files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] },
};
mock.onGet(endpointCodequality).reply(200, { data });
testAction(
fetchCodequality,
{},
{ endpointCodequality },
[{ type: types.SET_CODEQUALITY_DATA, payload: { data } }],
[],
done,
);
});
it('should show flash on API error', (done) => {
mock.onGet(endpointCodequality).reply(400);
testAction(fetchCodequality, {}, { endpointCodequality }, [], [], () => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(expect.stringMatching('Something went wrong'));
done();
});
});
});
describe('setHighlightedRow', () => { describe('setHighlightedRow', () => {
it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => { it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => {
testAction(setHighlightedRow, 'ABC_123', {}, [ testAction(setHighlightedRow, 'ABC_123', {}, [
......
...@@ -376,6 +376,26 @@ describe('Diffs Module Getters', () => { ...@@ -376,6 +376,26 @@ describe('Diffs Module Getters', () => {
}); });
}); });
describe('fileCodequalityDiff', () => {
beforeEach(() => {
Object.assign(localState.codequalityDiff, {
files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] },
});
});
it('returns empty array when no codequality data is available', () => {
Object.assign(localState.codequalityDiff, {});
expect(getters.fileCodequalityDiff(localState)('test.js')).toEqual([]);
});
it('returns array when codequality data is available for given file', () => {
expect(getters.fileCodequalityDiff(localState)('app.js')).toEqual([
{ line: 1, description: 'Unexpected alert.', severity: 'minor' },
]);
});
});
describe('suggestionCommitMessage', () => { describe('suggestionCommitMessage', () => {
let rootState; let rootState;
......
...@@ -113,6 +113,19 @@ describe('DiffsStoreMutations', () => { ...@@ -113,6 +113,19 @@ describe('DiffsStoreMutations', () => {
}); });
}); });
describe('SET_CODEQUALITY_DATA', () => {
it('should set codequality data', () => {
const state = { codequalityDiff: {} };
const codequality = {
files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] },
};
mutations[types.SET_CODEQUALITY_DATA](state, codequality);
expect(state.codequalityDiff).toEqual(codequality);
});
});
describe('SET_DIFF_VIEW_TYPE', () => { describe('SET_DIFF_VIEW_TYPE', () => {
it('should set diff view type properly', () => { it('should set diff view type properly', () => {
const state = {}; const state = {};
......
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