Commit 726e45cc authored by Nick Gaskill's avatar Nick Gaskill Committed by Kushal Pandya

Finish migration to GlModal

The Test Report Modal in the Merge Request Widget made use of the old
Bootstrap modals. In order to be able to use GLModal, we are now
persisting the Modal visibility state in VueX.
parent 52e8bc0a
......@@ -45,6 +45,7 @@ export default {
...mapState({
modalTitle: (state) => state.modal.title || '',
modalData: (state) => state.modal.data || {},
modalOpen: (state) => state.modal.open || false,
}),
...mapGetters(['summaryStatus']),
groupedSummaryText() {
......@@ -76,7 +77,7 @@ export default {
this.fetchReports();
},
methods: {
...mapActions(['setEndpoint', 'fetchReports']),
...mapActions(['setEndpoint', 'fetchReports', 'closeModal']),
reportText(report) {
const { name, summary } = report || {};
......@@ -170,8 +171,12 @@ export default {
class="report-block-group-list"
/>
</template>
<modal :title="modalTitle" :modal-data="modalData" />
<modal
:visible="modalOpen"
:title="modalTitle"
:modal-data="modalData"
@hide="closeModal"
/>
</div>
</template>
</report-section>
......
<script>
// import { sprintf, __ } from '~/locale';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import { GlModal, GlLink, GlSprintf } from '@gitlab/ui';
import CodeBlock from '~/vue_shared/components/code_block.vue';
import { fieldTypes } from '../constants';
export default {
components: {
Modal: DeprecatedModal2,
CodeBlock,
GlModal,
GlLink,
GlSprintf,
},
props: {
visible: {
type: Boolean,
required: true,
},
title: {
type: String,
required: true,
......@@ -23,39 +29,43 @@ export default {
};
</script>
<template>
<modal
id="modal-mrwidget-reports"
:header-title-text="title"
class="modal-security-report-dast modal-hide-footer"
<gl-modal
:visible="visible"
modal-id="modal-mrwidget-reports"
:title="title"
:hide-footer="true"
@hide="$emit('hide')"
>
<slot>
<div
v-for="(field, key, index) in modalData"
v-if="field.value"
:key="index"
class="row gl-mt-3 gl-mb-3"
>
<strong class="col-sm-3 text-right"> {{ field.text }}: </strong>
<div
v-for="(field, key, index) in modalData"
v-if="field.value"
:key="index"
class="row gl-mt-3 gl-mb-3"
>
<strong class="col-sm-3 text-right"> {{ field.text }}: </strong>
<div class="col-sm-9 text-secondary">
<code-block v-if="field.type === $options.fieldTypes.codeBock" :code="field.value" />
<div class="col-sm-9 text-secondary">
<code-block v-if="field.type === $options.fieldTypes.codeBock" :code="field.value" />
<template v-else-if="field.type === $options.fieldTypes.link">
<a :href="field.value" target="_blank" rel="noopener noreferrer" class="js-modal-link">
{{ field.value }}
</a>
</template>
<gl-link
v-else-if="field.type === $options.fieldTypes.link"
:href="field.value"
target="_blank"
>
{{ field.value }}
</gl-link>
<template v-else-if="field.type === $options.fieldTypes.seconds">{{
sprintf(__('%{value} s'), { value: field.value })
}}</template>
<gl-sprintf
v-else-if="field.type === $options.fieldTypes.seconds"
:message="__('%{value} s')"
>
<template #value>{{ field.value }}</template>
</gl-sprintf>
<template v-else-if="field.type === $options.fieldTypes.text">
{{ field.value }}
</template>
</div>
<template v-else-if="field.type === $options.fieldTypes.text">
{{ field.value }}
</template>
</div>
</slot>
<div slot="footer"></div>
</modal>
</div>
</gl-modal>
</template>
import Visibility from 'visibilityjs';
import $ from 'jquery';
import axios from '../../lib/utils/axios_utils';
import Poll from '../../lib/utils/poll';
import * as types from './mutation_types';
......@@ -78,10 +77,6 @@ export const receiveReportsSuccess = ({ commit }, response) => {
export const receiveReportsError = ({ commit }) => commit(types.RECEIVE_REPORTS_ERROR);
export const openModal = ({ dispatch }, payload) => {
dispatch('setModalData', payload);
export const openModal = ({ commit }, payload) => commit(types.SET_ISSUE_MODAL_DATA, payload);
$('#modal-mrwidget-reports').modal('show');
};
export const setModalData = ({ commit }, payload) => commit(types.SET_ISSUE_MODAL_DATA, payload);
export const closeModal = ({ commit }, payload) => commit(types.RESET_ISSUE_MODAL_DATA, payload);
......@@ -4,3 +4,4 @@ export const REQUEST_REPORTS = 'REQUEST_REPORTS';
export const RECEIVE_REPORTS_SUCCESS = 'RECEIVE_REPORTS_SUCCESS';
export const RECEIVE_REPORTS_ERROR = 'RECEIVE_REPORTS_ERROR';
export const SET_ISSUE_MODAL_DATA = 'SET_ISSUE_MODAL_DATA';
export const RESET_ISSUE_MODAL_DATA = 'RESET_ISSUE_MODAL_DATA';
......@@ -52,5 +52,19 @@ export default {
};
}
});
state.modal.open = true;
},
[types.RESET_ISSUE_MODAL_DATA](state) {
state.modal.open = false;
// Resetting modal data
state.modal.title = null;
Object.keys(state.modal.data).forEach((key) => {
state.modal.data[key] = {
...state.modal.data[key],
value: null,
};
});
},
};
......@@ -38,6 +38,7 @@ export default () => ({
modal: {
title: null,
open: false,
data: {
class: {
......
......@@ -605,11 +605,14 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
click_button 'addTest'
expect(page).to have_content('6.66')
expect(page).to have_content(sample_java_failed_message.gsub(/\s+/, ' ').strip)
end
end
within("#modal-mrwidget-reports") do
expect(page).to have_content('addTest')
expect(page).to have_content('6.66')
expect(page).to have_content(sample_java_failed_message.gsub(/\s+/, ' ').strip)
end
end
end
end
......@@ -650,11 +653,14 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
click_button 'Test#sum when a is 1 and b is 3 returns summary'
expect(page).to have_content('2.22')
expect(page).to have_content(sample_rspec_failed_message.gsub(/\s+/, ' ').strip)
end
end
within("#modal-mrwidget-reports") do
expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary')
expect(page).to have_content('2.22')
expect(page).to have_content(sample_rspec_failed_message.gsub(/\s+/, ' ').strip)
end
end
end
end
......@@ -694,10 +700,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
click_button 'addTest'
expect(page).to have_content('5.55')
end
end
within("#modal-mrwidget-reports") do
expect(page).to have_content('addTest')
expect(page).to have_content('5.55')
end
end
end
end
......@@ -738,10 +747,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
click_button 'addTest'
expect(page).to have_content('8.88')
end
end
within("#modal-mrwidget-reports") do
expect(page).to have_content('addTest')
expect(page).to have_content('8.88')
end
end
end
end
......@@ -782,10 +794,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
click_button 'Test#sum when a is 4 and b is 4 returns summary'
expect(page).to have_content('4.44')
end
end
within("#modal-mrwidget-reports") do
expect(page).to have_content('Test#sum when a is 4 and b is 4 returns summary')
expect(page).to have_content('4.44')
end
end
end
end
......@@ -825,10 +840,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
click_button 'addTest'
expect(page).to have_content('5.55')
end
end
within("#modal-mrwidget-reports") do
expect(page).to have_content('addTest')
expect(page).to have_content('5.55')
end
end
end
end
......
import Vue from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import { trimText } from 'helpers/text_helper';
import component from '~/reports/components/modal.vue';
import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import CodeBlock from '~/vue_shared/components/code_block.vue';
import ReportsModal from '~/reports/components/modal.vue';
import state from '~/reports/store/state';
const StubbedGlModal = { template: '<div><slot></slot></div>', name: 'GlModal', props: ['title'] };
describe('Grouped Test Reports Modal', () => {
const Component = Vue.extend(component);
const modalDataStructure = state().modal.data;
const title = 'Test#sum when a is 1 and b is 2 returns summary';
// populate data
modalDataStructure.execution_time.value = 0.009411;
modalDataStructure.system_output.value = 'Failure/Error: is_expected.to eq(3)\n\n';
modalDataStructure.class.value = 'link';
let vm;
let wrapper;
beforeEach(() => {
vm = mountComponent(Component, {
title: 'Test#sum when a is 1 and b is 2 returns summary',
modalData: modalDataStructure,
});
wrapper = extendedWrapper(
shallowMount(ReportsModal, {
propsData: {
title,
modalData: modalDataStructure,
visible: true,
},
stubs: { GlModal: StubbedGlModal, GlSprintf },
}),
);
});
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
it('renders code block', () => {
expect(vm.$el.querySelector('code').textContent).toEqual(
modalDataStructure.system_output.value,
);
expect(wrapper.find(CodeBlock).props().code).toEqual(modalDataStructure.system_output.value);
});
it('renders link', () => {
expect(vm.$el.querySelector('.js-modal-link').getAttribute('href')).toEqual(
modalDataStructure.class.value,
);
const link = wrapper.findComponent(GlLink);
expect(trimText(vm.$el.querySelector('.js-modal-link').textContent)).toEqual(
modalDataStructure.class.value,
);
expect(link.attributes().href).toEqual(modalDataStructure.class.value);
expect(link.text()).toEqual(modalDataStructure.class.value);
});
it('renders seconds', () => {
expect(vm.$el.textContent).toContain(`${modalDataStructure.execution_time.value} s`);
expect(wrapper.text()).toContain(`${modalDataStructure.execution_time.value} s`);
});
it('render title', () => {
expect(trimText(vm.$el.querySelector('.modal-title').textContent)).toEqual(
'Test#sum when a is 1 and b is 2 returns summary',
);
expect(wrapper.findComponent(StubbedGlModal).props().title).toEqual(title);
});
it('re-emits hide event', () => {
wrapper.findComponent(StubbedGlModal).vm.$emit('hide');
expect(wrapper.emitted().hide).toEqual([[]]);
});
});
......@@ -11,7 +11,7 @@ import {
receiveReportsSuccess,
receiveReportsError,
openModal,
setModalData,
closeModal,
} from '~/reports/store/actions';
import state from '~/reports/store/state';
import * as types from '~/reports/store/mutation_types';
......@@ -144,25 +144,25 @@ describe('Reports Store Actions', () => {
});
describe('openModal', () => {
it('should dispatch setModalData', (done) => {
it('should commit SET_ISSUE_MODAL_DATA', (done) => {
testAction(
openModal,
{ name: 'foo' },
mockedState,
[{ type: types.SET_ISSUE_MODAL_DATA, payload: { name: 'foo' } }],
[],
[{ type: 'setModalData', payload: { name: 'foo' } }],
done,
);
});
});
describe('setModalData', () => {
it('should commit SET_ISSUE_MODAL_DATA', (done) => {
describe('closeModal', () => {
it('should commit RESET_ISSUE_MODAL_DATA', (done) => {
testAction(
setModalData,
{ name: 'foo' },
closeModal,
{},
mockedState,
[{ type: types.SET_ISSUE_MODAL_DATA, payload: { name: 'foo' } }],
[{ type: types.RESET_ISSUE_MODAL_DATA, payload: {} }],
[],
done,
);
......
......@@ -127,5 +127,32 @@ describe('Reports Store Mutations', () => {
expect(stateCopy.modal.data.execution_time.value).toEqual(issue.execution_time);
expect(stateCopy.modal.data.system_output.value).toEqual(issue.system_output);
});
it('should open modal', () => {
expect(stateCopy.modal.open).toEqual(true);
});
});
describe('RESET_ISSUE_MODAL_DATA', () => {
beforeEach(() => {
mutations[types.SET_ISSUE_MODAL_DATA](stateCopy, {
issue,
});
mutations[types.RESET_ISSUE_MODAL_DATA](stateCopy);
});
it('should reset modal title', () => {
expect(stateCopy.modal.title).toEqual(null);
});
it('should reset modal data', () => {
expect(stateCopy.modal.data.execution_time.value).toEqual(null);
expect(stateCopy.modal.data.system_output.value).toEqual(null);
});
it('should close modal', () => {
expect(stateCopy.modal.open).toEqual(false);
});
});
});
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