Commit 7f6f70fc authored by Savas Vedova's avatar Savas Vedova

Merge branch...

Merge branch '335974-vsa-fe-add-sorting-and-pagination-to-the-project-level-stage-table' into 'master'

[VSA][FE] Add sorting and pagination to the project level stage table

See merge request gitlab-org/gitlab!71875
parents 2c99025f 76e23a12
......@@ -51,6 +51,7 @@ export default {
'features',
'createdBefore',
'createdAfter',
'pagination',
]),
...mapGetters(['pathNavigationData', 'filterParams']),
displayStageEvents() {
......@@ -99,7 +100,12 @@ export default {
},
},
methods: {
...mapActions(['fetchStageData', 'setSelectedStage', 'setDateRange']),
...mapActions([
'fetchStageData',
'setSelectedStage',
'setDateRange',
'updateStageTablePagination',
]),
onSetDateRange({ startDate, endDate }) {
this.setDateRange({
createdAfter: new Date(startDate),
......@@ -108,6 +114,7 @@ export default {
},
onSelectStage(stage) {
this.setSelectedStage(stage);
this.updateStageTablePagination({ ...this.pagination, page: 1 });
},
dismissOverviewDialog() {
this.isOverviewDialogDismissed = true;
......@@ -117,6 +124,9 @@ export default {
const { permissions } = this;
return Boolean(permissions?.[id]);
},
onHandleUpdatePagination(data) {
this.updateStageTablePagination(data);
},
},
dayRangeOptions: [7, 30, 90],
i18n: {
......@@ -163,8 +173,8 @@ export default {
:empty-state-title="emptyStageTitle"
:empty-state-message="emptyStageText"
:no-data-svg-path="noDataSvgPath"
:pagination="null"
:sortable="false"
:pagination="pagination"
@handleUpdatePagination="onHandleUpdatePagination"
/>
</div>
</template>
......@@ -194,6 +194,9 @@ export default {
><formatted-stage-count :stage-count="stageCount"
/></gl-badge>
</template>
<template #head(duration)="data">
<span data-testid="vsa-stage-header-duration">{{ data.label }}</span>
</template>
<template #cell(end_event)="{ item }">
<div data-testid="vsa-stage-event">
<div v-if="item.id" data-testid="vsa-stage-content">
......
......@@ -6,6 +6,7 @@ import {
getValueStreamStageRecords,
getValueStreamStageCounts,
} from '~/api/analytics_api';
import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils';
import createFlash from '~/flash';
import { __ } from '~/locale';
import { DEFAULT_VALUE_STREAM, I18N_VSA_ERROR_STAGE_MEDIAN } from '../constants';
......@@ -72,16 +73,21 @@ export const fetchCycleAnalyticsData = ({
});
};
export const fetchStageData = ({ getters: { requestParams, filterParams }, commit }) => {
export const fetchStageData = ({
getters: { requestParams, filterParams, paginationParams },
commit,
}) => {
commit(types.REQUEST_STAGE_DATA);
return getValueStreamStageRecords(requestParams, filterParams)
.then(({ data }) => {
return getValueStreamStageRecords(requestParams, { ...filterParams, ...paginationParams })
.then(({ data, headers }) => {
// when there's a query timeout, the request succeeds but the error is encoded in the response data
if (data?.error) {
commit(types.RECEIVE_STAGE_DATA_ERROR, data.error);
} else {
commit(types.RECEIVE_STAGE_DATA_SUCCESS, data);
const { page = null, nextPage = null } = parseIntPagination(normalizeHeaders(headers));
commit(types.SET_PAGINATION, { ...paginationParams, page, hasNextPage: Boolean(nextPage) });
}
})
.catch(() => commit(types.RECEIVE_STAGE_DATA_ERROR));
......@@ -176,6 +182,14 @@ export const setDateRange = ({ dispatch, commit }, { createdAfter, createdBefore
return refetchStageData(dispatch);
};
export const updateStageTablePagination = (
{ commit, dispatch, state: { selectedStage } },
paginationParams,
) => {
commit(types.SET_PAGINATION, paginationParams);
return dispatch('fetchStageData', selectedStage.id);
};
export const initializeVsa = ({ commit, dispatch }, initialData = {}) => {
commit(types.INITIALIZE_VSA, initialData);
......
import dateFormat from 'dateformat';
import { dateFormats } from '~/analytics/shared/constants';
import { filterToQueryObject } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { PAGINATION_TYPE } from '../constants';
import { transformStagesForPathNavigation, filterStagesByHiddenStatus } from '../utils';
export const pathNavigationData = ({ stages, medians, stageCounts, selectedStage }) => {
......@@ -21,6 +22,13 @@ export const requestParams = (state) => {
return { requestPath: fullPath, valueStreamId, stageId };
};
export const paginationParams = ({ pagination: { page, sort, direction } }) => ({
pagination: PAGINATION_TYPE,
sort,
direction,
page,
});
const filterBarParams = ({ filters }) => {
const {
authors: { selected: selectedAuthor },
......
......@@ -4,6 +4,7 @@ export const SET_LOADING = 'SET_LOADING';
export const SET_SELECTED_VALUE_STREAM = 'SET_SELECTED_VALUE_STREAM';
export const SET_SELECTED_STAGE = 'SET_SELECTED_STAGE';
export const SET_DATE_RANGE = 'SET_DATE_RANGE';
export const SET_PAGINATION = 'SET_PAGINATION';
export const REQUEST_VALUE_STREAMS = 'REQUEST_VALUE_STREAMS';
export const RECEIVE_VALUE_STREAMS_SUCCESS = 'RECEIVE_VALUE_STREAMS_SUCCESS';
......
import Vue from 'vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { PAGINATION_SORT_FIELD_END_EVENT, PAGINATION_SORT_DIRECTION_DESC } from '../constants';
import { formatMedianValues } from '../utils';
import * as types from './mutation_types';
export default {
[types.INITIALIZE_VSA](state, { endpoints, features, createdBefore, createdAfter }) {
[types.INITIALIZE_VSA](
state,
{ endpoints, features, createdBefore, createdAfter, pagination = {} },
) {
state.endpoints = endpoints;
state.createdBefore = createdBefore;
state.createdAfter = createdAfter;
state.features = features;
Vue.set(state, 'pagination', {
page: pagination.page ?? state.pagination.page,
sort: pagination.sort ?? state.pagination.sort,
direction: pagination.direction ?? state.pagination.direction,
});
},
[types.SET_LOADING](state, loadingState) {
state.isLoading = loadingState;
......@@ -22,6 +33,14 @@ export default {
state.createdBefore = createdBefore;
state.createdAfter = createdAfter;
},
[types.SET_PAGINATION](state, { page, hasNextPage, sort, direction }) {
Vue.set(state, 'pagination', {
page,
hasNextPage,
sort: sort || PAGINATION_SORT_FIELD_END_EVENT,
direction: direction || PAGINATION_SORT_DIRECTION_DESC,
});
},
[types.REQUEST_VALUE_STREAMS](state) {
state.valueStreams = [];
},
......
import {
PAGINATION_SORT_FIELD_END_EVENT,
PAGINATION_SORT_DIRECTION_DESC,
} from '~/cycle_analytics/constants';
export default () => ({
id: null,
features: {},
......@@ -20,4 +25,10 @@ export default () => ({
isLoadingStage: false,
isEmptyStage: false,
permissions: {},
pagination: {
page: null,
hasNextPage: false,
sort: PAGINATION_SORT_FIELD_END_EVENT,
direction: PAGINATION_SORT_DIRECTION_DESC,
},
});
......@@ -68,6 +68,34 @@ To filter analytics results based on a date range,
select different **From** and **To** days
from the date picker (default: last 30 days).
### Stage table
> Sorting the stage table [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335974) in GitLab 14.4.
![Value Stream Analytics Stage table](img/project_vsa_stage_table_v14_4.png "Project VSA stage table")
The stage table shows a list of related workflow items for the selected stage. This can include:
- CI/CD jobs
- Issues
- Merge requests
- Pipelines
A little badge next to the workflow items table header shows the number of workflow items that
completed the selected stage.
The stage table also includes the **Time** column, which shows how long it takes each item to pass
through the selected value stream stage.
To sort the stage table by a table column, select the table header.
You can sort in ascending or descending order. To find items that spent the most time in a stage,
potentially causing bottlenecks in your value stream, sort the table by the **Time** column.
From there, select individual items to drill in and investigate how delays are happening.
To see which items most recently exited the stage, sort by the work item column on the left.
The table displays 20 items per page. If there are more than 20 items, you can use the
**Prev** and **Next** buttons to navigate through the pages.
## How Time metrics are measured
The **Time** metrics near the top of the page are measured as follows:
......
......@@ -284,9 +284,9 @@ To sort the stage table by a table column, select the table header.
You can sort in ascending or descending order. To find items that spent the most time in a stage,
potentially causing bottlenecks in your value stream, sort the table by the **Time** column.
From there, select individual items to drill in and investigate how delays are happening.
To see which items the stage most recently, sort by the work item column on the left.
To see which items most recently exited the stage, sort by the work item column on the left.
The table displays up to 20 items at a time. If there are more than 20 items, you can use the
The table displays 20 items per page. If there are more than 20 items, you can use the
**Prev** and **Next** buttons to navigate through the pages.
### Creating a value stream
......
import dateFormat from 'dateformat';
import { isNumber } from 'lodash';
import { dateFormats } from '~/analytics/shared/constants';
import { OVERVIEW_STAGE_ID, PAGINATION_TYPE } from '~/cycle_analytics/constants';
import { pathNavigationData as basePathNavigationData } from '~/cycle_analytics/store/getters';
import { OVERVIEW_STAGE_ID } from '~/cycle_analytics/constants';
import {
pathNavigationData as basePathNavigationData,
paginationParams as basePaginationParams,
} from '~/cycle_analytics/store/getters';
import { filterStagesByHiddenStatus } from '~/cycle_analytics/utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import httpStatus from '~/lib/utils/http_status';
......@@ -46,12 +49,7 @@ export const cycleAnalyticsRequestParams = (state, getters) => {
};
};
export const paginationParams = ({ pagination: { page, sort, direction } }) => ({
pagination: PAGINATION_TYPE,
sort,
direction,
page,
});
export const paginationParams = basePaginationParams;
export const hiddenStages = ({ stages }) => filterStagesByHiddenStatus(stages);
export const activeStages = ({ stages }) => filterStagesByHiddenStatus(stages, false);
......
......@@ -14,6 +14,7 @@ import {
createdBefore,
createdAfter,
selectedProjects,
initialPaginationQuery,
} from 'jest/cycle_analytics/mock_data';
import { toYmd } from '~/analytics/shared/utils';
import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
......@@ -33,7 +34,6 @@ import httpStatusCodes from '~/lib/utils/http_status';
import * as urlUtils from '~/lib/utils/url_utility';
import UrlSync from '~/vue_shared/components/url_sync.vue';
import {
initialPaginationQuery,
valueStreams,
endpoints,
customizableStagesAndEvents,
......
import tasksByType from 'test_fixtures/analytics/charts/type_of_work/tasks_by_type.json';
import { uniq } from 'lodash';
import tasksByType from 'test_fixtures/analytics/charts/type_of_work/tasks_by_type.json';
import {
TASKS_BY_TYPE_SUBJECT_ISSUE,
OVERVIEW_STAGE_CONFIG,
......@@ -20,11 +20,6 @@ import {
deepCamelCase,
} from 'jest/cycle_analytics/mock_data';
import { toYmd } from '~/analytics/shared/utils';
import {
PAGINATION_TYPE,
PAGINATION_SORT_DIRECTION_DESC,
PAGINATION_SORT_FIELD_END_EVENT,
} from '~/cycle_analytics/constants';
import { transformStagesForPathNavigation, formatMedianValues } from '~/cycle_analytics/utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { getDatesInRange } from '~/lib/utils/datetime_utility';
......@@ -270,22 +265,3 @@ export const rawDurationMedianData = [
];
export const pathNavIssueMetric = 172800;
export const initialPaginationQuery = {
page: 15,
sort: PAGINATION_SORT_FIELD_END_EVENT,
direction: PAGINATION_SORT_DIRECTION_DESC,
};
export const initialPaginationState = {
...initialPaginationQuery,
page: null,
hasNextPage: false,
};
export const basePaginationResult = {
pagination: PAGINATION_TYPE,
sort: PAGINATION_SORT_FIELD_END_EVENT,
direction: PAGINATION_SORT_DIRECTION_DESC,
page: null,
};
......@@ -14,8 +14,6 @@ import {
issueStage,
stageMediansWithNumericIds,
stageCounts,
basePaginationResult,
initialPaginationState,
transformedStagePathData,
} from '../mock_data';
......@@ -221,26 +219,6 @@ describe('Value Stream Analytics getters', () => {
});
});
describe('paginationParams', () => {
beforeEach(() => {
state = { pagination: initialPaginationState };
});
it('returns the `pagination` type', () => {
expect(getters.paginationParams(state)).toEqual(basePaginationResult);
});
it('returns the `sort` type', () => {
expect(getters.paginationParams(state)).toEqual(basePaginationResult);
});
it('with page=10, sets the `page` property', () => {
const page = 10;
state = { pagination: { ...initialPaginationState, page } };
expect(getters.paginationParams(state)).toEqual({ ...basePaginationResult, page });
});
});
describe('selectedStageCount', () => {
it('returns the count when a value exist for the given stage', () => {
state = { selectedStage: { id: 1 }, stageCounts: { 1: 10, 2: 20 } };
......
......@@ -7,10 +7,13 @@ RSpec.describe 'Value Stream Analytics', :js do
let_it_be(:guest) { create(:user) }
let_it_be(:stage_table_selector) { '[data-testid="vsa-stage-table"]' }
let_it_be(:stage_table_event_selector) { '[data-testid="vsa-stage-event"]' }
let_it_be(:stage_table_event_title_selector) { '[data-testid="vsa-stage-event-title"]' }
let_it_be(:stage_table_pagination_selector) { '[data-testid="vsa-stage-pagination"]' }
let_it_be(:stage_table_duration_column_header_selector) { '[data-testid="vsa-stage-header-duration"]' }
let_it_be(:metrics_selector) { "[data-testid='vsa-time-metrics']" }
let_it_be(:metric_value_selector) { "[data-testid='displayValue']" }
let(:stage_table) { page.find(stage_table_selector) }
let(:stage_table) { find(stage_table_selector) }
let(:project) { create(:project, :repository) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
let(:milestone) { create(:milestone, project: project) }
......@@ -53,6 +56,7 @@ RSpec.describe 'Value Stream Analytics', :js do
# So setting the date range to be the last 2 days should skip past the existing data
from = 2.days.ago.strftime("%Y-%m-%d")
to = 1.day.ago.strftime("%Y-%m-%d")
max_items_per_page = 20
around do |example|
travel_to(5.days.ago) { example.run }
......@@ -60,9 +64,8 @@ RSpec.describe 'Value Stream Analytics', :js do
before do
project.add_maintainer(user)
create_list(:issue, 2, project: project, created_at: 2.weeks.ago, milestone: milestone)
create_cycle(user, project, issue, mr, milestone, pipeline)
create_list(:issue, max_items_per_page, project: project, created_at: 2.weeks.ago, milestone: milestone)
deploy_master(user, project)
issue.metrics.update!(first_mentioned_in_commit_at: issue.metrics.first_associated_with_milestone_at + 1.hour)
......@@ -81,6 +84,8 @@ RSpec.describe 'Value Stream Analytics', :js do
wait_for_requests
end
let(:stage_table_events) { stage_table.all(stage_table_event_selector) }
it 'displays metrics' do
metrics_tiles = page.find(metrics_selector)
......@@ -112,20 +117,62 @@ RSpec.describe 'Value Stream Analytics', :js do
end
it 'can filter the issues by date' do
expect(stage_table.all(stage_table_event_selector).length).to eq(3)
expect(page).to have_selector(stage_table_event_selector)
set_daterange(from, to)
expect(stage_table.all(stage_table_event_selector).length).to eq(0)
expect(page).not_to have_selector(stage_table_event_selector)
expect(page).not_to have_selector(stage_table_pagination_selector)
end
it 'can filter the metrics by date' do
expect(metrics_values).to eq(["3.0", "2.0", "1.0", "0.0"])
expect(metrics_values).to match_array(["21.0", "2.0", "1.0", "0.0"])
set_daterange(from, to)
expect(metrics_values).to eq(['-'] * 4)
end
it 'can sort records' do
# NOTE: checking that the string changes should suffice
# depending on the order the tests are run we might run into problems with hard coded strings
original_first_title = first_stage_title
stage_time_column.click
expect_to_be_sorted "descending"
expect(first_stage_title).not_to have_text(original_first_title, exact: true)
stage_time_column.click
expect_to_be_sorted "ascending"
expect(first_stage_title).to have_text(original_first_title, exact: true)
end
it 'paginates the results' do
original_first_title = first_stage_title
expect(page).to have_selector(stage_table_pagination_selector)
go_to_next_page
expect(page).not_to have_text(original_first_title, exact: true)
end
def stage_time_column
stage_table.find(stage_table_duration_column_header_selector).ancestor("th")
end
def first_stage_title
stage_table.all(stage_table_event_title_selector).first.text
end
def expect_to_be_sorted(direction)
expect(stage_time_column['aria-sort']).to eq(direction)
end
def go_to_next_page
page.find(stage_table_pagination_selector).find_link("Next").click
end
end
end
......
......@@ -19,6 +19,7 @@ import {
createdAfter,
currentGroup,
stageCounts,
initialPaginationState as pagination,
} from './mock_data';
const selectedStageEvents = issueEvents.events;
......@@ -81,6 +82,7 @@ const findOverviewMetrics = () => wrapper.findComponent(ValueStreamMetrics);
const findStageTable = () => wrapper.findComponent(StageTable);
const findStageEvents = () => findStageTable().props('stageEvents');
const findEmptyStageTitle = () => wrapper.findComponent(GlEmptyState).props('title');
const findPagination = () => wrapper.findByTestId('vsa-stage-pagination');
const hasMetricsRequests = (reqs) => {
const foundReqs = findOverviewMetrics().props('requests');
......@@ -90,7 +92,7 @@ const hasMetricsRequests = (reqs) => {
describe('Value stream analytics component', () => {
beforeEach(() => {
wrapper = createComponent({ initialState: { selectedStage, selectedStageEvents } });
wrapper = createComponent({ initialState: { selectedStage, selectedStageEvents, pagination } });
});
afterEach(() => {
......@@ -153,6 +155,10 @@ describe('Value stream analytics component', () => {
expect(findLoadingIcon().exists()).toBe(false);
});
it('renders pagination', () => {
expect(findPagination().exists()).toBe(true);
});
describe('with `cycleAnalyticsForGroups=true` license', () => {
beforeEach(() => {
wrapper = createComponent({ initialState: { features: { cycleAnalyticsForGroups: true } } });
......
import { getJSONFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'helpers/test_constants';
import { DEFAULT_VALUE_STREAM, DEFAULT_DAYS_IN_PAST } from '~/cycle_analytics/constants';
import {
DEFAULT_VALUE_STREAM,
DEFAULT_DAYS_IN_PAST,
PAGINATION_TYPE,
PAGINATION_SORT_DIRECTION_DESC,
PAGINATION_SORT_FIELD_END_EVENT,
} from '~/cycle_analytics/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { getDateInPast } from '~/lib/utils/datetime_utility';
......@@ -256,3 +262,22 @@ export const rawValueStreamStages = customizableStagesAndEvents.stages;
export const valueStreamStages = rawValueStreamStages.map((s) =>
convertObjectPropsToCamelCase(s, { deep: true }),
);
export const initialPaginationQuery = {
page: 15,
sort: PAGINATION_SORT_FIELD_END_EVENT,
direction: PAGINATION_SORT_DIRECTION_DESC,
};
export const initialPaginationState = {
...initialPaginationQuery,
page: null,
hasNextPage: false,
};
export const basePaginationResult = {
pagination: PAGINATION_TYPE,
sort: PAGINATION_SORT_FIELD_END_EVENT,
direction: PAGINATION_SORT_DIRECTION_DESC,
page: null,
};
......@@ -11,6 +11,8 @@ import {
currentGroup,
createdAfter,
createdBefore,
initialPaginationState,
reviewEvents,
} from '../mock_data';
const { id: groupId, path: groupPath } = currentGroup;
......@@ -31,7 +33,13 @@ const mockSetDateActionCommit = {
type: 'SET_DATE_RANGE',
};
const defaultState = { ...getters, selectedValueStream, createdAfter, createdBefore };
const defaultState = {
...getters,
selectedValueStream,
createdAfter,
createdBefore,
pagination: initialPaginationState,
};
describe('Project Value Stream Analytics actions', () => {
let state;
......@@ -112,6 +120,21 @@ describe('Project Value Stream Analytics actions', () => {
});
});
describe('updateStageTablePagination', () => {
beforeEach(() => {
state = { ...state, selectedStage };
});
it(`will dispatch the "fetchStageData" action and commit the 'SET_PAGINATION' mutation`, () => {
return testAction({
action: actions.updateStageTablePagination,
state,
expectedMutations: [{ type: 'SET_PAGINATION' }],
expectedActions: [{ type: 'fetchStageData', payload: selectedStage.id }],
});
});
});
describe('fetchCycleAnalyticsData', () => {
beforeEach(() => {
state = { ...defaultState, endpoints: mockEndpoints };
......@@ -154,6 +177,10 @@ describe('Project Value Stream Analytics actions', () => {
describe('fetchStageData', () => {
const mockStagePath = /value_streams\/\w+\/stages\/\w+\/records/;
const headers = {
'X-Next-Page': 2,
'X-Page': 1,
};
beforeEach(() => {
state = {
......@@ -162,7 +189,7 @@ describe('Project Value Stream Analytics actions', () => {
selectedStage,
};
mock = new MockAdapter(axios);
mock.onGet(mockStagePath).reply(httpStatusCodes.OK);
mock.onGet(mockStagePath).reply(httpStatusCodes.OK, reviewEvents, headers);
});
it(`commits the 'RECEIVE_STAGE_DATA_SUCCESS' mutation`, () =>
......@@ -170,7 +197,11 @@ describe('Project Value Stream Analytics actions', () => {
action: actions.fetchStageData,
state,
payload: {},
expectedMutations: [{ type: 'REQUEST_STAGE_DATA' }, { type: 'RECEIVE_STAGE_DATA_SUCCESS' }],
expectedMutations: [
{ type: 'REQUEST_STAGE_DATA' },
{ type: 'RECEIVE_STAGE_DATA_SUCCESS', payload: reviewEvents },
{ type: 'SET_PAGINATION', payload: { hasNextPage: true, page: 1 } },
],
expectedActions: [],
}));
......
import * as getters from '~/cycle_analytics/store/getters';
import {
allowedStages,
stageMedians,
transformedProjectStagePathData,
selectedStage,
stageCounts,
basePaginationResult,
initialPaginationState,
} from '../mock_data';
describe('Value stream analytics getters', () => {
let state = {};
describe('pathNavigationData', () => {
it('returns the transformed data', () => {
const state = { stages: allowedStages, medians: stageMedians, selectedStage, stageCounts };
state = { stages: allowedStages, medians: stageMedians, selectedStage, stageCounts };
expect(getters.pathNavigationData(state)).toEqual(transformedProjectStagePathData);
});
});
describe('paginationParams', () => {
beforeEach(() => {
state = { pagination: initialPaginationState };
});
it('returns the `pagination` type', () => {
expect(getters.paginationParams(state)).toEqual(basePaginationResult);
});
it('returns the `sort` type', () => {
expect(getters.paginationParams(state)).toEqual(basePaginationResult);
});
it('with page=10, sets the `page` property', () => {
const page = 10;
state = { pagination: { ...initialPaginationState, page } };
expect(getters.paginationParams(state)).toEqual({ ...basePaginationResult, page });
});
});
});
import { useFakeDate } from 'helpers/fake_date';
import * as types from '~/cycle_analytics/store/mutation_types';
import mutations from '~/cycle_analytics/store/mutations';
import {
PAGINATION_SORT_FIELD_END_EVENT,
PAGINATION_SORT_DIRECTION_DESC,
} from '~/cycle_analytics/constants';
import {
selectedStage,
rawIssueEvents,
......@@ -12,6 +16,7 @@ import {
formattedStageMedians,
rawStageCounts,
stageCounts,
initialPaginationState as pagination,
} from '../mock_data';
let state;
......@@ -25,7 +30,7 @@ describe('Project Value Stream Analytics mutations', () => {
useFakeDate(2020, 6, 18);
beforeEach(() => {
state = {};
state = { pagination };
});
afterEach(() => {
......@@ -94,6 +99,8 @@ describe('Project Value Stream Analytics mutations', () => {
${types.SET_LOADING} | ${true} | ${'isLoading'} | ${true}
${types.SET_LOADING} | ${false} | ${'isLoading'} | ${false}
${types.SET_SELECTED_VALUE_STREAM} | ${selectedValueStream} | ${'selectedValueStream'} | ${selectedValueStream}
${types.SET_PAGINATION} | ${pagination} | ${'pagination'} | ${{ ...pagination, sort: PAGINATION_SORT_FIELD_END_EVENT, direction: PAGINATION_SORT_DIRECTION_DESC }}
${types.SET_PAGINATION} | ${{ ...pagination, sort: 'duration', direction: 'asc' }} | ${'pagination'} | ${{ ...pagination, sort: 'duration', direction: 'asc' }}
${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}
......
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