Commit ae451305 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '321438-add-overview-stage-to-vsa-navigation' into 'master'

Adds an overview stage to VSA

See merge request gitlab-org/gitlab!56621
parents 2c5dc906 a972b1f2
...@@ -6,7 +6,7 @@ import DateRange from '../../shared/components/daterange.vue'; ...@@ -6,7 +6,7 @@ import DateRange from '../../shared/components/daterange.vue';
import ProjectsDropdownFilter from '../../shared/components/projects_dropdown_filter.vue'; import ProjectsDropdownFilter from '../../shared/components/projects_dropdown_filter.vue';
import { DATE_RANGE_LIMIT } from '../../shared/constants'; import { DATE_RANGE_LIMIT } from '../../shared/constants';
import { toYmd } from '../../shared/utils'; import { toYmd } from '../../shared/utils';
import { PROJECTS_PER_PAGE } from '../constants'; import { PROJECTS_PER_PAGE, OVERVIEW_STAGE_ID } from '../constants';
import CustomStageForm from './custom_stage_form.vue'; import CustomStageForm from './custom_stage_form.vue';
import DurationChart from './duration_chart.vue'; import DurationChart from './duration_chart.vue';
import FilterBar from './filter_bar.vue'; import FilterBar from './filter_bar.vue';
...@@ -86,17 +86,28 @@ export default { ...@@ -86,17 +86,28 @@ export default {
shouldDisplayFilters() { shouldDisplayFilters() {
return !this.errorCode; return !this.errorCode;
}, },
isOverviewStageSelected() {
return this.selectedStage?.id === OVERVIEW_STAGE_ID;
},
shouldDisplayDurationChart() { shouldDisplayDurationChart() {
return this.featureFlags.hasDurationChart && !this.hasNoAccessError; return (
!this.featureFlags.hasPathNavigation ||
(this.featureFlags.hasDurationChart &&
this.isOverviewStageSelected &&
!this.hasNoAccessError)
);
}, },
shouldDisplayTypeOfWorkCharts() { shouldDisplayTypeOfWorkCharts() {
return !this.hasNoAccessError; return (
!this.featureFlags.hasPathNavigation ||
(this.isOverviewStageSelected && !this.hasNoAccessError)
);
}, },
selectedStageReady() { selectedStageReady() {
return !this.hasNoAccessError && this.selectedStage; return !this.hasNoAccessError && this.selectedStage;
}, },
shouldDisplayPathNavigation() { shouldDisplayPathNavigation() {
return this.featureFlags.hasPathNavigation && !this.hasNoAccessError; return this.featureFlags.hasPathNavigation && this.selectedStageReady;
}, },
shouldDisplayVerticalNavigation() { shouldDisplayVerticalNavigation() {
return !this.featureFlags.hasPathNavigation && this.selectedStageReady; return !this.featureFlags.hasPathNavigation && this.selectedStageReady;
...@@ -134,6 +145,7 @@ export default { ...@@ -134,6 +145,7 @@ export default {
'fetchStageData', 'fetchStageData',
'setSelectedProjects', 'setSelectedProjects',
'setSelectedStage', 'setSelectedStage',
'setDefaultSelectedStage',
'setDateRange', 'setDateRange',
'removeStage', 'removeStage',
'updateStage', 'updateStage',
...@@ -146,8 +158,12 @@ export default { ...@@ -146,8 +158,12 @@ export default {
}, },
onStageSelect(stage) { onStageSelect(stage) {
this.hideForm(); this.hideForm();
this.setSelectedStage(stage); if (stage.slug === OVERVIEW_STAGE_ID) {
this.fetchStageData(this.selectedStage.slug); this.setDefaultSelectedStage();
} else {
this.setSelectedStage(stage);
this.fetchStageData(stage.slug);
}
}, },
onShowAddStageForm() { onShowAddStageForm() {
this.showCreateForm(); this.showCreateForm();
...@@ -235,7 +251,7 @@ export default { ...@@ -235,7 +251,7 @@ export default {
</div> </div>
</div> </div>
</div> </div>
<div v-if="!shouldRenderEmptyState" class="cycle-analytics gl-mt-0"> <div v-if="!shouldRenderEmptyState" class="cycle-analytics gl-mt-2">
<gl-empty-state <gl-empty-state
v-if="hasNoAccessError" v-if="hasNoAccessError"
class="js-empty-state" class="js-empty-state"
...@@ -248,8 +264,13 @@ export default { ...@@ -248,8 +264,13 @@ export default {
" "
/> />
<div v-else> <div v-else>
<metrics :group-path="currentGroupPath" :request-params="cycleAnalyticsRequestParams" /> <metrics
v-if="!featureFlags.hasPathNavigation || isOverviewStageSelected"
:group-path="currentGroupPath"
:request-params="cycleAnalyticsRequestParams"
/>
<stage-table <stage-table
v-if="!featureFlags.hasPathNavigation || !isOverviewStageSelected"
:key="stageCount" :key="stageCount"
class="js-stage-table" class="js-stage-table"
:current-stage="selectedStage" :current-stage="selectedStage"
......
...@@ -47,7 +47,7 @@ export default { ...@@ -47,7 +47,7 @@ export default {
</template> </template>
<gl-link :href="url" class="pipeline-id">#{{ id }}</gl-link> <gl-link :href="url" class="pipeline-id">#{{ id }}</gl-link>
<gl-icon :size="16" name="fork" /> <gl-icon :size="16" name="fork" />
<gl-link :href="branch.url" class="ref-name">{{ branch.name }}</gl-link> <gl-link v-if="branch" :href="branch.url" class="ref-name">{{ branch.name }}</gl-link>
<span class="icon-branch gl-text-gray-400"> <span class="icon-branch gl-text-gray-400">
<gl-icon name="commit" :size="14" /> <gl-icon name="commit" :size="14" />
</span> </span>
......
...@@ -61,3 +61,11 @@ export const OVERVIEW_METRICS = { ...@@ -61,3 +61,11 @@ export const OVERVIEW_METRICS = {
}; };
export const FETCH_VALUE_STREAM_DATA = 'fetchValueStreamData'; export const FETCH_VALUE_STREAM_DATA = 'fetchValueStreamData';
export const OVERVIEW_STAGE_ID = 'overview';
export const OVERVIEW_STAGE_CONFIG = {
id: OVERVIEW_STAGE_ID,
slug: OVERVIEW_STAGE_ID,
title: __('Overview'),
icon: 'home',
};
...@@ -2,7 +2,7 @@ import Api from 'ee/api'; ...@@ -2,7 +2,7 @@ import Api from 'ee/api';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import { FETCH_VALUE_STREAM_DATA } from '../constants'; import { FETCH_VALUE_STREAM_DATA, OVERVIEW_STAGE_CONFIG } from '../constants';
import { import {
removeFlash, removeFlash,
throwIfUserForbidden, throwIfUserForbidden,
...@@ -151,7 +151,11 @@ export const receiveGroupStagesError = ({ commit }, error) => { ...@@ -151,7 +151,11 @@ export const receiveGroupStagesError = ({ commit }, error) => {
createFlash(__('There was an error fetching value stream analytics stages.')); createFlash(__('There was an error fetching value stream analytics stages.'));
}; };
export const setDefaultSelectedStage = ({ dispatch, getters }) => { export const setDefaultSelectedStage = ({ dispatch, getters, state: { featureFlags } = {} }) => {
if (featureFlags?.hasPathNavigation) {
return dispatch('setSelectedStage', OVERVIEW_STAGE_CONFIG);
}
const { activeStages = [] } = getters; const { activeStages = [] } = getters;
if (activeStages?.length) { if (activeStages?.length) {
......
...@@ -4,7 +4,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils'; ...@@ -4,7 +4,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import { filterToQueryObject } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils'; import { filterToQueryObject } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { dateFormats } from '../../shared/constants'; import { dateFormats } from '../../shared/constants';
import { DEFAULT_VALUE_STREAM_ID } from '../constants'; import { DEFAULT_VALUE_STREAM_ID, OVERVIEW_STAGE_CONFIG } from '../constants';
import { transformStagesForPathNavigation } from '../utils'; import { transformStagesForPathNavigation } from '../utils';
export const hasNoAccessError = (state) => state.errorCode === httpStatus.FORBIDDEN; export const hasNoAccessError = (state) => state.errorCode === httpStatus.FORBIDDEN;
...@@ -64,7 +64,7 @@ export const customStageFormActive = ({ isCreatingCustomStage, isEditingCustomSt ...@@ -64,7 +64,7 @@ export const customStageFormActive = ({ isCreatingCustomStage, isEditingCustomSt
*/ */
export const pathNavigationData = ({ stages, medians, selectedStage }) => export const pathNavigationData = ({ stages, medians, selectedStage }) =>
transformStagesForPathNavigation({ transformStagesForPathNavigation({
stages: filterStagesByHiddenStatus(stages, false), stages: [OVERVIEW_STAGE_CONFIG, ...filterStagesByHiddenStatus(stages, false)],
medians, medians,
selectedStage, selectedStage,
}); });
...@@ -374,11 +374,10 @@ export const transformStagesForPathNavigation = ({ stages, medians, selectedStag ...@@ -374,11 +374,10 @@ export const transformStagesForPathNavigation = ({ stages, medians, selectedStag
}); });
return { return {
...stage,
metric: days ? sprintf(s__('ValueStreamAnalytics|%{days}d'), { days }) : null, metric: days ? sprintf(s__('ValueStreamAnalytics|%{days}d'), { days }) : null,
selected: stage.title === selectedStage.title, selected: stage.title === selectedStage.title,
title: stage.title,
icon: null, icon: null,
...stage,
}; };
}); });
......
---
title: Adds an overview stage to value stream analytics
merge_request: 56621
author:
type: added
...@@ -122,6 +122,10 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -122,6 +122,10 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
shared_examples 'group value stream analytics' do shared_examples 'group value stream analytics' do
context 'stage panel' do context 'stage panel' do
before do
select_stage("Issue")
end
it 'displays the stage table headers' do it 'displays the stage table headers' do
expect(page).to have_selector('.event-header', visible: true) expect(page).to have_selector('.event-header', visible: true)
expect(page).to have_selector('.total-time-header', visible: true) expect(page).to have_selector('.total-time-header', visible: true)
...@@ -155,10 +159,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -155,10 +159,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
end end
shared_examples 'has default filters' do shared_examples 'has default filters' do
it 'hides the empty state' do
expect(page).to have_selector('.row.empty-state', visible: false)
end
it 'shows the projects filter' do it 'shows the projects filter' do
expect(page).to have_selector('.dropdown-projects', visible: true) expect(page).to have_selector('.dropdown-projects', visible: true)
end end
...@@ -222,6 +222,8 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -222,6 +222,8 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
context 'with fake parameters' do context 'with fake parameters' do
before do before do
visit "#{group_analytics_cycle_analytics_path(group)}?beans=not-cool" visit "#{group_analytics_cycle_analytics_path(group)}?beans=not-cool"
select_stage("Issue")
end end
it_behaves_like 'empty state' it_behaves_like 'empty state'
...@@ -354,9 +356,14 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -354,9 +356,14 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
end end
end end
it 'will have data available' do it 'will not display the stage table on the overview stage' do
expect(page.find('[data-testid="vsa-stage-table"]')).not_to have_text(_("We don't have enough data to show this stage.")) expect(page).not_to have_selector('[data-testid="vsa-stage-table"]')
select_stage("Issue")
expect(page).to have_selector('[data-testid="vsa-stage-table"]')
end
it 'will have data available' do
duration_chart_content = page.find('[data-testid="vsa-duration-chart"]') duration_chart_content = page.find('[data-testid="vsa-duration-chart"]')
expect(duration_chart_content).not_to have_text(_("There is no data available. Please change your selection.")) expect(duration_chart_content).not_to have_text(_("There is no data available. Please change your selection."))
expect(duration_chart_content).to have_text(_('Total days to completion')) expect(duration_chart_content).to have_text(_('Total days to completion'))
...@@ -373,8 +380,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -373,8 +380,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
end end
it 'will filter the data' do it 'will filter the data' do
expect(page.find('[data-testid="vsa-stage-table"]')).to have_text(_("We don't have enough data to show this stage."))
duration_chart_content = page.find('[data-testid="vsa-duration-chart"]') duration_chart_content = page.find('[data-testid="vsa-duration-chart"]')
expect(duration_chart_content).not_to have_text(_('Total days to completion')) expect(duration_chart_content).not_to have_text(_('Total days to completion'))
expect(duration_chart_content).to have_text(_("There is no data available. Please change your selection.")) expect(duration_chart_content).to have_text(_("There is no data available. Please change your selection."))
......
...@@ -97,7 +97,7 @@ RSpec.describe 'Multiple value streams', :js do ...@@ -97,7 +97,7 @@ RSpec.describe 'Multiple value streams', :js do
create_value_stream create_value_stream
expect(page).to have_text(_("'%{name}' Value Stream created") % { name: custom_value_stream_name }) expect(page).to have_text(_("'%{name}' Value Stream created") % { name: custom_value_stream_name })
expect(page.all("[data-testid='gl-path-nav'] .gl-path-button").count).to eq(4) expect(page.find('[data-testid="gl-path-nav"]')).to have_text("Cool custom stage - name")
end end
end end
......
...@@ -32,6 +32,28 @@ exports[`PathNavigation displays correctly loading is false matches the snapshot ...@@ -32,6 +32,28 @@ exports[`PathNavigation displays correctly loading is false matches the snapshot
<li <li
class="gl-path-nav-list-item" class="gl-path-nav-list-item"
id="path-6-item-0" id="path-6-item-0"
>
<button
class="gl-path-button"
>
<svg
aria-hidden="true"
class="gl-mr-2 gl-icon s16"
data-testid="gl-path-item-icon"
>
<use
href="#home"
/>
</svg>
Overview
<!---->
</button>
</li>
<li
class="gl-path-nav-list-item"
id="path-6-item-1"
> >
<button <button
class="gl-path-button gl-path-active-item-indigo" class="gl-path-button gl-path-active-item-indigo"
...@@ -99,7 +121,7 @@ exports[`PathNavigation displays correctly loading is false matches the snapshot ...@@ -99,7 +121,7 @@ exports[`PathNavigation displays correctly loading is false matches the snapshot
</li> </li>
<li <li
class="gl-path-nav-list-item" class="gl-path-nav-list-item"
id="path-6-item-1" id="path-6-item-2"
> >
<button <button
class="gl-path-button" class="gl-path-button"
...@@ -167,7 +189,7 @@ exports[`PathNavigation displays correctly loading is false matches the snapshot ...@@ -167,7 +189,7 @@ exports[`PathNavigation displays correctly loading is false matches the snapshot
</li> </li>
<li <li
class="gl-path-nav-list-item" class="gl-path-nav-list-item"
id="path-6-item-2" id="path-6-item-3"
> >
<button <button
class="gl-path-button" class="gl-path-button"
......
...@@ -376,42 +376,55 @@ describe('Value Stream Analytics component', () => { ...@@ -376,42 +376,55 @@ describe('Value Stream Analytics component', () => {
displaysDateRangePicker(true); displaysDateRangePicker(true);
}); });
it('displays the filter bar', () => {
displaysFilterBar(true);
});
it('displays the metrics', () => { it('displays the metrics', () => {
displaysMetrics(true); displaysMetrics(true);
}); });
it('displays the stage table', () => { it('displays the type of work chart', () => {
displaysStageTable(true); displaysTypeOfWork(true);
}); });
it('displays the filter bar', () => { it('displays the duration chart', () => {
displaysFilterBar(true); displaysDurationChart(true);
}); });
it('displays the add stage button', async () => { it('hides the stage table', () => {
wrapper = await createComponent({ displaysStageTable(false);
opts: {
stubs: {
StageTable,
StageTableNav,
AddStageButton,
},
},
withStageSelected: true,
});
await wrapper.vm.$nextTick();
displaysAddStageButton(true);
}); });
it('displays the tasks by type chart', async () => { it('hides the add stage button', () => {
wrapper = await createComponent({ shallow: false, withStageSelected: true }); displaysAddStageButton(false);
await wrapper.vm.$nextTick();
expect(wrapper.find('.js-tasks-by-type-chart').exists()).toBe(true);
}); });
it('displays the duration chart', () => { describe('Without the overview stage selected', () => {
displaysDurationChart(true); beforeEach(async () => {
await store.dispatch('setSelectedStage', mockData.issueStage);
await wrapper.vm.$nextTick();
});
it('displays the stage table', () => {
displaysStageTable(true);
});
it('displays the add stage button', async () => {
wrapper = await createComponent({
opts: {
stubs: {
StageTable,
StageTableNav,
AddStageButton,
},
},
withStageSelected: true,
});
await wrapper.vm.$nextTick();
displaysAddStageButton(true);
});
}); });
describe('path navigation', () => { describe('path navigation', () => {
...@@ -463,7 +476,7 @@ describe('Value Stream Analytics component', () => { ...@@ -463,7 +476,7 @@ describe('Value Stream Analytics component', () => {
}); });
}); });
it('has the first stage selected by default', async () => { it('has the first stage selected by default', () => {
const first = findStageNavItemAtIndex(0); const first = findStageNavItemAtIndex(0);
const second = findStageNavItemAtIndex(1); const second = findStageNavItemAtIndex(1);
......
...@@ -63,9 +63,9 @@ describe('PathNavigation', () => { ...@@ -63,9 +63,9 @@ describe('PathNavigation', () => {
describe('popovers', () => { describe('popovers', () => {
const modifiedStages = [ const modifiedStages = [
...transformedStagePathData.slice(0, 2), ...transformedStagePathData.slice(0, 3),
{ {
...transformedStagePathData[2], ...transformedStagePathData[3],
startEventHtmlDescription: null, startEventHtmlDescription: null,
endEventHtmlDescription: null, endEventHtmlDescription: null,
}, },
...@@ -80,16 +80,16 @@ describe('PathNavigation', () => { ...@@ -80,16 +80,16 @@ describe('PathNavigation', () => {
}); });
it('shows the sanitized start event description for the first stage item', () => { it('shows the sanitized start event description for the first stage item', () => {
const firsPpopover = wrapper.findAll('[data-testid="stage-item-popover"]').at(0); const firstPopover = wrapper.findAll('[data-testid="stage-item-popover"]').at(0);
const expectedStartEventDescription = 'Issue created'; const expectedStartEventDescription = 'Issue created';
expect(firsPpopover.text()).toContain(expectedStartEventDescription); expect(firstPopover.text()).toContain(expectedStartEventDescription);
}); });
it('shows the sanitized end event description for the first stage item', () => { it('shows the sanitized end event description for the first stage item', () => {
const firsPpopover = wrapper.findAll('[data-testid="stage-item-popover"]').at(0); const firstPopover = wrapper.findAll('[data-testid="stage-item-popover"]').at(0);
const expectedStartEventDescription = const expectedStartEventDescription =
'Issue first associated with a milestone or issue first added to a board'; 'Issue first associated with a milestone or issue first added to a board';
expect(firsPpopover.text()).toContain(expectedStartEventDescription); expect(firstPopover.text()).toContain(expectedStartEventDescription);
}); });
}); });
}); });
......
...@@ -2,6 +2,7 @@ import { uniq } from 'lodash'; ...@@ -2,6 +2,7 @@ import { uniq } from 'lodash';
import { import {
DEFAULT_DAYS_IN_PAST, DEFAULT_DAYS_IN_PAST,
TASKS_BY_TYPE_SUBJECT_ISSUE, TASKS_BY_TYPE_SUBJECT_ISSUE,
OVERVIEW_STAGE_CONFIG,
} from 'ee/analytics/cycle_analytics/constants'; } from 'ee/analytics/cycle_analytics/constants';
import * as types from 'ee/analytics/cycle_analytics/store/mutation_types'; import * as types from 'ee/analytics/cycle_analytics/store/mutation_types';
import mutations from 'ee/analytics/cycle_analytics/store/mutations'; import mutations from 'ee/analytics/cycle_analytics/store/mutations';
...@@ -205,7 +206,7 @@ export const rawTasksByTypeData = transformRawTasksByTypeData(apiTasksByTypeData ...@@ -205,7 +206,7 @@ export const rawTasksByTypeData = transformRawTasksByTypeData(apiTasksByTypeData
export const transformedTasksByTypeData = getTasksByTypeData(apiTasksByTypeData); export const transformedTasksByTypeData = getTasksByTypeData(apiTasksByTypeData);
export const transformedStagePathData = transformStagesForPathNavigation({ export const transformedStagePathData = transformStagesForPathNavigation({
stages: allowedStages, stages: [OVERVIEW_STAGE_CONFIG, ...allowedStages],
medians, medians,
selectedStage: issueStage, selectedStage: issueStage,
}); });
......
import axios from 'axios'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { OVERVIEW_STAGE_CONFIG } from 'ee/analytics/cycle_analytics/constants';
import * as actions from 'ee/analytics/cycle_analytics/store/actions'; import * as actions from 'ee/analytics/cycle_analytics/store/actions';
import * as getters from 'ee/analytics/cycle_analytics/store/getters'; import * as getters from 'ee/analytics/cycle_analytics/store/getters';
import * as types from 'ee/analytics/cycle_analytics/store/mutation_types'; import * as types from 'ee/analytics/cycle_analytics/store/mutation_types';
...@@ -325,8 +326,6 @@ describe('Value Stream Analytics actions', () => { ...@@ -325,8 +326,6 @@ describe('Value Stream Analytics actions', () => {
}); });
describe('receiveCycleAnalyticsDataError', () => { describe('receiveCycleAnalyticsDataError', () => {
beforeEach(() => {});
it(`commits the ${types.RECEIVE_VALUE_STREAM_DATA_ERROR} mutation on a 403 response`, () => { it(`commits the ${types.RECEIVE_VALUE_STREAM_DATA_ERROR} mutation on a 403 response`, () => {
const response = { status: 403 }; const response = { status: 403 };
return testAction( return testAction(
...@@ -373,8 +372,6 @@ describe('Value Stream Analytics actions', () => { ...@@ -373,8 +372,6 @@ describe('Value Stream Analytics actions', () => {
}); });
describe('receiveGroupStagesSuccess', () => { describe('receiveGroupStagesSuccess', () => {
beforeEach(() => {});
it(`commits the ${types.RECEIVE_GROUP_STAGES_SUCCESS} mutation and dispatches 'setDefaultSelectedStage'`, () => { it(`commits the ${types.RECEIVE_GROUP_STAGES_SUCCESS} mutation and dispatches 'setDefaultSelectedStage'`, () => {
return testAction( return testAction(
actions.receiveGroupStagesSuccess, actions.receiveGroupStagesSuccess,
...@@ -392,39 +389,84 @@ describe('Value Stream Analytics actions', () => { ...@@ -392,39 +389,84 @@ describe('Value Stream Analytics actions', () => {
}); });
describe('setDefaultSelectedStage', () => { describe('setDefaultSelectedStage', () => {
it("dispatches the 'fetchStageData' action", () => { describe('when the `hasPathNavigation` feature flag is enabled', () => {
return testAction( beforeEach(() => {
actions.setDefaultSelectedStage, state = {
null, ...state,
state, featureFlags: {
[], ...state.featureFlags,
[ hasPathNavigation: true,
{ type: 'setSelectedStage', payload: selectedStage }, },
{ type: 'fetchStageData', payload: selectedStageSlug }, };
], });
);
});
it.each` afterEach(() => {
data mock.restore();
${[]} });
${null}
`('with $data will flash an error', ({ data }) => { it("dispatches the 'setSelectedStage' with the overview stage", () => {
actions.setDefaultSelectedStage({ getters: { activeStages: data }, dispatch: () => {} }, {}); return testAction(
shouldFlashAMessage(flashErrorMessage); actions.setDefaultSelectedStage,
null,
state,
[],
[{ type: 'setSelectedStage', payload: OVERVIEW_STAGE_CONFIG }],
);
});
}); });
it('will select the first active stage', () => { describe('when the `hasPathNavigation` feature flag is disabled', () => {
return testAction( beforeEach(() => {
actions.setDefaultSelectedStage, state = {
null, ...state,
state, featureFlags: {
[], ...state.featureFlags,
[ hasPathNavigation: false,
{ type: 'setSelectedStage', payload: stages[1] }, },
{ type: 'fetchStageData', payload: stages[1].slug }, };
], });
);
afterEach(() => {
mock.restore();
});
it("dispatches the 'fetchStageData' action", () => {
return testAction(
actions.setDefaultSelectedStage,
null,
state,
[],
[
{ type: 'setSelectedStage', payload: selectedStage },
{ type: 'fetchStageData', payload: selectedStageSlug },
],
);
});
it.each`
data
${[]}
${null}
`('with $data will flash an error', ({ data }) => {
actions.setDefaultSelectedStage(
{ getters: { activeStages: data }, dispatch: () => {} },
{},
);
shouldFlashAMessage(flashErrorMessage);
});
it('will select the first active stage', () => {
return testAction(
actions.setDefaultSelectedStage,
null,
state,
[],
[
{ type: 'setSelectedStage', payload: stages[1] },
{ type: 'fetchStageData', payload: stages[1].slug },
],
);
});
}); });
}); });
......
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