Commit 31c993cd authored by Dave Pisek's avatar Dave Pisek

Vulnerability Chart: Fix selected state of buttons

This commit changes the buttons on the over-time vulnerabilities to
the recommended 'gl-segmented-control' component.

Changelog: changed
EE: true
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73516
parent 2a3aa782
...@@ -203,7 +203,7 @@ export default { ...@@ -203,7 +203,7 @@ export default {
v-if="!isLoadingHistory" v-if="!isLoadingHistory"
:days="$options.days" :days="$options.days"
:active-day="vulnerabilitiesHistoryDayRange" :active-day="vulnerabilitiesHistoryDayRange"
@click="setVulnerabilitiesHistoryDayRange" @days-selected="setVulnerabilitiesHistoryDayRange"
/> />
</div> </div>
......
<script> <script>
import { GlButton } from '@gitlab/ui'; import { GlSegmentedControl } from '@gitlab/ui';
import { n__ } from '~/locale'; import { n__ } from '~/locale';
export default { export default {
name: 'VulnerabilityChartButtons', name: 'VulnerabilityChartButtons',
components: { components: {
GlButton, GlSegmentedControl,
}, },
props: { props: {
days: { days: {
...@@ -18,28 +18,23 @@ export default { ...@@ -18,28 +18,23 @@ export default {
}, },
}, },
computed: { computed: {
buttonContent() { controlOptions() {
return (days) => n__('1 Day', '%d Days', days); return this.days.map((day) => ({ text: n__('1 Day', '%d Days', day), value: day }));
}, },
}, },
methods: { methods: {
clickHandler(days) { inputHandler(days) {
this.$emit('click', days); this.$emit('days-selected', days);
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="btn-group w-100"> <gl-segmented-control
<gl-button :options="controlOptions"
v-for="day in days" :checked="activeDay"
:key="day" class="gl-display-flex"
:class="{ selected: activeDay === day }" @input="inputHandler"
:data-days="day" />
@click="clickHandler(day)"
>
{{ buttonContent(day) }}
</gl-button>
</div>
</template> </template>
import { shallowMount, mount, createLocalVue } from '@vue/test-utils'; import { GlSegmentedControl } from '@gitlab/ui';
import Vue from 'vue'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import component from 'ee/security_dashboard/components/shared/vulnerabilities_over_time_chart_buttons.vue'; import VulnerabilitiesOverTimeChartButtons from 'ee/security_dashboard/components/shared/vulnerabilities_over_time_chart_buttons.vue';
import { DAYS } from 'ee/security_dashboard/store/constants'; import { DAYS } from 'ee/security_dashboard/store/constants';
const localVue = createLocalVue();
describe('Vulnerability Chart Buttons', () => { describe('Vulnerability Chart Buttons', () => {
let wrapper; let wrapper;
const Component = Vue.extend(component);
const days = Object.values(DAYS); const days = Object.values(DAYS);
const createWrapper = (props = {}, mountfn = shallowMount) => { const findSegmentedControlButtons = () => wrapper.findComponent(GlSegmentedControl);
wrapper = mountfn(localVue.extend(Component), {
const createWrapper = (props = { activeDay: DAYS.thirty }) => {
wrapper = shallowMountExtended(VulnerabilitiesOverTimeChartButtons, {
propsData: { days, ...props }, propsData: { days, ...props },
localVue,
}); });
}; };
...@@ -21,53 +19,29 @@ describe('Vulnerability Chart Buttons', () => { ...@@ -21,53 +19,29 @@ describe('Vulnerability Chart Buttons', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('when rendering the buttons', () => { it('should pass the correct options to the segmented control group', () => {
it('should render with 90 days selected', () => { createWrapper();
const activeDay = DAYS.ninety;
createWrapper({ activeDay });
const activeButton = wrapper.find('[data-days="90"].selected');
expect(activeButton.attributes('data-days')).toMatch('90');
});
it('should render with 60 days selected', () => {
const activeDay = DAYS.sixty;
createWrapper({ activeDay });
const activeButton = wrapper.find('[data-days="60"].selected');
expect(activeButton.attributes('data-days')).toMatch('60');
});
it('should render with 30 days selected', () => {
const activeDay = DAYS.thirty;
createWrapper({ activeDay });
const activeButton = wrapper.find('[data-days="30"].selected'); expect(findSegmentedControlButtons().props('options')).toStrictEqual([
{ value: DAYS.thirty, text: '30 Days' },
expect(activeButton.attributes('data-days')).toMatch('30'); { value: DAYS.sixty, text: '60 Days' },
}); { value: DAYS.ninety, text: '90 Days' },
]);
}); });
describe('when clicking the button', () => { it.each(days)('should set "%s days" as selected', (activeDay) => {
const activeDay = DAYS.thirty; createWrapper({ activeDay });
beforeEach(() => { expect(findSegmentedControlButtons().props('checked')).toBe(activeDay);
createWrapper({ activeDay }, mount); });
});
it('should call the clickHandler', () => { it('should emit a "days-selected" event with the correct payload when the selection changes', () => {
jest.spyOn(wrapper.vm, 'clickHandler'); createWrapper();
wrapper.find('[data-days="30"].selected').trigger('click', DAYS.thirty);
expect(wrapper.vm.clickHandler).toHaveBeenCalledWith(DAYS.thirty); expect(wrapper.emitted('days-selected')).toBeFalsy();
});
it('should emit a click event', () => { findSegmentedControlButtons().vm.$emit('input', DAYS.thirty);
wrapper.find('[data-days="30"].selected').trigger('click', DAYS.thirty);
expect(wrapper.emitted().click[0]).toEqual([DAYS.thirty]); expect(wrapper.emitted('days-selected')).toEqual([[DAYS.thirty]]);
});
}); });
}); });
import { nextTick } from 'vue';
import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import { GlLoadingIcon, GlTable } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import VulnerabilitiesOverTimeChart from 'ee/security_dashboard/components/shared/vulnerabilities_over_time_chart.vue'; import VulnerabilitiesOverTimeChart from 'ee/security_dashboard/components/shared/vulnerabilities_over_time_chart.vue';
...@@ -19,8 +20,6 @@ describe('Vulnerabilities Over Time Chart Component', () => { ...@@ -19,8 +20,6 @@ describe('Vulnerabilities Over Time Chart Component', () => {
const findTimeInfo = () => wrapper.findByTestId('timeInfo'); const findTimeInfo = () => wrapper.findByTestId('timeInfo');
const findChartButtons = () => wrapper.findComponent(ChartButtons); const findChartButtons = () => wrapper.findComponent(ChartButtons);
const findSelectedChartButton = () => findChartButtons().find('.selected');
const find90DaysChartButton = () => findChartButtons().find('[data-days="90"]');
const mockApollo = (options) => { const mockApollo = (options) => {
return { return {
...@@ -69,24 +68,22 @@ describe('Vulnerabilities Over Time Chart Component', () => { ...@@ -69,24 +68,22 @@ describe('Vulnerabilities Over Time Chart Component', () => {
describe('date range selectors', () => { describe('date range selectors', () => {
beforeEach(() => { beforeEach(() => {
wrapper = createComponent({ wrapper = createComponent({
stubs: { ChartButtons },
$apollo: { refetch: jest.fn() }, $apollo: { refetch: jest.fn() },
}); });
}); });
it('should contain the chart buttons', () => { it('should contain the chart buttons', () => {
expect(findChartButtons().text()).toContain('30 Days'); expect(findChartButtons().props('days')).toEqual([30, 60, 90]);
expect(findChartButtons().text()).toContain('60 Days');
expect(findChartButtons().text()).toContain('90 Days');
}); });
it('should change the actively selected chart button and refetch the new data', () => { it('should change the actively selected chart button and refetch the new data', async () => {
expect(findSelectedChartButton().text()).toContain('30 Days'); expect(findChartButtons().props('activeDay')).toBe(30);
find90DaysChartButton().vm.$emit('click'); findChartButtons().vm.$emit('days-selected', 90);
return wrapper.vm.$nextTick(() => {
expect(findSelectedChartButton().text()).toContain('90 Days'); await nextTick();
expect(wrapper.vm.$apollo.queries.vulnerabilitiesHistory.refetch).toHaveBeenCalledTimes(1);
}); expect(findChartButtons().props('activeDay')).toBe(90);
expect(wrapper.vm.$apollo.queries.vulnerabilitiesHistory.refetch).toHaveBeenCalledTimes(1);
}); });
}); });
......
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