Commit af27c54b authored by Kyle Mann's avatar Kyle Mann Committed by Mark Florian

Migrate vulnerability modal to GlModal

- Migrated vulnerability modal to use GlModal
- Refactored Vuex actions to let the modal be opened from a Vue
  component rather than the actions themselves
Co-authored-by: default avatarPaul Gascou-Vaillancourt <paul.gascvail@gmail.com>
Co-authored-by: default avatarMark Florian <mflorian@gitlab.com>
parent 3ae06d3d
<script> <script>
import { VULNERABILITY_MODAL_ID } from 'ee/vue_shared/security_reports/components/constants';
import { GlTooltipDirective, GlResizeObserverDirective } from '@gitlab/ui'; import { GlTooltipDirective, GlResizeObserverDirective } from '@gitlab/ui';
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
...@@ -25,10 +26,11 @@ export default { ...@@ -25,10 +26,11 @@ export default {
this.updateTooltipTitle(); this.updateTooltipTitle();
}, },
methods: { methods: {
...mapActions(['openModal']), ...mapActions(['setModalData']),
handleIssueClick() { handleIssueClick() {
const { issue, status, openModal } = this; const { issue, status, setModalData } = this;
openModal({ issue, status }); setModalData({ issue, status });
this.$root.$emit('bv::show::modal', VULNERABILITY_MODAL_ID);
}, },
updateTooltipTitle() { updateTooltipTitle() {
// Only show the tooltip if the text is truncated with an ellipsis. // Only show the tooltip if the text is truncated with an ellipsis.
......
...@@ -45,7 +45,6 @@ export default { ...@@ -45,7 +45,6 @@ export default {
...mapActions('vulnerabilities', [ ...mapActions('vulnerabilities', [
'deselectAllVulnerabilities', 'deselectAllVulnerabilities',
'fetchVulnerabilities', 'fetchVulnerabilities',
'openModal',
'selectAllVulnerabilities', 'selectAllVulnerabilities',
]), ]),
fetchPage(page) { fetchPage(page) {
...@@ -107,7 +106,6 @@ export default { ...@@ -107,7 +106,6 @@ export default {
v-for="vulnerability in vulnerabilities" v-for="vulnerability in vulnerabilities"
:key="vulnerability.id" :key="vulnerability.id"
:vulnerability="vulnerability" :vulnerability="vulnerability"
@openModal="openModal({ vulnerability })"
/> />
<slot v-if="showEmptyState" name="empty-state"> <slot v-if="showEmptyState" name="empty-state">
......
...@@ -10,6 +10,7 @@ import { ...@@ -10,6 +10,7 @@ import {
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue'; import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import convertReportType from 'ee/vue_shared/security_reports/store/utils/convert_report_type'; import convertReportType from 'ee/vue_shared/security_reports/store/utils/convert_report_type';
import getPrimaryIdentifier from 'ee/vue_shared/security_reports/store/utils/get_primary_identifier'; import getPrimaryIdentifier from 'ee/vue_shared/security_reports/store/utils/get_primary_identifier';
import { VULNERABILITY_MODAL_ID } from 'ee/vue_shared/security_reports/components/constants';
import VulnerabilityActionButtons from './vulnerability_action_buttons.vue'; import VulnerabilityActionButtons from './vulnerability_action_buttons.vue';
import VulnerabilityIssueLink from './vulnerability_issue_link.vue'; import VulnerabilityIssueLink from './vulnerability_issue_link.vue';
import { DASHBOARD_TYPES } from '../store/constants'; import { DASHBOARD_TYPES } from '../store/constants';
...@@ -88,13 +89,21 @@ export default { ...@@ -88,13 +89,21 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions('vulnerabilities', ['openModal', 'selectVulnerability', 'deselectVulnerability']), ...mapActions('vulnerabilities', [
'setModalData',
'selectVulnerability',
'deselectVulnerability',
]),
toggleVulnerability() { toggleVulnerability() {
if (this.isSelected) { if (this.isSelected) {
return this.deselectVulnerability(this.vulnerability); return this.deselectVulnerability(this.vulnerability);
} }
return this.selectVulnerability(this.vulnerability); return this.selectVulnerability(this.vulnerability);
}, },
openModal(payload) {
this.setModalData(payload);
this.$root.$emit('bv::show::modal', VULNERABILITY_MODAL_ID);
},
}, },
}; };
</script> </script>
......
<script> <script>
import { mapActions, mapState, mapGetters } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import IssueModal from 'ee/vue_shared/security_reports/components/modal.vue'; import IssueModal from 'ee/vue_shared/security_reports/components/modal.vue';
import { vulnerabilityModalMixin } from 'ee/vue_shared/security_reports/mixins/vulnerability_modal_mixin';
import Filters from './filters.vue'; import Filters from './filters.vue';
import SecurityDashboardLayout from './security_dashboard_layout.vue'; import SecurityDashboardLayout from './security_dashboard_layout.vue';
import SecurityDashboardTable from './security_dashboard_table.vue'; import SecurityDashboardTable from './security_dashboard_table.vue';
...@@ -16,6 +17,7 @@ export default { ...@@ -16,6 +17,7 @@ export default {
FuzzingArtifactsDownload, FuzzingArtifactsDownload,
LoadingError, LoadingError,
}, },
mixins: [vulnerabilityModalMixin('vulnerabilities')],
props: { props: {
vulnerabilitiesEndpoint: { vulnerabilitiesEndpoint: {
type: String, type: String,
...@@ -69,19 +71,15 @@ export default { ...@@ -69,19 +71,15 @@ export default {
}, },
methods: { methods: {
...mapActions('vulnerabilities', [ ...mapActions('vulnerabilities', [
'addDismissalComment',
'deleteDismissalComment',
'closeDismissalCommentBox', 'closeDismissalCommentBox',
'createIssue', 'createIssue',
'createMergeRequest', 'createMergeRequest',
'dismissVulnerability',
'fetchVulnerabilities', 'fetchVulnerabilities',
'openDismissalCommentBox', 'openDismissalCommentBox',
'setPipelineId', 'setPipelineId',
'setVulnerabilitiesEndpoint', 'setVulnerabilitiesEndpoint',
'showDismissalDeleteButtons', 'showDismissalDeleteButtons',
'hideDismissalDeleteButtons', 'hideDismissalDeleteButtons',
'undoDismiss',
'downloadPatch', 'downloadPatch',
]), ]),
...mapActions('pipelineJobs', ['fetchPipelineJobs']), ...mapActions('pipelineJobs', ['fetchPipelineJobs']),
...@@ -126,17 +124,17 @@ export default { ...@@ -126,17 +124,17 @@ export default {
:is-creating-issue="isCreatingIssue" :is-creating-issue="isCreatingIssue"
:is-dismissing-vulnerability="isDismissingVulnerability" :is-dismissing-vulnerability="isDismissingVulnerability"
:is-creating-merge-request="isCreatingMergeRequest" :is-creating-merge-request="isCreatingMergeRequest"
@addDismissalComment="addDismissalComment({ vulnerability, comment: $event })" @addDismissalComment="handleAddDismissalComment({ vulnerability, comment: $event })"
@editVulnerabilityDismissalComment="openDismissalCommentBox" @editVulnerabilityDismissalComment="openDismissalCommentBox"
@showDismissalDeleteButtons="showDismissalDeleteButtons" @showDismissalDeleteButtons="showDismissalDeleteButtons"
@hideDismissalDeleteButtons="hideDismissalDeleteButtons" @hideDismissalDeleteButtons="hideDismissalDeleteButtons"
@deleteDismissalComment="deleteDismissalComment({ vulnerability })" @deleteDismissalComment="handleDeleteDismissalComment({ vulnerability })"
@closeDismissalCommentBox="closeDismissalCommentBox" @closeDismissalCommentBox="closeDismissalCommentBox"
@createMergeRequest="createMergeRequest({ vulnerability })" @createMergeRequest="createMergeRequest({ vulnerability })"
@createNewIssue="createIssue({ vulnerability })" @createNewIssue="createIssue({ vulnerability })"
@dismissVulnerability="dismissVulnerability({ vulnerability, comment: $event })" @dismissVulnerability="handleDismissVulnerability({ vulnerability, comment: $event })"
@openDismissalCommentBox="openDismissalCommentBox" @openDismissalCommentBox="openDismissalCommentBox"
@revertDismissVulnerability="undoDismiss({ vulnerability })" @revertDismissVulnerability="handleRevertDismissVulnerability({ vulnerability })"
@downloadPatch="downloadPatch({ vulnerability })" @downloadPatch="downloadPatch({ vulnerability })"
/> />
</template> </template>
......
<script> <script>
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { GlTooltipDirective, GlButton } from '@gitlab/ui'; import { GlTooltipDirective, GlButton } from '@gitlab/ui';
import { VULNERABILITY_MODAL_ID } from 'ee/vue_shared/security_reports/components/constants';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
export default { export default {
...@@ -37,10 +38,10 @@ export default { ...@@ -37,10 +38,10 @@ export default {
}, },
methods: { methods: {
...mapActions('vulnerabilities', [ ...mapActions('vulnerabilities', [
'openModal', 'setModalData',
'createIssue', 'createIssue',
'dismissVulnerability', 'dismissVulnerability',
'undoDismiss', 'revertDismissVulnerability',
]), ]),
handleCreateIssue() { handleCreateIssue() {
const { vulnerability } = this; const { vulnerability } = this;
...@@ -52,13 +53,17 @@ export default { ...@@ -52,13 +53,17 @@ export default {
}, },
handleUndoDismiss() { handleUndoDismiss() {
const { vulnerability } = this; const { vulnerability } = this;
this.undoDismiss({ vulnerability, flashError: true }); this.revertDismissVulnerability({ vulnerability, flashError: true });
},
openModal(payload) {
this.setModalData(payload);
this.$root.$emit('bv::show::modal', VULNERABILITY_MODAL_ID);
}, },
}, },
i18n: { i18n: {
moreInfo: s__('SecurityReports|More info'), moreInfo: s__('SecurityReports|More info'),
createIssue: s__('SecurityReports|Create issue'), createIssue: s__('SecurityReports|Create issue'),
undoDismiss: s__('SecurityReports|Undo dismiss'), revertDismissVulnerability: s__('SecurityReports|Undo dismiss'),
dismissVulnerability: s__('SecurityReports|Dismiss vulnerability'), dismissVulnerability: s__('SecurityReports|Dismiss vulnerability'),
}, },
}; };
......
import $ from 'jquery';
import _ from 'lodash'; import _ from 'lodash';
import download from '~/lib/utils/downloader'; import download from '~/lib/utils/downloader';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
...@@ -22,8 +21,6 @@ import * as types from './mutation_types'; ...@@ -22,8 +21,6 @@ import * as types from './mutation_types';
* https://gitlab.com/gitlab-org/gitlab/issues/8519 * https://gitlab.com/gitlab-org/gitlab/issues/8519
*/ */
const hideModal = () => $('#modal-mrwidget-security-issue').modal('hide');
export const setPipelineId = ({ commit }, id) => commit(types.SET_PIPELINE_ID, id); export const setPipelineId = ({ commit }, id) => commit(types.SET_PIPELINE_ID, id);
export const setSourceBranch = ({ commit }, ref) => commit(types.SET_SOURCE_BRANCH, ref); export const setSourceBranch = ({ commit }, ref) => commit(types.SET_SOURCE_BRANCH, ref);
...@@ -77,9 +74,7 @@ export const receiveVulnerabilitiesError = ({ commit }, errorCode) => { ...@@ -77,9 +74,7 @@ export const receiveVulnerabilitiesError = ({ commit }, errorCode) => {
commit(types.RECEIVE_VULNERABILITIES_ERROR, errorCode); commit(types.RECEIVE_VULNERABILITIES_ERROR, errorCode);
}; };
export const openModal = ({ commit }, payload = {}) => { export const setModalData = ({ commit }, payload = {}) => {
$('#modal-mrwidget-security-issue').modal('show');
commit(types.SET_MODAL_DATA, payload); commit(types.SET_MODAL_DATA, payload);
}; };
...@@ -224,7 +219,7 @@ export const dismissVulnerability = ( ...@@ -224,7 +219,7 @@ export const dismissVulnerability = (
text: s__('SecurityReports|Undo dismiss'), text: s__('SecurityReports|Undo dismiss'),
onClick: (e, toastObject) => { onClick: (e, toastObject) => {
if (vulnerability.dismissal_feedback) { if (vulnerability.dismissal_feedback) {
dispatch('undoDismiss', { vulnerability }) dispatch('revertDismissVulnerability', { vulnerability })
.then(() => dispatch('fetchVulnerabilities', { page })) .then(() => dispatch('fetchVulnerabilities', { page }))
.catch(() => {}); .catch(() => {});
toastObject.goAway(0); toastObject.goAway(0);
...@@ -234,7 +229,7 @@ export const dismissVulnerability = ( ...@@ -234,7 +229,7 @@ export const dismissVulnerability = (
} }
: {}; : {};
axios return axios
.post(vulnerability.create_vulnerability_feedback_dismissal_path, { .post(vulnerability.create_vulnerability_feedback_dismissal_path, {
vulnerability_feedback: { vulnerability_feedback: {
category: vulnerability.report_type, category: vulnerability.report_type,
...@@ -272,7 +267,6 @@ export const requestDismissVulnerability = ({ commit }) => { ...@@ -272,7 +267,6 @@ export const requestDismissVulnerability = ({ commit }) => {
export const receiveDismissVulnerabilitySuccess = ({ commit }, payload) => { export const receiveDismissVulnerabilitySuccess = ({ commit }, payload) => {
commit(types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS, payload); commit(types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS, payload);
hideModal();
}; };
export const receiveDismissVulnerabilityError = ({ commit }, { flashError }) => { export const receiveDismissVulnerabilityError = ({ commit }, { flashError }) => {
...@@ -302,7 +296,7 @@ export const addDismissalComment = ({ dispatch }, { vulnerability, comment }) => ...@@ -302,7 +296,7 @@ export const addDismissalComment = ({ dispatch }, { vulnerability, comment }) =>
vulnerabilityName: vulnerability.name, vulnerabilityName: vulnerability.name,
}); });
axios return axios
.patch(url, { .patch(url, {
project_id: dismissal_feedback.project_id, project_id: dismissal_feedback.project_id,
id: dismissal_feedback.id, id: dismissal_feedback.id,
...@@ -327,7 +321,7 @@ export const deleteDismissalComment = ({ dispatch }, { vulnerability }) => { ...@@ -327,7 +321,7 @@ export const deleteDismissalComment = ({ dispatch }, { vulnerability }) => {
vulnerabilityName: vulnerability.name, vulnerabilityName: vulnerability.name,
}); });
axios return axios
.patch(url, { .patch(url, {
project_id: dismissal_feedback.project_id, project_id: dismissal_feedback.project_id,
comment: '', comment: '',
...@@ -349,7 +343,6 @@ export const requestAddDismissalComment = ({ commit }) => { ...@@ -349,7 +343,6 @@ export const requestAddDismissalComment = ({ commit }) => {
export const receiveAddDismissalCommentSuccess = ({ commit }, payload) => { export const receiveAddDismissalCommentSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS, payload); commit(types.RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS, payload);
hideModal();
}; };
export const receiveAddDismissalCommentError = ({ commit }) => { export const receiveAddDismissalCommentError = ({ commit }) => {
...@@ -362,7 +355,6 @@ export const requestDeleteDismissalComment = ({ commit }) => { ...@@ -362,7 +355,6 @@ export const requestDeleteDismissalComment = ({ commit }) => {
export const receiveDeleteDismissalCommentSuccess = ({ commit }, payload) => { export const receiveDeleteDismissalCommentSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload); commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload);
hideModal();
}; };
export const receiveDeleteDismissalCommentError = ({ commit }) => { export const receiveDeleteDismissalCommentError = ({ commit }) => {
...@@ -377,7 +369,7 @@ export const hideDismissalDeleteButtons = ({ commit }) => { ...@@ -377,7 +369,7 @@ export const hideDismissalDeleteButtons = ({ commit }) => {
commit(types.HIDE_DISMISSAL_DELETE_BUTTONS); commit(types.HIDE_DISMISSAL_DELETE_BUTTONS);
}; };
export const undoDismiss = ({ dispatch }, { vulnerability, flashError }) => { export const revertDismissVulnerability = ({ dispatch }, { vulnerability, flashError }) => {
const { destroy_vulnerability_feedback_dismissal_path } = vulnerability.dismissal_feedback; const { destroy_vulnerability_feedback_dismissal_path } = vulnerability.dismissal_feedback;
dispatch('requestUndoDismiss'); dispatch('requestUndoDismiss');
...@@ -398,7 +390,6 @@ export const requestUndoDismiss = ({ commit }) => { ...@@ -398,7 +390,6 @@ export const requestUndoDismiss = ({ commit }) => {
export const receiveUndoDismissSuccess = ({ commit }, payload) => { export const receiveUndoDismissSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_REVERT_DISMISSAL_SUCCESS, payload); commit(types.RECEIVE_REVERT_DISMISSAL_SUCCESS, payload);
hideModal();
}; };
export const receiveUndoDismissError = ({ commit }, { flashError }) => { export const receiveUndoDismissError = ({ commit }, { flashError }) => {
...@@ -423,7 +414,6 @@ export const downloadPatch = ({ state }) => { ...@@ -423,7 +414,6 @@ export const downloadPatch = ({ state }) => {
*/ */
const { vulnerability } = state.modal; const { vulnerability } = state.modal;
download({ fileData: vulnerability.remediations[0].diff, fileName: `remediation.patch` }); download({ fileData: vulnerability.remediations[0].diff, fileName: `remediation.patch` });
$('#modal-mrwidget-security-issue').modal('hide');
}; };
export const createMergeRequest = ({ state, dispatch }, { vulnerability, flashError }) => { export const createMergeRequest = ({ state, dispatch }, { vulnerability, flashError }) => {
......
...@@ -7,3 +7,5 @@ export const SEVERITY_TOOLTIP_TITLE_MAP = { ...@@ -7,3 +7,5 @@ export const SEVERITY_TOOLTIP_TITLE_MAP = {
`SecurityReports|The rating "unknown" indicates that the underlying scanner doesn’t contain or provide a severity rating.`, `SecurityReports|The rating "unknown" indicates that the underlying scanner doesn’t contain or provide a severity rating.`,
), ),
}; };
export const VULNERABILITY_MODAL_ID = 'modal-mrwidget-security-issue';
...@@ -7,17 +7,19 @@ import MergeRequestNote from 'ee/vue_shared/security_reports/components/merge_re ...@@ -7,17 +7,19 @@ import MergeRequestNote from 'ee/vue_shared/security_reports/components/merge_re
import ModalFooter from 'ee/vue_shared/security_reports/components/modal_footer.vue'; import ModalFooter from 'ee/vue_shared/security_reports/components/modal_footer.vue';
import SolutionCard from 'ee/vue_shared/security_reports/components/solution_card_vuex.vue'; import SolutionCard from 'ee/vue_shared/security_reports/components/solution_card_vuex.vue';
import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.vue'; import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.vue';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue'; import { GlModal } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { VULNERABILITY_MODAL_ID } from './constants';
export default { export default {
VULNERABILITY_MODAL_ID,
components: { components: {
DismissalNote, DismissalNote,
DismissalCommentBoxToggle, DismissalCommentBoxToggle,
DismissalCommentModalFooter, DismissalCommentModalFooter,
IssueNote, IssueNote,
MergeRequestNote, MergeRequestNote,
Modal: DeprecatedModal2, GlModal,
ModalFooter, ModalFooter,
SolutionCard, SolutionCard,
VulnerabilityDetails, VulnerabilityDetails,
...@@ -183,15 +185,20 @@ export default { ...@@ -183,15 +185,20 @@ export default {
clearDismissalError() { clearDismissalError() {
this.dismissalCommentErrorMessage = ''; this.dismissalCommentErrorMessage = '';
}, },
close() {
this.$refs.modal.close();
},
}, },
}; };
</script> </script>
<template> <template>
<modal <gl-modal
id="modal-mrwidget-security-issue" ref="modal"
:header-title-text="modal.title" :modal-id="$options.VULNERABILITY_MODAL_ID"
:title="modal.title"
data-qa-selector="vulnerability_modal_content" data-qa-selector="vulnerability_modal_content"
class="modal-security-report-dast" class="modal-security-report-dast"
v-bind="$attrs"
> >
<slot> <slot>
<vulnerability-details :vulnerability="vulnerability" class="js-vulnerability-details" /> <vulnerability-details :vulnerability="vulnerability" class="js-vulnerability-details" />
...@@ -244,7 +251,7 @@ export default { ...@@ -244,7 +251,7 @@ export default {
<div v-if="modal.error" class="alert alert-danger">{{ modal.error }}</div> <div v-if="modal.error" class="alert alert-danger">{{ modal.error }}</div>
</slot> </slot>
<template #footer> <template #modal-footer>
<dismissal-comment-modal-footer <dismissal-comment-modal-footer
v-if="modal.isCommentingOnDismissal" v-if="modal.isCommentingOnDismissal"
:is-dismissed="vulnerability.isDismissed" :is-dismissed="vulnerability.isDismissed"
...@@ -274,7 +281,8 @@ export default { ...@@ -274,7 +281,8 @@ export default {
@openDismissalCommentBox="$emit('openDismissalCommentBox')" @openDismissalCommentBox="$emit('openDismissalCommentBox')"
@revertDismissVulnerability="$emit('revertDismissVulnerability')" @revertDismissVulnerability="$emit('revertDismissVulnerability')"
@downloadPatch="$emit('downloadPatch')" @downloadPatch="$emit('downloadPatch')"
@cancel="close"
/> />
</template> </template>
</modal> </gl-modal>
</template> </template>
...@@ -100,7 +100,7 @@ export default { ...@@ -100,7 +100,7 @@ export default {
<template> <template>
<div> <div>
<gl-button data-dismiss="modal" :disabled="disabled"> <gl-button :disabled="disabled" @click="$emit('cancel')">
{{ __('Cancel') }} {{ __('Cancel') }}
</gl-button> </gl-button>
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
* Scanning, Secret Scanning) body text * Scanning, Secret Scanning) body text
* [severity-badge] [name] in [link]:[line] * [severity-badge] [name] in [link]:[line]
*/ */
import ModalOpenName from 'ee/reports/components/modal_open_name.vue';
import ReportLink from '~/reports/components/report_link.vue'; import ReportLink from '~/reports/components/report_link.vue';
import ModalOpenName from '~/reports/components/modal_open_name.vue';
import SeverityBadge from './severity_badge.vue'; import SeverityBadge from './severity_badge.vue';
export default { export default {
......
...@@ -4,9 +4,10 @@ import { once } from 'lodash'; ...@@ -4,9 +4,10 @@ import { once } from 'lodash';
import { componentNames } from 'ee/reports/components/issue_body'; import { componentNames } from 'ee/reports/components/issue_body';
import { GlButton, GlSprintf, GlLink, GlModalDirective } from '@gitlab/ui'; import { GlButton, GlSprintf, GlLink, GlModalDirective } from '@gitlab/ui';
import FuzzingArtifactsDownload from 'ee/security_dashboard/components/fuzzing_artifacts_download.vue'; import FuzzingArtifactsDownload from 'ee/security_dashboard/components/fuzzing_artifacts_download.vue';
import ArtifactDownload from 'ee/vue_shared/security_reports/components/artifact_download.vue'; import ArtifactDownload from './components/artifact_download.vue';
import { LOADING } from '~/reports/constants'; import { LOADING } from '~/reports/constants';
import { securityReportTypeEnumToReportType } from './constants'; import { securityReportTypeEnumToReportType } from './constants';
import { vulnerabilityModalMixin } from './mixins/vulnerability_modal_mixin';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ReportSection from '~/reports/components/report_section.vue'; import ReportSection from '~/reports/components/report_section.vue';
import SummaryRow from '~/reports/components/summary_row.vue'; import SummaryRow from '~/reports/components/summary_row.vue';
...@@ -49,7 +50,7 @@ export default { ...@@ -49,7 +50,7 @@ export default {
directives: { directives: {
'gl-modal': GlModalDirective, 'gl-modal': GlModalDirective,
}, },
mixins: [securityReportsMixin, glFeatureFlagsMixin()], mixins: [securityReportsMixin, vulnerabilityModalMixin(), glFeatureFlagsMixin()],
apollo: { apollo: {
dastSummary: { dastSummary: {
query: securityReportSummaryQuery, query: securityReportSummaryQuery,
...@@ -411,15 +412,11 @@ export default { ...@@ -411,15 +412,11 @@ export default {
'setCreateVulnerabilityFeedbackMergeRequestPath', 'setCreateVulnerabilityFeedbackMergeRequestPath',
'setCreateVulnerabilityFeedbackDismissalPath', 'setCreateVulnerabilityFeedbackDismissalPath',
'setPipelineId', 'setPipelineId',
'dismissVulnerability',
'revertDismissVulnerability',
'createNewIssue', 'createNewIssue',
'createMergeRequest', 'createMergeRequest',
'openDismissalCommentBox', 'openDismissalCommentBox',
'closeDismissalCommentBox', 'closeDismissalCommentBox',
'downloadPatch', 'downloadPatch',
'addDismissalComment',
'deleteDismissalComment',
'showDismissalDeleteButtons', 'showDismissalDeleteButtons',
'hideDismissalDeleteButtons', 'hideDismissalDeleteButtons',
'fetchContainerScanningDiff', 'fetchContainerScanningDiff',
...@@ -700,13 +697,13 @@ export default { ...@@ -700,13 +697,13 @@ export default {
@closeDismissalCommentBox="closeDismissalCommentBox()" @closeDismissalCommentBox="closeDismissalCommentBox()"
@createMergeRequest="createMergeRequest" @createMergeRequest="createMergeRequest"
@createNewIssue="createNewIssue" @createNewIssue="createNewIssue"
@dismissVulnerability="dismissVulnerability" @dismissVulnerability="handleDismissVulnerability"
@openDismissalCommentBox="openDismissalCommentBox()" @openDismissalCommentBox="openDismissalCommentBox()"
@editVulnerabilityDismissalComment="openDismissalCommentBox()" @editVulnerabilityDismissalComment="openDismissalCommentBox()"
@revertDismissVulnerability="revertDismissVulnerability" @revertDismissVulnerability="handleRevertDismissVulnerability"
@downloadPatch="downloadPatch" @downloadPatch="downloadPatch"
@addDismissalComment="addDismissalComment({ comment: $event })" @addDismissalComment="handleAddDismissalComment({ comment: $event })"
@deleteDismissalComment="deleteDismissalComment" @deleteDismissalComment="handleDeleteDismissalComment"
@showDismissalDeleteButtons="showDismissalDeleteButtons" @showDismissalDeleteButtons="showDismissalDeleteButtons"
@hideDismissalDeleteButtons="hideDismissalDeleteButtons" @hideDismissalDeleteButtons="hideDismissalDeleteButtons"
/> />
......
import { mapActions } from 'vuex';
import { VULNERABILITY_MODAL_ID } from '../components/constants';
export const vulnerabilityModalMixin = (storeModule) => {
const actions = [
'dismissVulnerability',
'addDismissalComment',
'deleteDismissalComment',
'revertDismissVulnerability',
];
const mapActionsArgs = storeModule ? [storeModule, actions] : [actions];
return {
methods: {
...mapActions(...mapActionsArgs),
handleDismissVulnerability(payload) {
return this.dismissVulnerability(payload).then(this.hideModal);
},
handleAddDismissalComment(payload) {
return this.addDismissalComment(payload).then(this.hideModal);
},
handleDeleteDismissalComment(payload) {
return this.deleteDismissalComment(payload).then(this.hideModal);
},
handleRevertDismissVulnerability(payload) {
return this.revertDismissVulnerability(payload).then(this.hideModal);
},
hideModal() {
this.$root.$emit('bv::hide::modal', VULNERABILITY_MODAL_ID);
},
},
};
};
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import download from '~/lib/utils/downloader'; import download from '~/lib/utils/downloader';
import pollUntilComplete from '~/lib/utils/poll_until_complete'; import pollUntilComplete from '~/lib/utils/poll_until_complete';
...@@ -22,8 +21,6 @@ import * as types from './mutation_types'; ...@@ -22,8 +21,6 @@ import * as types from './mutation_types';
* https://gitlab.com/gitlab-org/gitlab/issues/8519 * https://gitlab.com/gitlab-org/gitlab/issues/8519
*/ */
const hideModal = () => $('#modal-mrwidget-security-issue').modal('hide');
export const setHeadBlobPath = ({ commit }, blobPath) => commit(types.SET_HEAD_BLOB_PATH, blobPath); export const setHeadBlobPath = ({ commit }, blobPath) => commit(types.SET_HEAD_BLOB_PATH, blobPath);
export const setBaseBlobPath = ({ commit }, blobPath) => commit(types.SET_BASE_BLOB_PATH, blobPath); export const setBaseBlobPath = ({ commit }, blobPath) => commit(types.SET_BASE_BLOB_PATH, blobPath);
...@@ -175,12 +172,6 @@ export const fetchCoverageFuzzingDiff = ({ state, dispatch }) => { ...@@ -175,12 +172,6 @@ export const fetchCoverageFuzzingDiff = ({ state, dispatch }) => {
export const updateCoverageFuzzingIssue = ({ commit }, issue) => export const updateCoverageFuzzingIssue = ({ commit }, issue) =>
commit(types.UPDATE_COVERAGE_FUZZING_ISSUE, issue); commit(types.UPDATE_COVERAGE_FUZZING_ISSUE, issue);
export const openModal = ({ dispatch }, payload) => {
dispatch('setModalData', payload);
$('#modal-mrwidget-security-issue').modal('show');
};
export const setModalData = ({ commit }, payload) => commit(types.SET_ISSUE_MODAL_DATA, payload); export const setModalData = ({ commit }, payload) => commit(types.SET_ISSUE_MODAL_DATA, payload);
export const requestDismissVulnerability = ({ commit }) => export const requestDismissVulnerability = ({ commit }) =>
commit(types.REQUEST_DISMISS_VULNERABILITY); commit(types.REQUEST_DISMISS_VULNERABILITY);
...@@ -196,7 +187,7 @@ export const dismissVulnerability = ({ state, dispatch }, comment) => { ...@@ -196,7 +187,7 @@ export const dismissVulnerability = ({ state, dispatch }, comment) => {
vulnerabilityName: state.modal.vulnerability.name, vulnerabilityName: state.modal.vulnerability.name,
}); });
axios return axios
.post(state.createVulnerabilityFeedbackDismissalPath, { .post(state.createVulnerabilityFeedbackDismissalPath, {
vulnerability_feedback: { vulnerability_feedback: {
category: state.modal.vulnerability.category, category: state.modal.vulnerability.category,
...@@ -217,7 +208,6 @@ export const dismissVulnerability = ({ state, dispatch }, comment) => { ...@@ -217,7 +208,6 @@ export const dismissVulnerability = ({ state, dispatch }, comment) => {
dispatch('closeDismissalCommentBox'); dispatch('closeDismissalCommentBox');
dispatch('receiveDismissVulnerability', updatedIssue); dispatch('receiveDismissVulnerability', updatedIssue);
hideModal();
toast(toastMsg); toast(toastMsg);
}) })
.catch(() => { .catch(() => {
...@@ -246,7 +236,7 @@ export const addDismissalComment = ({ state, dispatch }, { comment }) => { ...@@ -246,7 +236,7 @@ export const addDismissalComment = ({ state, dispatch }, { comment }) => {
vulnerabilityName: vulnerability.name, vulnerabilityName: vulnerability.name,
}); });
axios return axios
.patch(url, { .patch(url, {
project_id: dismissalFeedback.project_id, project_id: dismissalFeedback.project_id,
id: dismissalFeedback.id, id: dismissalFeedback.id,
...@@ -275,7 +265,7 @@ export const deleteDismissalComment = ({ state, dispatch }) => { ...@@ -275,7 +265,7 @@ export const deleteDismissalComment = ({ state, dispatch }) => {
vulnerabilityName: vulnerability.name, vulnerabilityName: vulnerability.name,
}); });
axios return axios
.patch(url, { .patch(url, {
project_id: dismissalFeedback.project_id, project_id: dismissalFeedback.project_id,
comment: '', comment: '',
...@@ -299,7 +289,6 @@ export const requestDeleteDismissalComment = ({ commit }) => { ...@@ -299,7 +289,6 @@ export const requestDeleteDismissalComment = ({ commit }) => {
export const receiveDeleteDismissalCommentSuccess = ({ commit }, payload) => { export const receiveDeleteDismissalCommentSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload); commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload);
hideModal();
}; };
export const receiveDeleteDismissalCommentError = ({ commit }, error) => { export const receiveDeleteDismissalCommentError = ({ commit }, error) => {
...@@ -312,7 +301,6 @@ export const requestAddDismissalComment = ({ commit }) => { ...@@ -312,7 +301,6 @@ export const requestAddDismissalComment = ({ commit }) => {
export const receiveAddDismissalCommentSuccess = ({ commit }, payload) => { export const receiveAddDismissalCommentSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS, payload); commit(types.RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS, payload);
hideModal();
}; };
export const receiveAddDismissalCommentError = ({ commit }, error) => { export const receiveAddDismissalCommentError = ({ commit }, error) => {
...@@ -322,7 +310,7 @@ export const receiveAddDismissalCommentError = ({ commit }, error) => { ...@@ -322,7 +310,7 @@ export const receiveAddDismissalCommentError = ({ commit }, error) => {
export const revertDismissVulnerability = ({ state, dispatch }) => { export const revertDismissVulnerability = ({ state, dispatch }) => {
dispatch('requestDismissVulnerability'); dispatch('requestDismissVulnerability');
axios return axios
.delete( .delete(
state.modal.vulnerability.dismissalFeedback.destroy_vulnerability_feedback_dismissal_path, state.modal.vulnerability.dismissalFeedback.destroy_vulnerability_feedback_dismissal_path,
) )
...@@ -335,8 +323,6 @@ export const revertDismissVulnerability = ({ state, dispatch }) => { ...@@ -335,8 +323,6 @@ export const revertDismissVulnerability = ({ state, dispatch }) => {
}; };
dispatch('receiveDismissVulnerability', updatedIssue); dispatch('receiveDismissVulnerability', updatedIssue);
hideModal();
}) })
.catch(() => .catch(() =>
dispatch( dispatch(
...@@ -426,7 +412,6 @@ export const downloadPatch = ({ state }) => { ...@@ -426,7 +412,6 @@ export const downloadPatch = ({ state }) => {
*/ */
const { vulnerability } = state.modal; const { vulnerability } = state.modal;
download({ fileData: vulnerability.remediations[0].diff, fileName: 'remediation.patch' }); download({ fileData: vulnerability.remediations[0].diff, fileName: 'remediation.patch' });
$('#modal-mrwidget-security-issue').modal('hide');
}; };
export const requestCreateMergeRequest = ({ commit }) => { export const requestCreateMergeRequest = ({ commit }) => {
......
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import component from '~/reports/components/modal_open_name.vue'; import { VULNERABILITY_MODAL_ID } from 'ee/vue_shared/security_reports/components/constants';
import component from 'ee/reports/components/modal_open_name.vue';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -11,7 +12,7 @@ describe('Modal open name', () => { ...@@ -11,7 +12,7 @@ describe('Modal open name', () => {
const store = new Vuex.Store({ const store = new Vuex.Store({
actions: { actions: {
openModal: () => {}, setModalData: () => {},
}, },
state: {}, state: {},
mutations: {}, mutations: {},
...@@ -37,11 +38,13 @@ describe('Modal open name', () => { ...@@ -37,11 +38,13 @@ describe('Modal open name', () => {
expect(vm.$el.textContent.trim()).toEqual('Issue'); expect(vm.$el.textContent.trim()).toEqual('Issue');
}); });
it('calls openModal actions when button is clicked', () => { it('calls setModalData actions and opens modal when button is clicked', () => {
jest.spyOn(vm, 'openModal').mockImplementation(() => {}); jest.spyOn(vm, 'setModalData').mockImplementation(() => {});
jest.spyOn(vm.$root, '$emit');
vm.$el.click(); vm.$el.click();
expect(vm.openModal).toHaveBeenCalled(); expect(vm.setModalData).toHaveBeenCalled();
expect(vm.$root.$emit).toHaveBeenCalledWith('bv::show::modal', VULNERABILITY_MODAL_ID);
}); });
}); });
...@@ -2,6 +2,7 @@ import { GlFormCheckbox } from '@gitlab/ui'; ...@@ -2,6 +2,7 @@ import { GlFormCheckbox } from '@gitlab/ui';
import { mount, shallowMount, createLocalVue } from '@vue/test-utils'; import { mount, shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import SecurityDashboardTableRow from 'ee/security_dashboard/components/security_dashboard_table_row.vue'; import SecurityDashboardTableRow from 'ee/security_dashboard/components/security_dashboard_table_row.vue';
import { VULNERABILITY_MODAL_ID } from 'ee/vue_shared/security_reports/components/constants';
import createStore from 'ee/security_dashboard/store'; import createStore from 'ee/security_dashboard/store';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants'; import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
...@@ -104,15 +105,20 @@ describe('Security Dashboard Table Row', () => { ...@@ -104,15 +105,20 @@ describe('Security Dashboard Table Row', () => {
expect(findContent(1).text()).toContain(vulnerability.location.file); expect(findContent(1).text()).toContain(vulnerability.location.file);
}); });
it('should fire the openModal action when clicked', () => { it('should fire the setModalData action and open the modal when clicked', () => {
jest.spyOn(store, 'dispatch').mockImplementation(); jest.spyOn(store, 'dispatch').mockImplementation();
jest.spyOn(wrapper.vm.$root, '$emit');
const el = wrapper.find({ ref: 'vulnerability-title' }); const el = wrapper.find({ ref: 'vulnerability-title' });
el.trigger('click'); el.trigger('click');
expect(store.dispatch).toHaveBeenCalledWith('vulnerabilities/openModal', { expect(store.dispatch).toHaveBeenCalledWith('vulnerabilities/setModalData', {
vulnerability, vulnerability,
}); });
expect(wrapper.vm.$root.$emit).toHaveBeenCalledWith(
'bv::show::modal',
VULNERABILITY_MODAL_ID,
);
}); });
}); });
......
...@@ -103,14 +103,14 @@ describe('Security Dashboard component', () => { ...@@ -103,14 +103,14 @@ describe('Security Dashboard component', () => {
${'createNewIssue'} | ${undefined} | ${'vulnerabilities/createIssue'} | ${{ vulnerability: 'bar' }} ${'createNewIssue'} | ${undefined} | ${'vulnerabilities/createIssue'} | ${{ vulnerability: 'bar' }}
${'dismissVulnerability'} | ${'bar'} | ${'vulnerabilities/dismissVulnerability'} | ${{ comment: 'bar', vulnerability: 'bar' }} ${'dismissVulnerability'} | ${'bar'} | ${'vulnerabilities/dismissVulnerability'} | ${{ comment: 'bar', vulnerability: 'bar' }}
${'openDismissalCommentBox'} | ${undefined} | ${'vulnerabilities/openDismissalCommentBox'} | ${undefined} ${'openDismissalCommentBox'} | ${undefined} | ${'vulnerabilities/openDismissalCommentBox'} | ${undefined}
${'revertDismissVulnerability'} | ${undefined} | ${'vulnerabilities/undoDismiss'} | ${{ vulnerability: 'bar' }} ${'revertDismissVulnerability'} | ${undefined} | ${'vulnerabilities/revertDismissVulnerability'} | ${{ vulnerability: 'bar' }}
${'downloadPatch'} | ${undefined} | ${'vulnerabilities/downloadPatch'} | ${{ vulnerability: 'bar' }} ${'downloadPatch'} | ${undefined} | ${'vulnerabilities/downloadPatch'} | ${{ vulnerability: 'bar' }}
`( `(
'dispatches the "$expectedDispatchedAction" action when the modal emits a "$emittedModalEvent" event', 'dispatches the "$expectedDispatchedAction" action when the modal emits a "$emittedModalEvent" event',
({ emittedModalEvent, eventPayload, expectedDispatchedAction, expectedActionPayload }) => { ({ emittedModalEvent, eventPayload, expectedDispatchedAction, expectedActionPayload }) => {
store.state.vulnerabilities.modal.vulnerability = 'bar'; store.state.vulnerabilities.modal.vulnerability = 'bar';
jest.spyOn(store, 'dispatch').mockImplementation(); jest.spyOn(store, 'dispatch').mockImplementation(() => Promise.resolve());
wrapper.find(IssueModal).vm.$emit(emittedModalEvent, eventPayload); wrapper.find(IssueModal).vm.$emit(emittedModalEvent, eventPayload);
expect(store.dispatch).toHaveBeenCalledWith( expect(store.dispatch).toHaveBeenCalledWith(
......
...@@ -3,6 +3,7 @@ import component from 'ee/security_dashboard/components/vulnerability_action_but ...@@ -3,6 +3,7 @@ import component from 'ee/security_dashboard/components/vulnerability_action_but
import createStore from 'ee/security_dashboard/store'; import createStore from 'ee/security_dashboard/store';
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { VULNERABILITY_MODAL_ID } from 'ee/vue_shared/security_reports/components/constants';
import { resetStore } from '../helpers'; import { resetStore } from '../helpers';
import mockDataVulnerabilities from '../store/modules/vulnerabilities/data/mock_data_vulnerabilities'; import mockDataVulnerabilities from '../store/modules/vulnerabilities/data/mock_data_vulnerabilities';
...@@ -51,12 +52,15 @@ describe('Security Dashboard Action Buttons', () => { ...@@ -51,12 +52,15 @@ describe('Security Dashboard Action Buttons', () => {
expect(button).not.toBeNull(); expect(button).not.toBeNull();
}); });
it('should emit an `openModal` event when clicked', () => { it('should emit an `setModalData` event and open the modal when clicked', () => {
jest.spyOn(vm.$root, '$emit');
button.click(); button.click();
expect(vm.$store.dispatch).toHaveBeenCalledWith('vulnerabilities/openModal', { expect(vm.$store.dispatch).toHaveBeenCalledWith('vulnerabilities/setModalData', {
vulnerability: mockDataVulnerabilities[0], vulnerability: mockDataVulnerabilities[0],
}); });
expect(vm.$root.$emit).toHaveBeenCalledWith('bv::show::modal', VULNERABILITY_MODAL_ID);
}); });
}); });
......
...@@ -222,7 +222,7 @@ describe('vulnerabilities actions', () => { ...@@ -222,7 +222,7 @@ describe('vulnerabilities actions', () => {
}); });
}); });
describe('openModal', () => { describe('setModalData', () => {
let state; let state;
beforeEach(() => { beforeEach(() => {
...@@ -232,7 +232,7 @@ describe('openModal', () => { ...@@ -232,7 +232,7 @@ describe('openModal', () => {
it('should commit the SET_MODAL_DATA mutation', () => { it('should commit the SET_MODAL_DATA mutation', () => {
const vulnerability = mockDataVulnerabilities[0]; const vulnerability = mockDataVulnerabilities[0];
return testAction(actions.openModal, { vulnerability }, state, [ return testAction(actions.setModalData, { vulnerability }, state, [
{ {
type: types.SET_MODAL_DATA, type: types.SET_MODAL_DATA,
payload: { vulnerability }, payload: { vulnerability },
...@@ -1044,7 +1044,7 @@ describe('hideDismissalDeleteButtons', () => { ...@@ -1044,7 +1044,7 @@ describe('hideDismissalDeleteButtons', () => {
}); });
describe('revert vulnerability dismissal', () => { describe('revert vulnerability dismissal', () => {
describe('undoDismiss', () => { describe('revertDismissVulnerability', () => {
const vulnerability = mockDataVulnerabilities[2]; const vulnerability = mockDataVulnerabilities[2];
const url = vulnerability.dismissal_feedback.destroy_vulnerability_feedback_dismissal_path; const url = vulnerability.dismissal_feedback.destroy_vulnerability_feedback_dismissal_path;
let mock; let mock;
...@@ -1064,7 +1064,7 @@ describe('revert vulnerability dismissal', () => { ...@@ -1064,7 +1064,7 @@ describe('revert vulnerability dismissal', () => {
it('should dispatch the request and success actions', () => { it('should dispatch the request and success actions', () => {
return testAction( return testAction(
actions.undoDismiss, actions.revertDismissVulnerability,
{ vulnerability }, { vulnerability },
{}, {},
[], [],
...@@ -1085,7 +1085,7 @@ describe('revert vulnerability dismissal', () => { ...@@ -1085,7 +1085,7 @@ describe('revert vulnerability dismissal', () => {
const flashError = false; const flashError = false;
return testAction( return testAction(
actions.undoDismiss, actions.revertDismissVulnerability,
{ vulnerability, flashError }, { vulnerability, flashError },
{}, {},
[], [],
......
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import { GlModal } from '@gitlab/ui';
import Vue from 'vue'; import Vue from 'vue';
import IssueNote from 'ee/vue_shared/security_reports/components/issue_note.vue'; import IssueNote from 'ee/vue_shared/security_reports/components/issue_note.vue';
import MergeRequestNote from 'ee/vue_shared/security_reports/components/merge_request_note.vue'; import MergeRequestNote from 'ee/vue_shared/security_reports/components/merge_request_note.vue';
...@@ -8,9 +9,14 @@ import createState from 'ee/vue_shared/security_reports/store/state'; ...@@ -8,9 +9,14 @@ import createState from 'ee/vue_shared/security_reports/store/state';
describe('Security Reports modal', () => { describe('Security Reports modal', () => {
let wrapper; let wrapper;
let modal;
const mountComponent = (propsData, mountFn = shallowMount) => { const mountComponent = (propsData, mountFn = shallowMount) => {
wrapper = mountFn(component, { wrapper = mountFn(component, {
attrs: {
static: true,
visible: true,
},
propsData: { propsData: {
isCreatingIssue: false, isCreatingIssue: false,
isDismissingVulnerability: false, isDismissingVulnerability: false,
...@@ -18,6 +24,7 @@ describe('Security Reports modal', () => { ...@@ -18,6 +24,7 @@ describe('Security Reports modal', () => {
...propsData, ...propsData,
}, },
}); });
modal = wrapper.find(GlModal);
}; };
describe('with permissions', () => { describe('with permissions', () => {
...@@ -37,13 +44,13 @@ describe('Security Reports modal', () => { ...@@ -37,13 +44,13 @@ describe('Security Reports modal', () => {
}); });
it('renders dismissal author and associated pipeline', () => { it('renders dismissal author and associated pipeline', () => {
expect(wrapper.text().trim()).toContain('John Smith'); expect(modal.text().trim()).toContain('John Smith');
expect(wrapper.text().trim()).toContain('@jsmith'); expect(modal.text().trim()).toContain('@jsmith');
expect(wrapper.text().trim()).toContain('#123'); expect(modal.text().trim()).toContain('#123');
}); });
it('renders the dismissal comment placeholder', () => { it('renders the dismissal comment placeholder', () => {
expect(wrapper.find('.js-comment-placeholder')).not.toBeNull(); expect(modal.find('.js-comment-placeholder')).not.toBeNull();
}); });
}); });
...@@ -61,9 +68,9 @@ describe('Security Reports modal', () => { ...@@ -61,9 +68,9 @@ describe('Security Reports modal', () => {
}); });
it('renders dismissal author and hides associated pipeline', () => { it('renders dismissal author and hides associated pipeline', () => {
expect(wrapper.text().trim()).toContain('John Smith'); expect(modal.text().trim()).toContain('John Smith');
expect(wrapper.text().trim()).toContain('@jsmith'); expect(modal.text().trim()).toContain('@jsmith');
expect(wrapper.text().trim()).not.toContain('#123'); expect(modal.text().trim()).not.toContain('#123');
}); });
}); });
...@@ -137,7 +144,7 @@ describe('Security Reports modal', () => { ...@@ -137,7 +144,7 @@ describe('Security Reports modal', () => {
}); });
it('renders title', () => { it('renders title', () => {
expect(wrapper.text()).toContain('Arbitrary file existence disclosure in Action Pack'); expect(modal.text()).toContain('Arbitrary file existence disclosure in Action Pack');
}); });
}); });
...@@ -303,7 +310,7 @@ describe('Security Reports modal', () => { ...@@ -303,7 +310,7 @@ describe('Security Reports modal', () => {
}); });
describe('Solution Card', () => { describe('Solution Card', () => {
it('is rendered if the vulnerability has a solution', () => { it('is rendered if the vulnerability has a solution', async () => {
const propsData = { const propsData = {
modal: createState().modal, modal: createState().modal,
}; };
...@@ -311,15 +318,16 @@ describe('Security Reports modal', () => { ...@@ -311,15 +318,16 @@ describe('Security Reports modal', () => {
const solution = 'Upgrade to XYZ'; const solution = 'Upgrade to XYZ';
propsData.modal.vulnerability.solution = solution; propsData.modal.vulnerability.solution = solution;
mountComponent(propsData, mount); mountComponent(propsData, mount);
await wrapper.vm.$nextTick();
const solutionCard = wrapper.find(SolutionCard); const solutionCard = modal.find(SolutionCard);
expect(solutionCard.exists()).toBe(true); expect(solutionCard.exists()).toBe(true);
expect(solutionCard.text()).toContain(solution); expect(solutionCard.text()).toContain(solution);
expect(wrapper.find('hr').exists()).toBe(false); expect(modal.find('hr').exists()).toBe(false);
}); });
it('is rendered if the vulnerability has a remediation', () => { it('is rendered if the vulnerability has a remediation', async () => {
const propsData = { const propsData = {
modal: createState().modal, modal: createState().modal,
}; };
...@@ -327,6 +335,7 @@ describe('Security Reports modal', () => { ...@@ -327,6 +335,7 @@ describe('Security Reports modal', () => {
const diff = 'foo'; const diff = 'foo';
propsData.modal.vulnerability.remediations = [{ summary, diff }]; propsData.modal.vulnerability.remediations = [{ summary, diff }];
mountComponent(propsData, mount); mountComponent(propsData, mount);
await wrapper.vm.$nextTick();
const solutionCard = wrapper.find(SolutionCard); const solutionCard = wrapper.find(SolutionCard);
...@@ -336,11 +345,12 @@ describe('Security Reports modal', () => { ...@@ -336,11 +345,12 @@ describe('Security Reports modal', () => {
expect(wrapper.find('hr').exists()).toBe(false); expect(wrapper.find('hr').exists()).toBe(false);
}); });
it('is rendered if the vulnerability has neither a remediation nor a solution', () => { it('is rendered if the vulnerability has neither a remediation nor a solution', async () => {
const propsData = { const propsData = {
modal: createState().modal, modal: createState().modal,
}; };
mountComponent(propsData, mount); mountComponent(propsData, mount);
await wrapper.vm.$nextTick();
const solutionCard = wrapper.find(SolutionCard); const solutionCard = wrapper.find(SolutionCard);
......
...@@ -368,11 +368,11 @@ describe('Grouped security reports app', () => { ...@@ -368,11 +368,11 @@ describe('Grouped security reports app', () => {
wrapper.vm.$el.querySelector('[aria-label="Vulnerability Name"]').click(); wrapper.vm.$el.querySelector('[aria-label="Vulnerability Name"]').click();
return Vue.nextTick().then(() => { return Vue.nextTick().then(() => {
expect(wrapper.vm.$el.querySelector('.modal-title').textContent.trim()).toEqual( expect(document.querySelector('.modal-title').textContent.trim()).toEqual(
mockFindings[0].name, mockFindings[0].name,
); );
expect(wrapper.vm.$el.querySelector('.modal-body').textContent).toContain( expect(document.querySelector('.modal-body').textContent).toContain(
mockFindings[0].solution, mockFindings[0].solution,
); );
}); });
......
...@@ -9,7 +9,6 @@ import { ...@@ -9,7 +9,6 @@ import {
requestDastDiff, requestDastDiff,
requestDependencyScanningDiff, requestDependencyScanningDiff,
requestCoverageFuzzingDiff, requestCoverageFuzzingDiff,
openModal,
setModalData, setModalData,
requestDismissVulnerability, requestDismissVulnerability,
receiveDismissVulnerability, receiveDismissVulnerability,
...@@ -272,24 +271,6 @@ describe('security reports actions', () => { ...@@ -272,24 +271,6 @@ describe('security reports actions', () => {
}); });
}); });
describe('openModal', () => {
it('dispatches setModalData action', (done) => {
testAction(
openModal,
{ issue: { id: 1 }, status: 'failed' },
mockedState,
[],
[
{
type: 'setModalData',
payload: { issue: { id: 1 }, status: 'failed' },
},
],
done,
);
});
});
describe('setModalData', () => { describe('setModalData', () => {
it('commits set issue modal data', (done) => { it('commits set issue modal data', (done) => {
testAction( testAction(
......
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