Commit a7601b55 authored by Phil Hughes's avatar Phil Hughes

Merge branch '8893-persist-security-dashboard-state-in-url-ee' into 'master'

Persist Group Level Security Dashboard state in URL

See merge request gitlab-org/gitlab-ee!9108
parents 930d2475 f52c9926
......@@ -64,7 +64,9 @@ export default {
this.setVulnerabilitiesEndpoint(this.vulnerabilitiesEndpoint);
this.setVulnerabilitiesCountEndpoint(this.vulnerabilitiesCountEndpoint);
this.setVulnerabilitiesHistoryEndpoint(this.vulnerabilitiesHistoryEndpoint);
this.fetchVulnerabilitiesCount();
this.fetchVulnerabilities(this.activeFilters);
this.fetchVulnerabilitiesCount(this.activeFilters);
this.fetchVulnerabilitiesHistory(this.activeFilters);
this.fetchProjects();
},
methods: {
......@@ -80,18 +82,13 @@ export default {
'setVulnerabilitiesHistoryEndpoint',
]),
...mapActions('projects', ['setProjectsEndpoint', 'fetchProjects']),
filterChange() {
this.fetchVulnerabilities(this.activeFilters);
this.fetchVulnerabilitiesCount(this.activeFilters);
this.fetchVulnerabilitiesHistory(this.activeFilters);
},
},
};
</script>
<template>
<div>
<filters :dashboard-documentation="dashboardDocumentation" @change="filterChange" />
<filters :dashboard-documentation="dashboardDocumentation" />
<vulnerability-count-list />
<h4 class="my-4">{{ __('Vulnerability Chart') }}</h4>
<vulnerability-chart />
......
......@@ -26,6 +26,9 @@ export default {
filter() {
return this.getFilter(this.filterId);
},
selection() {
return this.getFilter(this.filterId).selection;
},
selectedOptionText() {
return this.getSelectedOptionNames(this.filterId) || '-';
},
......@@ -37,7 +40,9 @@ export default {
filterId: this.filterId,
optionId: option.id,
});
this.$emit('change');
},
isSelected(option) {
return this.selection.has(option.id);
},
},
};
......@@ -57,11 +62,11 @@ export default {
@click="clickFilter(option)"
>
<icon
v-if="option.selected"
v-if="isSelected(option)"
class="vertical-align-middle js-check"
name="mobile-issue-close"
/>
<span class="vertical-align-middle" :class="{ 'prepend-left-20': !option.selected }">{{
<span class="vertical-align-middle" :class="{ 'prepend-left-20': !isSelected(option) }">{{
option.name
}}</span>
</gl-dropdown-item>
......
......@@ -27,7 +27,6 @@ export default {
class="col-sm-6 col-md-4 col-lg-2 p-2 js-filter"
:filter-id="filter.id"
:dashboard-documentation="dashboardDocumentation"
@change="$emit('change')"
/>
</div>
</div>
......
......@@ -43,9 +43,6 @@ export default {
return this.pageInfo && this.pageInfo.total;
},
},
created() {
this.fetchVulnerabilities();
},
methods: {
...mapActions('vulnerabilities', ['fetchVulnerabilities', 'openModal']),
fetchPage(page) {
......
<script>
import dateFormat from 'dateformat';
import { mapState, mapActions } from 'vuex';
import { mapState } from 'vuex';
import { GlChart } from '@gitlab/ui/dist/charts';
import ChartTooltip from './vulnerability_chart_tooltip.vue';
......@@ -142,11 +142,7 @@ export default {
};
},
},
created() {
this.fetchVulnerabilitiesHistory();
},
methods: {
...mapActions('vulnerabilities', ['fetchVulnerabilitiesHistory']),
renderTooltip(params, ticket, callback) {
this.tooltipTitle = dateFormat(params[0].axisValue, 'd mmmm');
this.tooltipEntries = params;
......
import Vue from 'vue';
import GroupSecurityDashboardApp from './components/app.vue';
import store from './store';
import createStore from './store';
import router from './store/router';
export default () => {
const el = document.getElementById('js-group-security-dashboard');
const store = createStore();
return new Vue({
el,
store,
router,
components: {
GroupSecurityDashboardApp,
},
......
import Vue from 'vue';
import Vuex from 'vuex';
import router from './router';
import configureModerator from './moderator';
import filters from './modules/filters/index';
import projects from './modules/projects/index';
......@@ -7,14 +8,18 @@ import vulnerabilities from './modules/vulnerabilities/index';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
filters,
projects,
vulnerabilities,
},
});
export default () => {
const store = new Vuex.Store({
modules: {
filters,
projects,
vulnerabilities,
},
});
configureModerator(store);
store.$router = router;
export default () => store;
configureModerator(store);
return store;
};
import * as vulnerabilitiesMutationTypes from './modules/vulnerabilities/mutation_types';
import * as filtersMutationTypes from './modules/filters/mutation_types';
import * as projectsMutationTypes from './modules/projects/mutation_types';
export default function configureModerator(store) {
store.$router.beforeEach((to, from, next) => {
const updatedFromState = (to.params && to.params.updatedFromState) || false;
if (to.name === 'dashboard' && !updatedFromState) {
store.dispatch(`filters/setAllFilters`, to.query);
}
next();
});
store.subscribe(({ type, payload }) => {
switch (type) {
case `projects/${projectsMutationTypes.RECEIVE_PROJECTS_SUCCESS}`:
return store.dispatch('filters/setFilterOptions', {
store.dispatch('filters/setFilterOptions', {
filterId: 'project_id',
options: [
{
name: 'All',
id: 'all',
selected: true,
},
...payload.projects.map(project => ({
name: project.name,
id: project.id.toString(),
selected: false,
})),
],
});
break;
case `filters/${filtersMutationTypes.SET_ALL_FILTERS}`:
case `filters/${filtersMutationTypes.SET_FILTER}`: {
const activeFilters = store.getters['filters/activeFilters'];
store.dispatch('vulnerabilities/fetchVulnerabilities', activeFilters);
store.dispatch('vulnerabilities/fetchVulnerabilitiesCount', activeFilters);
store.dispatch('vulnerabilities/fetchVulnerabilitiesHistory', activeFilters);
break;
}
case `vulnerabilities/${vulnerabilitiesMutationTypes.RECEIVE_VULNERABILITIES_SUCCESS}`: {
const activeFilters = store.getters['filters/activeFilters'];
store.$router.push({
name: 'dashboard',
query: activeFilters,
params: { updatedFromState: true },
});
break;
}
default:
return null;
}
});
}
......@@ -14,6 +14,10 @@ export const setFilterOptions = ({ commit }, payload) => {
commit(types.SET_FILTER_OPTIONS, payload);
};
export const setAllFilters = ({ commit }, payload) => {
commit(types.SET_ALL_FILTERS, payload);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
// This is no longer needed after gitlab-ce#52179 is merged
export default () => {};
......@@ -2,11 +2,10 @@ import { sprintf, __ } from '~/locale';
export const getFilter = state => filterId => state.filters.find(filter => filter.id === filterId);
export const getSelectedOptions = (state, getters) => filterId =>
getters.getFilter(filterId).options.filter(option => option.selected);
export const getSelectedOptionIds = (state, getters) => filterId =>
getters.getSelectedOptions(filterId).map(option => option.id);
export const getSelectedOptions = (state, getters) => filterId => {
const filter = getters.getFilter(filterId);
return filter.options.filter(option => filter.selection.has(option.id));
};
export const getSelectedOptionNames = (state, getters) => filterId => {
const selectedOptions = getters.getSelectedOptions(filterId);
......@@ -21,22 +20,17 @@ export const getSelectedOptionNames = (state, getters) => filterId => {
: firstOption;
};
export const getFilterIds = state => state.filters.map(filter => filter.id);
/**
* Loops through all the filters and returns all the active ones
* stripping out any that are set to 'all'
* @returns Object
* e.g. { type: ['sast'], severity: ['high', 'medium'] }
*/
export const activeFilters = (state, getters) =>
getters.getFilterIds.reduce(
(result, filterId) => ({
...result,
[filterId]: getters.getSelectedOptionIds(filterId).filter(option => option !== 'all'),
}),
{},
);
export const activeFilters = state =>
state.filters.reduce((acc, filter) => {
acc[filter.id] = [...filter.selection].filter(option => option !== 'all');
return acc;
}, {});
// prevent babel-plugin-rewire from generating an invalid default during karma tests
// This is no longer needed after gitlab-ce#52179 is merged
......
export const SET_FILTER = 'SET_FILTER';
export const SET_FILTER_OPTIONS = 'SET_FILTER_OPTIONS';
export const SET_ALL_FILTERS = 'SET_ALL_FILTERS';
import * as types from './mutation_types';
export default {
[types.SET_ALL_FILTERS](state, payload = {}) {
state.filters = state.filters.map(filter => {
// If the payload is empty, we fall back to an empty selection
const selectedOptions = (payload && payload[filter.id]) || [];
const selection = Array.isArray(selectedOptions)
? new Set(selectedOptions)
: new Set([selectedOptions]);
// This prevents us from selecting nothing at all
if (selection.size === 0) {
selection.add('all');
}
return { ...filter, selection };
});
},
[types.SET_FILTER](state, payload) {
const { filterId, optionId } = payload;
const activeFilter = state.filters.find(filter => filter.id === filterId);
if (activeFilter) {
let activeOptions;
let selection = new Set(activeFilter.selection);
if (optionId === 'all') {
activeOptions = activeFilter.options.map(option => ({
...option,
selected: option.id === optionId,
}));
selection = new Set(['all']);
} else {
activeOptions = activeFilter.options.map(option => {
if (option.id === 'all') {
return {
...option,
selected: false,
};
}
if (option.id === optionId) {
return {
...option,
selected: !option.selected,
};
}
return option;
});
selection.delete('all');
if (selection.has(optionId)) {
selection.delete(optionId);
} else {
selection.add(optionId);
}
}
// This prevents us from selecting nothing at all
if (!activeOptions.find(option => option.selected)) {
activeOptions[0].selected = true;
if (selection.size === 0) {
selection.add('all');
}
activeFilter.options = activeOptions;
activeFilter.selection = selection;
}
},
[types.SET_FILTER_OPTIONS](state, payload) {
......
......@@ -9,13 +9,13 @@ export default () => ({
{
name: 'All',
id: 'all',
selected: true,
},
...Object.entries(SEVERITIES).map(severity => {
const [id, name] = severity;
return { id, name };
}),
],
selection: new Set(['all']),
},
{
name: 'Report type',
......@@ -24,13 +24,13 @@ export default () => ({
{
name: 'All',
id: 'all',
selected: true,
},
...Object.entries(REPORT_TYPES).map(type => {
const [id, name] = type;
return { id, name };
}),
],
selection: new Set(['all']),
},
{
name: 'Project',
......@@ -39,9 +39,9 @@ export default () => ({
{
name: 'All',
id: 'all',
selected: true,
},
],
selection: new Set(['all']),
},
],
});
......@@ -14,6 +14,9 @@ export const setVulnerabilitiesCountEndpoint = ({ commit }, endpoint) => {
};
export const fetchVulnerabilitiesCount = ({ state, dispatch }, params = {}) => {
if (!state.vulnerabilitiesCountEndpoint) {
return;
}
dispatch('requestVulnerabilitiesCount');
axios({
......@@ -43,6 +46,9 @@ export const receiveVulnerabilitiesCountError = ({ commit }) => {
};
export const fetchVulnerabilities = ({ state, dispatch }, params = {}) => {
if (!state.vulnerabilitiesEndpoint) {
return;
}
dispatch('requestVulnerabilities');
axios({
......@@ -208,6 +214,9 @@ export const setVulnerabilitiesHistoryEndpoint = ({ commit }, endpoint) => {
};
export const fetchVulnerabilitiesHistory = ({ state, dispatch }, params = {}) => {
if (!state.vulnerabilitiesHistoryEndpoint) {
return;
}
dispatch('requestVulnerabilitiesHistory');
axios({
......
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
// Unfortunately Vue Router doesn't work without at least a fake component
// If you do only data handling
const EmptyRouterComponent = {
render(createElement) {
return createElement('div');
},
};
const routes = [{ path: '/', name: 'dashboard', component: EmptyRouterComponent }];
const router = new VueRouter({
mode: 'history',
base: window.location.pathname,
routes,
});
export default router;
---
title: Persist Group Level Security Dashboard state in URL
merge_request: 9108
author:
type: added
import Vue from 'vue';
import MockAdapater from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import component from 'ee/security_dashboard/components/security_dashboard_table.vue';
import createStore from 'ee/security_dashboard/store';
import { TEST_HOST } from 'spec/test_constants';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import waitForPromises from 'spec/helpers/wait_for_promises';
import {
RECEIVE_VULNERABILITIES_ERROR,
RECEIVE_VULNERABILITIES_SUCCESS,
REQUEST_VULNERABILITIES,
} from 'ee/security_dashboard/store/modules/vulnerabilities/mutation_types';
import { resetStore } from '../helpers';
import mockDataVulnerabilities from '../store/vulnerabilities/data/mock_data_vulnerabilities.json';
......@@ -19,11 +22,9 @@ describe('Security Dashboard Table', () => {
emptyStateSvgPath: TEST_HOST,
};
let store;
let mock;
let vm;
beforeEach(() => {
mock = new MockAdapater(axios);
store = createStore();
store.state.vulnerabilities.vulnerabilitiesEndpoint = vulnerabilitiesEndpoint;
});
......@@ -31,12 +32,11 @@ describe('Security Dashboard Table', () => {
afterEach(() => {
resetStore(store);
vm.$destroy();
mock.restore();
});
describe('while loading', () => {
beforeEach(() => {
store.dispatch('vulnerabilities/requestVulnerabilities');
store.commit(`vulnerabilities/${REQUEST_VULNERABILITIES}`);
vm = mountComponentWithStore(Component, { store, props });
});
......@@ -47,60 +47,42 @@ describe('Security Dashboard Table', () => {
describe('with a list of vulnerabilities', () => {
beforeEach(() => {
mock.onGet(vulnerabilitiesEndpoint).replyOnce(200, mockDataVulnerabilities);
store.commit(`vulnerabilities/${RECEIVE_VULNERABILITIES_SUCCESS}`, {
vulnerabilities: mockDataVulnerabilities,
});
vm = mountComponentWithStore(Component, { store, props });
});
it('should render a row for each vulnerability', done => {
waitForPromises()
.then(() => {
expect(vm.$el.querySelectorAll('.vulnerabilities-row')).toHaveLength(
mockDataVulnerabilities.length,
);
done();
})
.catch(done.fail);
it('should render a row for each vulnerability', () => {
expect(vm.$el.querySelectorAll('.vulnerabilities-row')).toHaveLength(
mockDataVulnerabilities.length,
);
});
});
describe('with no vulnerabilties', () => {
beforeEach(() => {
mock.onGet(vulnerabilitiesEndpoint).replyOnce(200, []);
store.commit(`vulnerabilities/${RECEIVE_VULNERABILITIES_SUCCESS}`, { vulnerabilities: [] });
vm = mountComponentWithStore(Component, { store, props });
});
it('should render the empty state', done => {
waitForPromises()
.then(() => {
expect(vm.$el.querySelector('.empty-state')).not.toBeNull();
done();
})
.catch(done.fail);
it('should render the empty state', () => {
expect(vm.$el.querySelector('.empty-state')).not.toBeNull();
});
});
describe('on error', () => {
beforeEach(() => {
mock.onGet(vulnerabilitiesEndpoint).replyOnce(404, []);
store.commit(`vulnerabilities/${RECEIVE_VULNERABILITIES_ERROR}`);
vm = mountComponentWithStore(Component, { store, props });
});
it('should not render the empty state', done => {
waitForPromises()
.then(() => {
expect(vm.$el.querySelector('.empty-state')).toBeNull();
done();
})
.catch(done.fail);
it('should not render the empty state', () => {
expect(vm.$el.querySelector('.empty-state')).toBeNull();
});
it('should render the error alert', done => {
waitForPromises()
.then(() => {
expect(vm.$el.querySelector('.flash-alert')).not.toBeNull();
done();
})
.catch(done.fail);
it('should render the error alert', () => {
expect(vm.$el.querySelector('.flash-alert')).not.toBeNull();
});
});
});
......@@ -46,4 +46,25 @@ describe('filters actions', () => {
);
});
});
describe('setAllFilters', () => {
it('should commit the SET_ALL_FILTERS mutuation', done => {
const state = createState();
const payload = { project_id: ['12', '15'] };
testAction(
actions.setAllFilters,
payload,
state,
[
{
type: types.SET_ALL_FILTERS,
payload,
},
],
[],
done,
);
});
});
});
......@@ -6,15 +6,10 @@ describe('filters module getters', () => {
const getFilter = filterId => getters.getFilter(state)(filterId);
const getSelectedOptions = filterId =>
getters.getSelectedOptions(state, { getFilter })(filterId);
const getSelectedOptionIds = filterId =>
getters.getSelectedOptionIds(state, { getSelectedOptions })(filterId);
const getFilterIds = getters.getFilterIds(state);
return {
getFilter,
getSelectedOptions,
getSelectedOptionIds,
getFilterIds,
};
};
let state;
......@@ -49,7 +44,8 @@ describe('filters module getters', () => {
filters: [
{
id: 'severity',
options: [{ id: 'critical', selected: true }, { id: 'high', selected: true }],
options: [{ id: 'critical' }, { id: 'high' }],
selection: new Set(['critical', 'high']),
},
],
};
......@@ -60,20 +56,6 @@ describe('filters module getters', () => {
});
});
describe('getSelectedOptionIds', () => {
it('should return "one" as the selcted dummy ID', () => {
const dummyFilter = {
id: 'dummy',
options: [{ id: 'one', selected: true }, { id: 'anotherone', selected: false }],
};
state.filters.push(dummyFilter);
const selectedOptionIds = getters.getSelectedOptionIds(state, mockedGetters(state))('dummy');
expect(selectedOptionIds).toHaveLength(1);
expect(selectedOptionIds[0]).toEqual('one');
});
});
describe('getSelectedOptionNames', () => {
it('should return "All" as the selected option', () => {
const selectedOptionNames = getters.getSelectedOptionNames(state, mockedGetters(state))(
......@@ -88,7 +70,8 @@ describe('filters module getters', () => {
filters: [
{
id: 'severity',
options: [{ name: 'Critical', selected: true }, { name: 'High', selected: true }],
options: [{ name: 'Critical', id: 1 }, { name: 'High', id: 2 }],
selection: new Set([1, 2]),
},
],
};
......@@ -110,7 +93,8 @@ describe('filters module getters', () => {
it('should return multiple dummy filters"', () => {
const dummyFilter = {
id: 'dummy',
options: [{ id: 'one', selected: true }, { id: 'anotherone', selected: true }],
options: [{ id: 'one' }, { id: 'two' }],
selection: new Set(['one', 'two']),
};
state.filters.push(dummyFilter);
const activeFilters = getters.activeFilters(state, mockedGetters(state));
......
......@@ -3,17 +3,19 @@ import * as types from 'ee/security_dashboard/store/modules/filters/mutation_typ
import mutations from 'ee/security_dashboard/store/modules/filters/mutations';
describe('filters module mutations', () => {
describe('SET_FILTER', () => {
let state;
let severityFilter;
let criticalOption;
let highOption;
let state;
let severityFilter;
let criticalOption;
let highOption;
beforeEach(() => {
state = createState();
[severityFilter] = state.filters;
[, criticalOption, highOption] = severityFilter.options;
beforeEach(() => {
state = createState();
[severityFilter] = state.filters;
[, criticalOption, highOption] = severityFilter.options;
});
describe('SET_FILTER', () => {
beforeEach(() => {
mutations[types.SET_FILTER](state, {
filterId: severityFilter.id,
optionId: criticalOption.id,
......@@ -21,11 +23,16 @@ describe('filters module mutations', () => {
});
it('should make critical the selected option', () => {
expect(state.filters[0].options[1].selected).toEqual(true);
expect(state.filters[0].selection).toEqual(new Set(['critical']));
});
it('should remove ALL as the selected option', () => {
expect(state.filters[0].options[0].selected).toEqual(false);
it('should set to `all` if no option is selected', () => {
mutations[types.SET_FILTER](state, {
filterId: severityFilter.id,
optionId: criticalOption.id,
});
expect(state.filters[0].selection).toEqual(new Set(['all']));
});
describe('on subsequent changes', () => {
......@@ -35,27 +42,62 @@ describe('filters module mutations', () => {
optionId: highOption.id,
});
expect(state.filters[0].options[1].selected).toEqual(true);
expect(state.filters[0].options[2].selected).toEqual(true);
expect(state.filters[0].selection).toEqual(new Set(['high', 'critical']));
});
});
});
describe('SET_ALL_FILTERS', () => {
it('should set options if they are a single string', () => {
mutations[types.SET_ALL_FILTERS](state, { [severityFilter.id]: criticalOption.id });
const expected = new Set([criticalOption.id]);
expect(state.filters[0].selection).toEqual(expected);
});
it('should set options if they are given as an array', () => {
mutations[types.SET_ALL_FILTERS](state, {
[severityFilter.id]: [criticalOption.id, highOption.id],
});
const expected = new Set([criticalOption.id, highOption.id]);
expect(state.filters[0].selection).toEqual(expected);
});
it('should set options to `all` if no payload is given', () => {
mutations[types.SET_ALL_FILTERS](state);
const expected = new Set(['all']);
state.filters.forEach(filter => {
expect(filter.selection).toEqual(expected);
});
});
it('should set options to `all` if payload contains an empty array', () => {
mutations[types.SET_ALL_FILTERS](state, {
[severityFilter.id]: [],
});
const expected = new Set(['all']);
expect(state.filters[0].selection).toEqual(expected);
});
});
describe('SET_FILTER_OPTIONS', () => {
let state;
let firstFilter;
const options = [{ id: 0, name: 'c' }, { id: 3, name: 'c' }];
beforeEach(() => {
state = createState();
[firstFilter] = state.filters;
const filterId = firstFilter.id;
const filterId = severityFilter.id;
mutations[types.SET_FILTER_OPTIONS](state, { filterId, options });
});
it('should add all the options to the type filter', () => {
expect(firstFilter.options).toEqual(options);
expect(severityFilter.options).toEqual(options);
});
});
});
import createStore from 'ee/security_dashboard/store/index';
import * as projectsMutationTypes from 'ee/security_dashboard/store/modules/projects/mutation_types';
import * as filtersMutationTypes from 'ee/security_dashboard/store/modules/filters/mutation_types';
import * as vulnerabilitiesMutationTypes from 'ee/security_dashboard/store/modules/vulnerabilities/mutation_types';
describe('moderator', () => {
let store;
beforeEach(() => {
store = createStore();
});
it('sets project filter options after projects have been received', () => {
spyOn(store, 'dispatch');
store.commit(`projects/${projectsMutationTypes.RECEIVE_PROJECTS_SUCCESS}`, {
projects: [{ name: 'foo', id: 1, otherProp: 'foobar' }],
});
expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledWith(
'filters/setFilterOptions',
Object({
filterId: 'project_id',
options: [{ name: 'All', id: 'all' }, { name: 'foo', id: '1' }],
}),
);
});
it('triggers fetching vulnerabilities after one filter changes', () => {
spyOn(store, 'dispatch');
const activeFilters = store.getters['filters/activeFilters'];
store.commit(`filters/${filtersMutationTypes.SET_FILTER}`, {});
expect(store.dispatch).toHaveBeenCalledTimes(3);
expect(store.dispatch).toHaveBeenCalledWith(
'vulnerabilities/fetchVulnerabilities',
activeFilters,
);
expect(store.dispatch).toHaveBeenCalledWith(
'vulnerabilities/fetchVulnerabilitiesCount',
activeFilters,
);
expect(store.dispatch).toHaveBeenCalledWith(
'vulnerabilities/fetchVulnerabilitiesHistory',
activeFilters,
);
});
it('triggers fetching vulnerabilities after filters change', () => {
spyOn(store, 'dispatch');
const activeFilters = store.getters['filters/activeFilters'];
store.commit(`filters/${filtersMutationTypes.SET_ALL_FILTERS}`, {});
expect(store.dispatch).toHaveBeenCalledTimes(3);
expect(store.dispatch).toHaveBeenCalledWith(
'vulnerabilities/fetchVulnerabilities',
activeFilters,
);
expect(store.dispatch).toHaveBeenCalledWith(
'vulnerabilities/fetchVulnerabilitiesCount',
activeFilters,
);
expect(store.dispatch).toHaveBeenCalledWith(
'vulnerabilities/fetchVulnerabilitiesHistory',
activeFilters,
);
});
describe('routing', () => {
it('updates store after URL changes', () => {
const query = { example: ['test'] };
spyOn(store, 'dispatch');
store.$router.push({ name: 'dashboard', query });
expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledWith(`filters/setAllFilters`, query);
});
it("doesn't update the store if the URL update originated from the moderator", () => {
const query = { example: ['test'] };
spyOn(store, 'commit');
store.$router.push({ name: 'dashboard', query, params: { updatedFromState: true } });
expect(store.commit).toHaveBeenCalledTimes(0);
});
it('it updates the route after a successful vulnerability retrieval', () => {
const activeFilters = store.getters['filters/activeFilters'];
spyOn(store.$router, 'push');
store.commit(
`vulnerabilities/${vulnerabilitiesMutationTypes.RECEIVE_VULNERABILITIES_SUCCESS}`,
{},
);
expect(store.$router.push).toHaveBeenCalledTimes(1);
expect(store.$router.push).toHaveBeenCalledWith({
name: 'dashboard',
query: activeFilters,
params: { updatedFromState: true },
});
});
});
});
......@@ -11,7 +11,7 @@ import mockDataVulnerabilities from './data/mock_data_vulnerabilities.json';
import mockDataVulnerabilitiesCount from './data/mock_data_vulnerabilities_count.json';
import mockDataVulnerabilitiesHistory from './data/mock_data_vulnerabilities_history.json';
describe('vulnerabiliites count actions', () => {
describe('vulnerabilities count actions', () => {
const data = mockDataVulnerabilitiesCount;
const params = { filters: { type: ['sast'] } };
const filteredData = mockDataVulnerabilitiesCount.sast;
......@@ -37,7 +37,7 @@ describe('vulnerabiliites count actions', () => {
});
});
describe('fetchVulnerabilitesCount', () => {
describe('fetchVulnerabilitiesCount', () => {
let mock;
const state = initialState;
......@@ -112,7 +112,7 @@ describe('vulnerabiliites count actions', () => {
});
});
describe('requestVulnerabilitesCount', () => {
describe('requestVulnerabilitiesCount', () => {
it('should commit the request mutation', done => {
const state = initialState;
......@@ -127,7 +127,7 @@ describe('vulnerabiliites count actions', () => {
});
});
describe('receiveVulnerabilitesCountSuccess', () => {
describe('receiveVulnerabilitiesCountSuccess', () => {
it('should commit the success mutation', done => {
const state = initialState;
......@@ -142,7 +142,7 @@ describe('vulnerabiliites count actions', () => {
});
});
describe('receivetVulnerabilitesCountError', () => {
describe('receiveVulnerabilitiesCountError', () => {
it('should commit the error mutation', done => {
const state = initialState;
......@@ -708,12 +708,12 @@ describe('vulnerabilities history actions', () => {
});
});
describe('fetchVulnerabilitesTimeline', () => {
describe('fetchVulnerabilitiesTimeline', () => {
let mock;
const state = initialState;
beforeEach(() => {
state.vulnerabilitiesCountEndpoint = `${TEST_HOST}/vulnerabilitIES_HISTORY.json`;
state.vulnerabilitiesHistoryEndpoint = `${TEST_HOST}/vulnerabilitIES_HISTORY.json`;
mock = new MockAdapter(axios);
});
......@@ -786,7 +786,7 @@ describe('vulnerabilities history actions', () => {
});
});
describe('requestVulnerabilitesTimeline', () => {
describe('requestVulnerabilitiesTimeline', () => {
it('should commit the request mutation', done => {
const state = initialState;
......@@ -801,7 +801,7 @@ describe('vulnerabilities history actions', () => {
});
});
describe('receiveVulnerabilitesTimelineSuccess', () => {
describe('receiveVulnerabilitiesTimelineSuccess', () => {
it('should commit the success mutation', done => {
const state = initialState;
......@@ -816,7 +816,7 @@ describe('vulnerabilities history actions', () => {
});
});
describe('receivetVulnerabilitesTimelineError', () => {
describe('receiveVulnerabilitiesTimelineError', () => {
it('should commit the error mutation', done => {
const state = initialState;
......
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