diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-19 09:08:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-19 09:08:42 +0000 |
commit | b76ae638462ab0f673e5915986070518dd3f9ad3 (patch) | |
tree | bdab0533383b52873be0ec0eb4d3c66598ff8b91 /spec/frontend/cycle_analytics/store | |
parent | 434373eabe7b4be9593d18a585fb763f1e5f1a6f (diff) | |
download | gitlab-ce-b76ae638462ab0f673e5915986070518dd3f9ad3.tar.gz |
Add latest changes from gitlab-org/gitlab@14-2-stable-eev14.2.0-rc42
Diffstat (limited to 'spec/frontend/cycle_analytics/store')
-rw-r--r-- | spec/frontend/cycle_analytics/store/actions_spec.js | 173 | ||||
-rw-r--r-- | spec/frontend/cycle_analytics/store/getters_spec.js | 3 | ||||
-rw-r--r-- | spec/frontend/cycle_analytics/store/mutations_spec.js | 104 |
3 files changed, 166 insertions, 114 deletions
diff --git a/spec/frontend/cycle_analytics/store/actions_spec.js b/spec/frontend/cycle_analytics/store/actions_spec.js index 8a8dd374f8e..915a828ff19 100644 --- a/spec/frontend/cycle_analytics/store/actions_spec.js +++ b/spec/frontend/cycle_analytics/store/actions_spec.js @@ -2,39 +2,23 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; import * as actions from '~/cycle_analytics/store/actions'; +import * as getters from '~/cycle_analytics/store/getters'; import httpStatusCodes from '~/lib/utils/http_status'; import { allowedStages, selectedStage, selectedValueStream } from '../mock_data'; const mockRequestPath = 'some/cool/path'; const mockFullPath = '/namespace/-/analytics/value_stream_analytics/value_streams'; const mockStartDate = 30; -const mockRequestedDataActions = ['fetchValueStreams', 'fetchCycleAnalyticsData']; -const mockInitializeActionCommit = { - payload: { requestPath: mockRequestPath }, - type: 'INITIALIZE_VSA', -}; +const mockEndpoints = { fullPath: mockFullPath, requestPath: mockRequestPath }; const mockSetDateActionCommit = { payload: { startDate: mockStartDate }, type: 'SET_DATE_RANGE' }; -const mockRequestedDataMutations = [ - { - payload: true, - type: 'SET_LOADING', - }, - { - payload: false, - type: 'SET_LOADING', - }, -]; - -const features = { - cycleAnalyticsForGroups: true, -}; + +const defaultState = { ...getters, selectedValueStream }; describe('Project Value Stream Analytics actions', () => { let state; let mock; beforeEach(() => { - state = {}; mock = new MockAdapter(axios); }); @@ -45,28 +29,62 @@ describe('Project Value Stream Analytics actions', () => { const mutationTypes = (arr) => arr.map(({ type }) => type); + const mockFetchStageDataActions = [ + { type: 'setLoading', payload: true }, + { type: 'fetchCycleAnalyticsData' }, + { type: 'fetchStageData' }, + { type: 'fetchStageMedians' }, + { type: 'setLoading', payload: false }, + ]; + describe.each` - action | payload | expectedActions | expectedMutations - ${'initializeVsa'} | ${{ requestPath: mockRequestPath }} | ${mockRequestedDataActions} | ${[mockInitializeActionCommit, ...mockRequestedDataMutations]} - ${'setDateRange'} | ${{ startDate: mockStartDate }} | ${mockRequestedDataActions} | ${[mockSetDateActionCommit, ...mockRequestedDataMutations]} - ${'setSelectedStage'} | ${{ selectedStage }} | ${['fetchStageData']} | ${[{ type: 'SET_SELECTED_STAGE', payload: { selectedStage } }]} - ${'setSelectedValueStream'} | ${{ selectedValueStream }} | ${['fetchValueStreamStages']} | ${[{ type: 'SET_SELECTED_VALUE_STREAM', payload: { selectedValueStream } }]} + action | payload | expectedActions | expectedMutations + ${'setLoading'} | ${true} | ${[]} | ${[{ type: 'SET_LOADING', payload: true }]} + ${'setDateRange'} | ${{ startDate: mockStartDate }} | ${mockFetchStageDataActions} | ${[mockSetDateActionCommit]} + ${'setFilters'} | ${[]} | ${mockFetchStageDataActions} | ${[]} + ${'setSelectedStage'} | ${{ selectedStage }} | ${[{ type: 'fetchStageData' }]} | ${[{ type: 'SET_SELECTED_STAGE', payload: { selectedStage } }]} + ${'setSelectedValueStream'} | ${{ selectedValueStream }} | ${[{ type: 'fetchValueStreamStages' }, { type: 'fetchCycleAnalyticsData' }]} | ${[{ type: 'SET_SELECTED_VALUE_STREAM', payload: { selectedValueStream } }]} `('$action', ({ action, payload, expectedActions, expectedMutations }) => { const types = mutationTypes(expectedMutations); - it(`will dispatch ${expectedActions} and commit ${types}`, () => testAction({ action: actions[action], state, payload, expectedMutations, - expectedActions: expectedActions.map((a) => ({ type: a })), + expectedActions, })); }); + describe('initializeVsa', () => { + let mockDispatch; + let mockCommit; + const payload = { endpoints: mockEndpoints }; + + beforeEach(() => { + mockDispatch = jest.fn(() => Promise.resolve()); + mockCommit = jest.fn(); + }); + + it('will dispatch the setLoading and fetchValueStreams actions and commit INITIALIZE_VSA', async () => { + await actions.initializeVsa( + { + ...state, + dispatch: mockDispatch, + commit: mockCommit, + }, + payload, + ); + expect(mockCommit).toHaveBeenCalledWith('INITIALIZE_VSA', { endpoints: mockEndpoints }); + expect(mockDispatch).toHaveBeenCalledWith('setLoading', true); + expect(mockDispatch).toHaveBeenCalledWith('fetchValueStreams'); + expect(mockDispatch).toHaveBeenCalledWith('setLoading', false); + }); + }); + describe('fetchCycleAnalyticsData', () => { beforeEach(() => { - state = { requestPath: mockRequestPath }; + state = { endpoints: mockEndpoints }; mock = new MockAdapter(axios); mock.onGet(mockRequestPath).reply(httpStatusCodes.OK); }); @@ -85,7 +103,7 @@ describe('Project Value Stream Analytics actions', () => { describe('with a failing request', () => { beforeEach(() => { - state = { requestPath: mockRequestPath }; + state = { endpoints: mockEndpoints }; mock = new MockAdapter(axios); mock.onGet(mockRequestPath).reply(httpStatusCodes.BAD_REQUEST); }); @@ -105,11 +123,12 @@ describe('Project Value Stream Analytics actions', () => { }); describe('fetchStageData', () => { - const mockStagePath = `${mockRequestPath}/events/${selectedStage.name}`; + const mockStagePath = /value_streams\/\w+\/stages\/\w+\/records/; beforeEach(() => { state = { - requestPath: mockRequestPath, + ...defaultState, + endpoints: mockEndpoints, startDate: mockStartDate, selectedStage, }; @@ -131,7 +150,8 @@ describe('Project Value Stream Analytics actions', () => { beforeEach(() => { state = { - requestPath: mockRequestPath, + ...defaultState, + endpoints: mockEndpoints, startDate: mockStartDate, selectedStage, }; @@ -155,7 +175,8 @@ describe('Project Value Stream Analytics actions', () => { describe('with a failing request', () => { beforeEach(() => { state = { - requestPath: mockRequestPath, + ...defaultState, + endpoints: mockEndpoints, startDate: mockStartDate, selectedStage, }; @@ -179,8 +200,7 @@ describe('Project Value Stream Analytics actions', () => { beforeEach(() => { state = { - features, - fullPath: mockFullPath, + endpoints: mockEndpoints, }; mock = new MockAdapter(axios); mock.onGet(mockValueStreamPath).reply(httpStatusCodes.OK); @@ -196,29 +216,10 @@ describe('Project Value Stream Analytics actions', () => { { type: 'receiveValueStreamsSuccess' }, { type: 'setSelectedStage' }, { type: 'fetchStageMedians' }, + { type: 'fetchStageCountValues' }, ], })); - describe('with cycleAnalyticsForGroups=false', () => { - beforeEach(() => { - state = { - features: { cycleAnalyticsForGroups: false }, - fullPath: mockFullPath, - }; - mock = new MockAdapter(axios); - mock.onGet(mockValueStreamPath).reply(httpStatusCodes.OK); - }); - - it("does not dispatch the 'fetchStageMedians' request", () => - testAction({ - action: actions.fetchValueStreams, - state, - payload: {}, - expectedMutations: [{ type: 'REQUEST_VALUE_STREAMS' }], - expectedActions: [{ type: 'receiveValueStreamsSuccess' }, { type: 'setSelectedStage' }], - })); - }); - describe('with a failing request', () => { beforeEach(() => { mock = new MockAdapter(axios); @@ -271,7 +272,7 @@ describe('Project Value Stream Analytics actions', () => { beforeEach(() => { state = { - fullPath: mockFullPath, + endpoints: mockEndpoints, selectedValueStream, }; mock = new MockAdapter(axios); @@ -364,4 +365,64 @@ describe('Project Value Stream Analytics actions', () => { })); }); }); + + describe('fetchStageCountValues', () => { + const mockValueStreamPath = /count/; + const stageCountsPayload = [ + { id: 'issue', count: 1 }, + { id: 'plan', count: 2 }, + { id: 'code', count: 3 }, + ]; + + const stageCountError = new Error( + `Request failed with status code ${httpStatusCodes.BAD_REQUEST}`, + ); + + beforeEach(() => { + state = { + fullPath: mockFullPath, + selectedValueStream, + stages: allowedStages, + }; + mock = new MockAdapter(axios); + mock + .onGet(mockValueStreamPath) + .replyOnce(httpStatusCodes.OK, { count: 1 }) + .onGet(mockValueStreamPath) + .replyOnce(httpStatusCodes.OK, { count: 2 }) + .onGet(mockValueStreamPath) + .replyOnce(httpStatusCodes.OK, { count: 3 }); + }); + + it(`commits the 'REQUEST_STAGE_COUNTS' and 'RECEIVE_STAGE_COUNTS_SUCCESS' mutations`, () => + testAction({ + action: actions.fetchStageCountValues, + state, + payload: {}, + expectedMutations: [ + { type: 'REQUEST_STAGE_COUNTS' }, + { type: 'RECEIVE_STAGE_COUNTS_SUCCESS', payload: stageCountsPayload }, + ], + expectedActions: [], + })); + + describe('with a failing request', () => { + beforeEach(() => { + mock = new MockAdapter(axios); + mock.onGet(mockValueStreamPath).reply(httpStatusCodes.BAD_REQUEST); + }); + + it(`commits the 'RECEIVE_STAGE_COUNTS_ERROR' mutation`, () => + testAction({ + action: actions.fetchStageCountValues, + state, + payload: {}, + expectedMutations: [ + { type: 'REQUEST_STAGE_COUNTS' }, + { type: 'RECEIVE_STAGE_COUNTS_ERROR', payload: stageCountError }, + ], + expectedActions: [], + })); + }); + }); }); diff --git a/spec/frontend/cycle_analytics/store/getters_spec.js b/spec/frontend/cycle_analytics/store/getters_spec.js index 5745e9d7902..c47a30a5f79 100644 --- a/spec/frontend/cycle_analytics/store/getters_spec.js +++ b/spec/frontend/cycle_analytics/store/getters_spec.js @@ -4,12 +4,13 @@ import { stageMedians, transformedProjectStagePathData, selectedStage, + stageCounts, } from '../mock_data'; describe('Value stream analytics getters', () => { describe('pathNavigationData', () => { it('returns the transformed data', () => { - const state = { stages: allowedStages, medians: stageMedians, selectedStage }; + const state = { stages: allowedStages, medians: stageMedians, selectedStage, stageCounts }; expect(getters.pathNavigationData(state)).toEqual(transformedProjectStagePathData); }); }); diff --git a/spec/frontend/cycle_analytics/store/mutations_spec.js b/spec/frontend/cycle_analytics/store/mutations_spec.js index 77b19280517..7fcfef98547 100644 --- a/spec/frontend/cycle_analytics/store/mutations_spec.js +++ b/spec/frontend/cycle_analytics/store/mutations_spec.js @@ -4,30 +4,29 @@ import * as types from '~/cycle_analytics/store/mutation_types'; import mutations from '~/cycle_analytics/store/mutations'; import { selectedStage, - rawEvents, - convertedEvents, - rawData, - convertedData, + rawIssueEvents, + issueEvents, selectedValueStream, rawValueStreamStages, valueStreamStages, rawStageMedians, formattedStageMedians, + rawStageCounts, + stageCounts, } from '../mock_data'; let state; +const rawEvents = rawIssueEvents.events; +const convertedEvents = issueEvents.events; const mockRequestPath = 'fake/request/path'; const mockCreatedAfter = '2020-06-18'; const mockCreatedBefore = '2020-07-18'; -const features = { - cycleAnalyticsForGroups: true, -}; describe('Project Value Stream Analytics mutations', () => { useFakeDate(2020, 6, 18); beforeEach(() => { - state = { features }; + state = {}; }); afterEach(() => { @@ -58,26 +57,48 @@ describe('Project Value Stream Analytics mutations', () => { ${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true} ${types.REQUEST_STAGE_MEDIANS} | ${'medians'} | ${{}} ${types.RECEIVE_STAGE_MEDIANS_ERROR} | ${'medians'} | ${{}} + ${types.REQUEST_STAGE_COUNTS} | ${'stageCounts'} | ${{}} + ${types.RECEIVE_STAGE_COUNTS_ERROR} | ${'stageCounts'} | ${{}} `('$mutation will set $stateKey to $value', ({ mutation, stateKey, value }) => { - mutations[mutation](state, {}); + mutations[mutation](state); expect(state).toMatchObject({ [stateKey]: value }); }); + const mockInitialPayload = { + endpoints: { requestPath: mockRequestPath }, + currentGroup: { title: 'cool-group' }, + id: 1337, + }; + const mockInitializedObj = { + endpoints: { requestPath: mockRequestPath }, + createdAfter: mockCreatedAfter, + createdBefore: mockCreatedBefore, + }; + it.each` - mutation | payload | stateKey | value - ${types.INITIALIZE_VSA} | ${{ requestPath: mockRequestPath }} | ${'requestPath'} | ${mockRequestPath} - ${types.SET_DATE_RANGE} | ${{ startDate: DEFAULT_DAYS_TO_DISPLAY }} | ${'startDate'} | ${DEFAULT_DAYS_TO_DISPLAY} - ${types.SET_DATE_RANGE} | ${{ startDate: DEFAULT_DAYS_TO_DISPLAY }} | ${'createdAfter'} | ${mockCreatedAfter} - ${types.SET_DATE_RANGE} | ${{ startDate: DEFAULT_DAYS_TO_DISPLAY }} | ${'createdBefore'} | ${mockCreatedBefore} - ${types.SET_LOADING} | ${true} | ${'isLoading'} | ${true} - ${types.SET_LOADING} | ${false} | ${'isLoading'} | ${false} - ${types.SET_SELECTED_VALUE_STREAM} | ${selectedValueStream} | ${'selectedValueStream'} | ${selectedValueStream} - ${types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS} | ${rawData} | ${'summary'} | ${convertedData.summary} - ${types.RECEIVE_VALUE_STREAMS_SUCCESS} | ${[selectedValueStream]} | ${'valueStreams'} | ${[selectedValueStream]} - ${types.RECEIVE_VALUE_STREAM_STAGES_SUCCESS} | ${{ stages: rawValueStreamStages }} | ${'stages'} | ${valueStreamStages} - ${types.RECEIVE_VALUE_STREAMS_SUCCESS} | ${[selectedValueStream]} | ${'valueStreams'} | ${[selectedValueStream]} - ${types.RECEIVE_STAGE_MEDIANS_SUCCESS} | ${rawStageMedians} | ${'medians'} | ${formattedStageMedians} + mutation | stateKey | value + ${types.INITIALIZE_VSA} | ${'endpoints'} | ${{ requestPath: mockRequestPath }} + ${types.INITIALIZE_VSA} | ${'createdAfter'} | ${mockCreatedAfter} + ${types.INITIALIZE_VSA} | ${'createdBefore'} | ${mockCreatedBefore} + `('$mutation will set $stateKey', ({ mutation, stateKey, value }) => { + mutations[mutation](state, { ...mockInitialPayload }); + + expect(state).toMatchObject({ ...mockInitializedObj, [stateKey]: value }); + }); + + it.each` + mutation | payload | stateKey | value + ${types.SET_DATE_RANGE} | ${DEFAULT_DAYS_TO_DISPLAY} | ${'daysInPast'} | ${DEFAULT_DAYS_TO_DISPLAY} + ${types.SET_DATE_RANGE} | ${DEFAULT_DAYS_TO_DISPLAY} | ${'createdAfter'} | ${mockCreatedAfter} + ${types.SET_DATE_RANGE} | ${DEFAULT_DAYS_TO_DISPLAY} | ${'createdBefore'} | ${mockCreatedBefore} + ${types.SET_LOADING} | ${true} | ${'isLoading'} | ${true} + ${types.SET_LOADING} | ${false} | ${'isLoading'} | ${false} + ${types.SET_SELECTED_VALUE_STREAM} | ${selectedValueStream} | ${'selectedValueStream'} | ${selectedValueStream} + ${types.RECEIVE_VALUE_STREAMS_SUCCESS} | ${[selectedValueStream]} | ${'valueStreams'} | ${[selectedValueStream]} + ${types.RECEIVE_VALUE_STREAM_STAGES_SUCCESS} | ${{ stages: rawValueStreamStages }} | ${'stages'} | ${valueStreamStages} + ${types.RECEIVE_STAGE_MEDIANS_SUCCESS} | ${rawStageMedians} | ${'medians'} | ${formattedStageMedians} + ${types.RECEIVE_STAGE_COUNTS_SUCCESS} | ${rawStageCounts} | ${'stageCounts'} | ${stageCounts} `( '$mutation with $payload will set $stateKey to $value', ({ mutation, payload, stateKey, value }) => { @@ -95,41 +116,10 @@ describe('Project Value Stream Analytics mutations', () => { }); it.each` - mutation | payload | stateKey | value - ${types.RECEIVE_STAGE_DATA_SUCCESS} | ${{ events: [] }} | ${'isEmptyStage'} | ${true} - ${types.RECEIVE_STAGE_DATA_SUCCESS} | ${{ events: rawEvents }} | ${'selectedStageEvents'} | ${convertedEvents} - ${types.RECEIVE_STAGE_DATA_SUCCESS} | ${{ events: rawEvents }} | ${'isEmptyStage'} | ${false} - `( - '$mutation with $payload will set $stateKey to $value', - ({ mutation, payload, stateKey, value }) => { - mutations[mutation](state, payload); - - expect(state).toMatchObject({ [stateKey]: value }); - }, - ); - }); - - describe('with cycleAnalyticsForGroups=false', () => { - useFakeDate(2020, 6, 18); - - beforeEach(() => { - state = { features: { cycleAnalyticsForGroups: false } }; - }); - - const formattedMedians = { - code: '2d', - issue: '-', - plan: '21h', - review: '-', - staging: '2d', - test: '4h', - }; - - it.each` - mutation | payload | stateKey | value - ${types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS} | ${rawData} | ${'medians'} | ${formattedMedians} - ${types.REQUEST_CYCLE_ANALYTICS_DATA} | ${{}} | ${'medians'} | ${{}} - ${types.RECEIVE_CYCLE_ANALYTICS_DATA_ERROR} | ${{}} | ${'medians'} | ${{}} + mutation | payload | stateKey | value + ${types.RECEIVE_STAGE_DATA_SUCCESS} | ${[]} | ${'isEmptyStage'} | ${true} + ${types.RECEIVE_STAGE_DATA_SUCCESS} | ${rawEvents} | ${'selectedStageEvents'} | ${convertedEvents} + ${types.RECEIVE_STAGE_DATA_SUCCESS} | ${rawEvents} | ${'isEmptyStage'} | ${false} `( '$mutation with $payload will set $stateKey to $value', ({ mutation, payload, stateKey, value }) => { |