Commit 9a87720a authored by Michael Lunøe's avatar Michael Lunøe Committed by Sarah Groff Hennigh-Palermo

Refactor(Productivity Analytics): refactor methods

@vue/test-utils 1.x deprecated use of methods.
This MR removes usage of this option from
productivity analytics tests

See the following for details:
https://gitlab.com/groups/gitlab-org/-/epics/3856
https://gitlab.com/groups/gitlab-org/-/epics/4255
parent 63db21c1
......@@ -10,8 +10,7 @@ import table from './modules/table/index';
Vue.use(Vuex);
const createStore = () =>
new Vuex.Store({
export const getStoreConfig = () => ({
state: state(),
getters,
actions,
......@@ -21,6 +20,6 @@ const createStore = () =>
charts,
table,
},
});
});
export default createStore();
export default () => new Vuex.Store(getStoreConfig());
......@@ -5,7 +5,7 @@ import MockAdapter from 'axios-mock-adapter';
import ProductivityApp from 'ee/analytics/productivity_analytics/components/app.vue';
import Scatterplot from 'ee/analytics/shared/components/scatterplot.vue';
import MergeRequestTable from 'ee/analytics/productivity_analytics/components/mr_table.vue';
import store from 'ee/analytics/productivity_analytics/store';
import { getStoreConfig } from 'ee/analytics/productivity_analytics/store';
import { chartKeys } from 'ee/analytics/productivity_analytics/constants';
import { TEST_HOST } from 'helpers/test_constants';
import {
......@@ -28,45 +28,71 @@ localVue.use(Vuex);
describe('ProductivityApp component', () => {
let wrapper;
let mock;
let mockStore;
const propsData = {
emptyStateSvgPath: TEST_HOST,
noAccessSvgPath: TEST_HOST,
};
const actionSpies = {
const chartsActionSpies = {
resetMainChartSelection: jest.fn(),
};
const tableActionSpies = {
setSortField: jest.fn(),
setPage: jest.fn(),
toggleSortOrder: jest.fn(),
setColumnMetric: jest.fn(),
resetMainChartSelection: jest.fn(),
};
const mainChartData = { 1: 2, 2: 3 };
const createComponent = ({ props = {}, options = {}, scatterplotEnabled = true } = {}) => {
const {
modules: { charts, table, ...modules },
...storeConfig
} = getStoreConfig();
mockStore = new Vuex.Store({
...storeConfig,
modules: {
charts: {
...charts,
actions: {
...charts.actions,
...chartsActionSpies,
},
},
table: {
...table,
actions: {
...table.actions,
...tableActionSpies,
},
},
...modules,
},
});
wrapper = shallowMount(ProductivityApp, {
localVue,
store,
store: mockStore,
mixins: [UrlSyncMixin],
propsData: {
...propsData,
...props,
},
methods: {
...actionSpies,
},
provide: {
glFeatures: { productivityAnalyticsScatterplotEnabled: scatterplotEnabled },
},
...options,
});
wrapper.vm.$store.dispatch('setEndpoint', TEST_HOST);
mockStore.dispatch('setEndpoint', TEST_HOST);
};
beforeEach(() => {
mock = new MockAdapter(axios);
createComponent();
});
afterEach(() => {
......@@ -99,26 +125,26 @@ describe('ProductivityApp component', () => {
describe('with a group being selected', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('filters/setInitialData', {
mockStore.dispatch('filters/setInitialData', {
skipFetch: true,
data: {
mergedAfter: new Date('2019-09-01'),
mergedBefore: new Date('2019-09-02'),
},
});
wrapper.vm.$store.dispatch('filters/setGroupNamespace', 'gitlab-org');
mock.onGet(wrapper.vm.$store.state.endpoint).replyOnce(200);
mockStore.dispatch('filters/setGroupNamespace', 'gitlab-org');
mock.onGet(mockStore.state.endpoint).replyOnce(200);
});
describe('user has no access to the group', () => {
beforeEach(() => {
createComponent();
const error = { response: { status: 403 } };
wrapper.vm.$store.dispatch('charts/receiveChartDataError', {
mockStore.dispatch('charts/receiveChartDataError', {
chartKey: chartKeys.main,
error,
});
wrapper.vm.$store.state.charts.charts[chartKeys.main].errorCode = 403;
mockStore.state.charts.charts[chartKeys.main].errorCode = 403;
});
it('renders the no access illustration', () => {
......@@ -131,7 +157,7 @@ describe('ProductivityApp component', () => {
describe('user has access to the group', () => {
beforeEach(() => {
wrapper.vm.$store.state.charts.charts[chartKeys.main].errorCode = null;
mockStore.state.charts.charts[chartKeys.main].errorCode = null;
return wrapper.vm.$nextTick();
});
......@@ -139,7 +165,7 @@ describe('ProductivityApp component', () => {
describe('when the main chart is loading', () => {
beforeEach(() => {
createComponent();
wrapper.vm.$store.dispatch('charts/requestChartData', chartKeys.main);
mockStore.dispatch('charts/requestChartData', chartKeys.main);
});
it('renders a metric chart component for the main chart', () => {
......@@ -164,7 +190,7 @@ describe('ProductivityApp component', () => {
describe('and has data', () => {
beforeEach(() => {
createComponent();
wrapper.vm.$store.dispatch('charts/receiveChartDataSuccess', {
mockStore.dispatch('charts/receiveChartDataSuccess', {
chartKey: chartKeys.main,
data: mainChartData,
});
......@@ -180,7 +206,7 @@ describe('ProductivityApp component', () => {
describe('when an item on the chart is clicked', () => {
beforeEach(() => {
jest.spyOn(store, 'dispatch');
jest.spyOn(mockStore, 'dispatch');
const data = {
chart: null,
......@@ -197,7 +223,7 @@ describe('ProductivityApp component', () => {
});
it('dispatches updateSelectedItems action', () => {
expect(store.dispatch).toHaveBeenCalledWith('charts/updateSelectedItems', {
expect(mockStore.dispatch).toHaveBeenCalledWith('charts/updateSelectedItems', {
chartKey: chartKeys.main,
item: 0,
});
......@@ -206,7 +232,7 @@ describe('ProductivityApp component', () => {
describe('when the main chart has selected items', () => {
beforeEach(() => {
wrapper.vm.$store.state.charts.charts[chartKeys.main].selected = [1];
mockStore.state.charts.charts[chartKeys.main].selected = [1];
});
it('renders the "Clear chart data" button', () => {
......@@ -216,7 +242,7 @@ describe('ProductivityApp component', () => {
it('dispatches resetMainChartSelection action when the user clicks on the "Clear chart data" button', () => {
findClearFilterButton().vm.$emit('click');
expect(actionSpies.resetMainChartSelection).toHaveBeenCalled();
expect(chartsActionSpies.resetMainChartSelection).toHaveBeenCalled();
});
});
......@@ -228,7 +254,7 @@ describe('ProductivityApp component', () => {
describe('when chart finished loading', () => {
describe('and the chart has data', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('charts/receiveChartDataSuccess', {
mockStore.dispatch('charts/receiveChartDataSuccess', {
chartKey: chartKeys.timeBasedHistogram,
data: { 1: 2, 2: 3 },
});
......@@ -244,12 +270,12 @@ describe('ProductivityApp component', () => {
describe('when the user changes the metric', () => {
beforeEach(() => {
jest.spyOn(store, 'dispatch');
jest.spyOn(mockStore, 'dispatch');
findTimeBasedMetricChart().vm.$emit('metricTypeChange', 'time_to_merge');
});
it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => {
expect(store.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
expect(mockStore.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
metricType: 'time_to_merge',
chartKey: chartKeys.timeBasedHistogram,
});
......@@ -267,7 +293,7 @@ describe('ProductivityApp component', () => {
describe('when chart finished loading', () => {
describe('and the chart has data', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('charts/receiveChartDataSuccess', {
mockStore.dispatch('charts/receiveChartDataSuccess', {
chartKey: chartKeys.commitBasedHistogram,
data: { 1: 2, 2: 3 },
});
......@@ -283,13 +309,13 @@ describe('ProductivityApp component', () => {
describe('when the user changes the metric', () => {
beforeEach(() => {
jest.spyOn(store, 'dispatch');
jest.spyOn(mockStore, 'dispatch');
findCommitBasedMetricChart().vm.$emit('metricTypeChange', 'loc_per_commit');
return wrapper.vm.$nextTick();
});
it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => {
expect(store.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
expect(mockStore.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
metricType: 'loc_per_commit',
chartKey: chartKeys.commitBasedHistogram,
});
......@@ -317,7 +343,7 @@ describe('ProductivityApp component', () => {
describe('when chart finished loading', () => {
describe('and the chart has data', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('charts/receiveChartDataSuccess', {
mockStore.dispatch('charts/receiveChartDataSuccess', {
chartKey: chartKeys.scatterplot,
data: {
1: { metric: 2, merged_at: '2019-09-01T07:06:23.193Z' },
......@@ -340,13 +366,13 @@ describe('ProductivityApp component', () => {
describe('when the user changes the metric', () => {
beforeEach(() => {
jest.spyOn(store, 'dispatch');
jest.spyOn(mockStore, 'dispatch');
findScatterplotMetricChart().vm.$emit('metricTypeChange', 'loc_per_commit');
return wrapper.vm.$nextTick();
});
it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => {
expect(store.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
expect(mockStore.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
metricType: 'loc_per_commit',
chartKey: chartKeys.scatterplot,
});
......@@ -379,7 +405,7 @@ describe('ProductivityApp component', () => {
describe('MR table', () => {
describe('when table is loading', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('table/requestMergeRequests');
mockStore.dispatch('table/requestMergeRequests');
});
it('renders a loading indicator', () => {
......@@ -394,7 +420,7 @@ describe('ProductivityApp component', () => {
describe('when table finished loading', () => {
describe('and the table has data', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('table/receiveMergeRequestsSuccess', {
mockStore.dispatch('table/receiveMergeRequestsSuccess', {
headers: {},
data: [{ id: 1, title: 'This is a test MR' }],
});
......@@ -412,17 +438,17 @@ describe('ProductivityApp component', () => {
).toBe(false);
});
it('should change the column metric', () => {
it('should change the column metric', async () => {
findMrTable().vm.$emit('columnMetricChange', 'time_to_first_comment');
expect(actionSpies.setColumnMetric).toHaveBeenCalledWith(
'time_to_first_comment',
);
const { calls } = tableActionSpies.setColumnMetric.mock;
expect(calls[calls.length - 1][1]).toBe('time_to_first_comment');
});
it('should change the page', () => {
const page = 2;
findMrTable().vm.$emit('pageChange', page);
expect(actionSpies.setPage).toHaveBeenCalledWith(page);
const { calls } = tableActionSpies.setPage.mock;
expect(calls[calls.length - 1][1]).toBe(page);
});
describe('sort controls', () => {
......@@ -437,19 +463,19 @@ describe('ProductivityApp component', () => {
.at(0)
.vm.$emit('click');
expect(actionSpies.setSortField).toHaveBeenCalled();
expect(tableActionSpies.setSortField).toHaveBeenCalled();
});
it('should toggle the sort order', () => {
findSortOrderToggle().vm.$emit('click');
expect(actionSpies.toggleSortOrder).toHaveBeenCalled();
expect(tableActionSpies.toggleSortOrder).toHaveBeenCalled();
});
});
});
describe("and the table doesn't have any data", () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('table/receiveMergeRequestsSuccess', {
mockStore.dispatch('table/receiveMergeRequestsSuccess', {
headers: {},
data: [],
});
......@@ -479,7 +505,7 @@ describe('ProductivityApp component', () => {
describe('and has no data', () => {
beforeEach(() => {
createComponent();
wrapper.vm.$store.dispatch('charts/receiveChartDataSuccess', {
mockStore.dispatch('charts/receiveChartDataSuccess', {
chartKey: chartKeys.main,
data: {},
});
......@@ -512,7 +538,7 @@ describe('ProductivityApp component', () => {
},
},
});
wrapper.vm.$store.dispatch('charts/receiveChartDataError', {
mockStore.dispatch('charts/receiveChartDataError', {
chartKey: chartKeys.main,
error: { response: { status: httpStatusCodes.INTERNAL_SERVER_ERROR } },
});
......@@ -570,7 +596,7 @@ describe('ProductivityApp component', () => {
urlUtils.setUrlParams = jest.fn();
createComponent();
wrapper.vm.$store.dispatch('filters/setInitialData', {
mockStore.dispatch('filters/setInitialData', {
skipFetch: true,
data: {
mergedAfter: new Date('2019-09-01'),
......@@ -589,7 +615,7 @@ describe('ProductivityApp component', () => {
urlUtils.setUrlParams = jest.fn();
createComponent({ props: { hideGroupDropDown: true } });
wrapper.vm.$store.dispatch('filters/setInitialData', {
mockStore.dispatch('filters/setInitialData', {
skipFetch: true,
data: {
mergedAfter: new Date('2019-09-01'),
......@@ -597,7 +623,7 @@ describe('ProductivityApp component', () => {
},
});
wrapper.vm.$store.dispatch('filters/setGroupNamespace', 'earth-special-forces');
mockStore.dispatch('filters/setGroupNamespace', 'earth-special-forces');
});
it('does not set the group_id', () => {
......@@ -609,7 +635,7 @@ describe('ProductivityApp component', () => {
describe('with a group selected', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('filters/setGroupNamespace', 'earth-special-forces');
mockStore.dispatch('filters/setGroupNamespace', 'earth-special-forces');
});
it('sets the group_id', () => {
......@@ -622,7 +648,7 @@ describe('ProductivityApp component', () => {
describe('with a project selected', () => {
beforeEach(() => {
wrapper.vm.$store.dispatch('filters/setProjectPath', 'earth-special-forces/frieza-saga');
mockStore.dispatch('filters/setProjectPath', 'earth-special-forces/frieza-saga');
});
it('sets the project_id', () => {
......@@ -640,7 +666,7 @@ describe('ProductivityApp component', () => {
${'label_name'} | ${'label_name[]'} | ${['who-will-win']}
`('with the $paramKey filter set', ({ paramKey, resultKey, value }) => {
beforeEach(() => {
wrapper.vm.$store.dispatch('filters/setFilters', {
mockStore.dispatch('filters/setFilters', {
...defaultFilters,
[paramKey]: value,
});
......
......@@ -3,7 +3,7 @@ import Vuex from 'vuex';
import FilterDropdowns from 'ee/analytics/productivity_analytics/components/filter_dropdowns.vue';
import GroupsDropdownFilter from 'ee/analytics/shared/components/groups_dropdown_filter.vue';
import ProjectsDropdownFilter from 'ee/analytics/shared/components/projects_dropdown_filter.vue';
import store from 'ee/analytics/productivity_analytics/store';
import { getStoreConfig } from 'ee/analytics/productivity_analytics/store';
import resetStore from '../helpers';
const localVue = createLocalVue();
......@@ -11,8 +11,9 @@ localVue.use(Vuex);
describe('FilterDropdowns component', () => {
let wrapper;
let mockStore;
const actionSpies = {
const filtersActionSpies = {
setGroupNamespace: jest.fn(),
setProjectPath: jest.fn(),
};
......@@ -23,19 +24,33 @@ describe('FilterDropdowns component', () => {
const projectId = 10;
beforeEach(() => {
const {
modules: { filters, ...modules },
...storeConfig
} = getStoreConfig();
mockStore = new Vuex.Store({
...storeConfig,
modules: {
filters: {
...filters,
actions: {
...filters.actions,
...filtersActionSpies,
},
},
...modules,
},
});
wrapper = shallowMount(FilterDropdowns, {
localVue,
store,
store: mockStore,
propsData: {},
methods: {
...actionSpies,
},
});
});
afterEach(() => {
wrapper.destroy();
resetStore(store);
resetStore(mockStore);
});
describe('template', () => {
......@@ -72,7 +87,8 @@ describe('FilterDropdowns component', () => {
it('updates the groupId and invokes setGroupNamespace action', () => {
expect(wrapper.vm.groupId).toBe(1);
expect(actionSpies.setGroupNamespace).toHaveBeenCalledWith(groupNamespace);
const { calls } = filtersActionSpies.setGroupNamespace.mock;
expect(calls[calls.length - 1][1]).toBe(groupNamespace);
});
it('emits the "groupSelected" event', () => {
......@@ -90,12 +106,13 @@ describe('FilterDropdowns component', () => {
describe('when the list of selected projects is not empty', () => {
beforeEach(() => {
store.state.filters.groupNamespace = groupNamespace;
mockStore.state.filters.groupNamespace = groupNamespace;
wrapper.vm.onProjectsSelected([{ id: projectId, path_with_namespace: `${projectPath}` }]);
});
it('invokes setProjectPath action', () => {
expect(actionSpies.setProjectPath).toHaveBeenCalledWith(projectPath);
const { calls } = filtersActionSpies.setProjectPath.mock;
expect(calls[calls.length - 1][1]).toBe(projectPath);
});
it('emits the "projectSelected" event', () => {
......@@ -110,12 +127,13 @@ describe('FilterDropdowns component', () => {
describe('when the list of selected projects is empty', () => {
beforeEach(() => {
store.state.filters.groupNamespace = groupNamespace;
mockStore.state.filters.groupNamespace = groupNamespace;
wrapper.vm.onProjectsSelected([]);
});
it('invokes setProjectPath action with null', () => {
expect(actionSpies.setProjectPath).toHaveBeenCalledWith(null);
const { calls } = filtersActionSpies.setProjectPath.mock;
expect(calls[calls.length - 1][1]).toBe(null);
});
it('emits the "projectSelected" event', () => {
......
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