Commit b4758cfa authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

FE Edit custom stage

Added vuex actions, mutations and state to
edit custom cycle analytics stages. Additionally
the isAddingStage state was split into
isCreatingStage and isEditingStage to reflect the
states of the form
parent 357b9ec5
......@@ -55,8 +55,9 @@ export default {
'isLoadingChartData',
'isLoadingDurationChart',
'isEmptyStage',
'isAddingCustomStage',
'isSavingCustomStage',
'isCreatingCustomStage',
'isEditingCustomStage',
'selectedGroup',
'selectedStageId',
'stages',
......@@ -68,6 +69,7 @@ export default {
'startDate',
'endDate',
'tasksByType',
'customStageFormInitData',
]),
...mapGetters([
'currentStage',
......@@ -117,11 +119,12 @@ export default {
'showCustomStageForm',
'setDateRange',
'fetchTasksByTypeData',
'updateSelectedDurationChartStages',
'createCustomStage',
'updateStage',
'removeStage',
'updateSelectedDurationChartStages',
'setFeatureFlags',
'editCustomStage',
]),
onGroupSelect(group) {
this.setSelectedGroup(group);
......@@ -140,6 +143,9 @@ export default {
onShowAddStageForm() {
this.showCustomStageForm();
},
onShowEditStageForm(initData = {}) {
this.editCustomStage(initData);
},
initDateRange() {
const endDate = new Date(Date.now());
const startDate = getDateInPast(endDate, DEFAULT_DAYS_IN_PAST);
......@@ -243,15 +249,18 @@ export default {
:stages="stages"
:is-loading="isLoadingStage"
:is-empty-stage="isEmptyStage"
:is-adding-custom-stage="isAddingCustomStage"
:is-saving-custom-stage="isSavingCustomStage"
:is-creating-custom-stage="isCreatingCustomStage"
:is-editing-custom-stage="isEditingCustomStage"
:current-stage-events="currentStageEvents"
:custom-stage-form-events="customStageFormEvents"
:labels="labels"
:no-data-svg-path="noDataSvgPath"
:no-access-svg-path="noAccessSvgPath"
:can-edit-stages="hasCustomizableCycleAnalytics"
:custom-stage-form-init-data="customStageFormInitData"
@selectStage="onStageSelect"
@editStage="onShowEditStageForm"
@showAddStageForm="onShowAddStageForm"
@submit="onCreateCustomStage"
@hideStage="onUpdateStage"
......
......@@ -2,7 +2,9 @@
import { isEqual } from 'underscore';
import { GlButton, GlFormGroup, GlFormInput, GlFormSelect, GlLoadingIcon } from '@gitlab/ui';
import { s__ } from '~/locale';
import { convertToSnakeCase } from '~/lib/utils/text_utility';
import LabelsSelector from './labels_selector.vue';
import { STAGE_ACTIONS } from '../constants';
import {
isStartEvent,
isLabelEvent,
......@@ -13,13 +15,20 @@ import {
} from '../utils';
const initFields = {
name: '',
startEvent: '',
startEventLabel: null,
stopEvent: '',
stopEventLabel: null,
name: null,
startEventIdentifier: null,
startEventLabelId: null,
endEventIdentifier: null,
endEventLabelId: null,
};
// TODO: should be a util / use a util if exists...
const snakeFields = (fields = {}) =>
Object.entries(fields).reduce((acc, curr) => {
const [key, value] = curr;
return { ...acc, [convertToSnakeCase(key)]: value };
}, {});
export default {
components: {
GlButton,
......@@ -50,11 +59,16 @@ export default {
required: false,
default: false,
},
isEditingCustomStage: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
fields: {
...initFields,
...this.initialFields,
},
};
},
......@@ -65,30 +79,34 @@ export default {
...this.events.filter(isStartEvent).map(eventToOption),
];
},
stopEventOptions() {
const stopEvents = getAllowedEndEvents(this.events, this.fields.startEvent);
endEventOptions() {
const endEvents = getAllowedEndEvents(this.events, this.fields.startEventIdentifier);
return [
{ value: null, text: s__('CustomCycleAnalytics|Select stop event') },
...eventsByIdentifier(this.events, stopEvents).map(eventToOption),
...eventsByIdentifier(this.events, endEvents).map(eventToOption),
];
},
hasStartEvent() {
return this.fields.startEvent;
return this.fields.startEventIdentifier;
},
startEventRequiresLabel() {
return isLabelEvent(this.labelEvents, this.fields.startEvent);
return isLabelEvent(this.labelEvents, this.fields.startEventIdentifier);
},
stopEventRequiresLabel() {
return isLabelEvent(this.labelEvents, this.fields.stopEvent);
endEventRequiresLabel() {
return isLabelEvent(this.labelEvents, this.fields.endEventIdentifier);
},
isComplete() {
if (!this.hasValidStartAndStopEventPair) return false;
const requiredFields = [this.fields.startEvent, this.fields.stopEvent, this.fields.name];
if (!this.hasValidStartAndEndEventPair) return false;
const requiredFields = [
this.fields.startEventIdentifier,
this.fields.endEventIdentifier,
this.fields.name,
];
if (this.startEventRequiresLabel) {
requiredFields.push(this.fields.startEventLabel);
requiredFields.push(this.fields.startEventLabelId);
}
if (this.stopEventRequiresLabel) {
requiredFields.push(this.fields.stopEventLabel);
if (this.endEventRequiresLabel) {
requiredFields.push(this.fields.endEventLabelId);
}
return requiredFields.every(
fieldValue => fieldValue && (fieldValue.length > 0 || fieldValue > 0),
......@@ -97,21 +115,31 @@ export default {
isDirty() {
return !isEqual(this.initialFields, this.fields);
},
hasValidStartAndStopEventPair() {
hasValidStartAndEndEventPair() {
const {
fields: { startEvent, stopEvent },
fields: { startEventIdentifier, endEventIdentifier },
} = this;
if (startEvent && stopEvent) {
const stopEvents = getAllowedEndEvents(this.events, startEvent);
return stopEvents.length && stopEvents.includes(stopEvent);
if (startEventIdentifier && endEventIdentifier) {
const endEvents = getAllowedEndEvents(this.events, startEventIdentifier);
return endEvents.length && endEvents.includes(endEventIdentifier);
}
return true;
},
stopEventError() {
return !this.hasValidStartAndStopEventPair
endEventError() {
return !this.hasValidStartAndEndEventPair
? s__('CustomCycleAnalytics|Start event changed, please select a valid stop event')
: null;
},
saveStageText() {
return this.isEditingCustomStage
? s__('CustomCycleAnalytics|Edit stage')
: s__('CustomCycleAnalytics|Add stage');
},
formTitle() {
return this.isEditingCustomStage
? s__('CustomCycleAnalytics|Editing stage')
: s__('CustomCycleAnalytics|New stage');
},
},
mounted() {
this.labelEvents = getLabelEventsIdentifiers(this.events);
......@@ -122,14 +150,10 @@ export default {
this.$emit('cancel');
},
handleSave() {
const { startEvent, startEventLabel, stopEvent, stopEventLabel, name } = this.fields;
this.$emit('submit', {
name,
start_event_identifier: startEvent,
start_event_label_id: startEventLabel,
end_event_identifier: stopEvent,
end_event_label_id: stopEventLabel,
});
this.$emit(
this.isEditingCustomStage ? STAGE_ACTIONS.EDIT : STAGE_ACTIONS.SAVE,
snakeFields(this.fields),
);
},
handleSelectLabel(key, labelId = null) {
this.fields[key] = labelId;
......@@ -143,7 +167,7 @@ export default {
<template>
<form class="custom-stage-form m-4 mt-0">
<div class="mb-1">
<h4>{{ s__('CustomCycleAnalytics|New stage') }}</h4>
<h4>{{ formTitle }}</h4>
</div>
<gl-form-group :label="s__('CustomCycleAnalytics|Name')">
<gl-form-input
......@@ -159,8 +183,8 @@ export default {
<div :class="[startEventRequiresLabel ? 'w-50 mr-1' : 'w-100']">
<gl-form-group :label="s__('CustomCycleAnalytics|Start event')">
<gl-form-select
v-model="fields.startEvent"
name="custom-stage-start-event"
v-model="fields.startEventIdentifier"
name="add-stage-start-event"
:required="true"
:options="startEventOptions"
/>
......@@ -170,41 +194,41 @@ export default {
<gl-form-group :label="s__('CustomCycleAnalytics|Start event label')">
<labels-selector
:labels="labels"
:selected-label-id="fields.startEventLabel"
name="custom-stage-start-event-label"
@selectLabel="labelId => handleSelectLabel('startEventLabel', labelId)"
@clearLabel="handleClearLabel('startEventLabel')"
:selected-label-id="fields.startEventLabelId"
name="add-stage-start-event-label"
@selectLabel="labelId => handleSelectLabel('startEventLabelId', labelId)"
@clearLabel="handleClearLabel('startEventLabelId')"
/>
</gl-form-group>
</div>
</div>
<div class="d-flex" :class="{ 'justify-content-between': stopEventRequiresLabel }">
<div :class="[stopEventRequiresLabel ? 'w-50 mr-1' : 'w-100']">
<div class="d-flex" :class="{ 'justify-content-between': endEventRequiresLabel }">
<div :class="[endEventRequiresLabel ? 'w-50 mr-1' : 'w-100']">
<gl-form-group
:label="s__('CustomCycleAnalytics|Stop event')"
:description="
!hasStartEvent ? s__('CustomCycleAnalytics|Please select a start event first') : ''
"
:state="hasValidStartAndStopEventPair"
:invalid-feedback="stopEventError"
:state="hasValidStartAndEndEventPair"
:invalid-feedback="endEventError"
>
<gl-form-select
v-model="fields.stopEvent"
name="custom-stage-stop-event"
:options="stopEventOptions"
v-model="fields.endEventIdentifier"
name="add-stage-stop-event"
:options="endEventOptions"
:required="true"
:disabled="!hasStartEvent"
/>
</gl-form-group>
</div>
<div v-if="stopEventRequiresLabel" class="w-50 ml-1">
<div v-if="endEventRequiresLabel" class="w-50 ml-1">
<gl-form-group :label="s__('CustomCycleAnalytics|Stop event label')">
<labels-selector
:labels="labels"
:selected-label-id="fields.stopEventLabel"
name="custom-stage-stop-event-label"
@selectLabel="labelId => handleSelectLabel('stopEventLabel', labelId)"
@clearLabel="handleClearLabel('stopEventLabel')"
:selected-label-id="fields.endEventLabelId"
name="add-stage-stop-event-label"
@selectLabel="labelId => handleSelectLabel('endEventLabelId', labelId)"
@clearLabel="handleClearLabel('endEventLabelId')"
/>
</gl-form-group>
</div>
......@@ -213,7 +237,7 @@ export default {
<div class="custom-stage-form-actions">
<button
:disabled="!isDirty"
class="btn btn-cancel js-custom-stage-form-cancel"
class="btn btn-cancel js-save-stage-cancel"
type="button"
@click="handleCancel"
>
......@@ -222,11 +246,11 @@ export default {
<button
:disabled="!isComplete || !isDirty"
type="button"
class="js-custom-stage-form-submit btn btn-success"
class="js-save-stage btn btn-success"
@click="handleSave"
>
<gl-loading-icon v-if="isSavingCustomStage" size="sm" inline />
{{ s__('CustomCycleAnalytics|Add stage') }}
{{ saveStageText }}
</button>
</div>
</form>
......
......@@ -41,7 +41,11 @@ export default {
type: Boolean,
required: true,
},
isAddingCustomStage: {
isCreatingCustomStage: {
type: Boolean,
required: true,
},
isEditingCustomStage: {
type: Boolean,
required: true,
},
......@@ -73,6 +77,11 @@ export default {
type: Boolean,
required: true,
},
customStageFormInitData: {
type: Object,
required: false,
default: () => ({}),
},
},
computed: {
stageName() {
......@@ -147,12 +156,13 @@ export default {
:key="`ca-stage-title-${stage.title}`"
:title="stage.title"
:value="stage.value"
:is-active="!isAddingCustomStage && stage.id === currentStage.id"
:is-active="!isCreatingCustomStage && stage.id === currentStage.id"
:can-edit="canEditStages"
:is-default-stage="!stage.custom"
@select="$emit('selectStage', stage)"
@remove="removeStage(stage.id)"
@hide="hideStage(stage.id)"
@edit="$emit(STAGE_ACTIONS.EDIT, stageData)"
/>
<add-stage-button
v-if="canEditStages"
......@@ -164,11 +174,14 @@ export default {
<div class="section stage-events">
<gl-loading-icon v-if="isLoading" class="mt-4" size="md" />
<custom-stage-form
v-else-if="isAddingCustomStage"
v-else-if="isCreatingCustomStage || isEditingCustomStage"
:events="customStageFormEvents"
:labels="labels"
:is-saving-custom-stage="isSavingCustomStage"
:initial-fields="customStageFormInitData"
:is-editing-custom-stage="isEditingCustomStage"
@submit="$emit('submit', $event)"
@saveStage="saveStage"
/>
<template v-else>
<stage-event-list
......
......@@ -34,6 +34,7 @@ export const TASKS_BY_TYPE_SUBJECT_ISSUE = 'Issue';
export const TASKS_BY_TYPE_SUBJECT_MERGE_REQUEST = 'MergeRequest';
export const STAGE_ACTIONS = {
SELECT: 'selectStage',
EDIT: 'editStage',
REMOVE: 'removeStage',
SAVE: 'saveStage',
......
......@@ -83,6 +83,16 @@ export const fetchCycleAnalyticsData = ({ dispatch }) => {
.catch(error => dispatch('receiveCycleAnalyticsDataError', error));
};
export const hideCustomStageForm = ({ commit }) => commit(types.HIDE_CUSTOM_STAGE_FORM);
export const showCustomStageForm = ({ commit }) => commit(types.SHOW_CUSTOM_STAGE_FORM);
export const editCustomStage = ({ commit, dispatch }, initData = {}) => {
commit(types.EDIT_CUSTOM_STAGE, initData);
if (initData.id) {
dispatch('setSelectedStageId', initData.id);
}
};
export const requestSummaryData = ({ commit }) => commit(types.REQUEST_SUMMARY_DATA);
export const receiveSummaryDataError = ({ commit }, error) => {
......@@ -112,9 +122,6 @@ export const fetchSummaryData = ({ state, dispatch, getters }) => {
export const requestGroupStagesAndEvents = ({ commit }) =>
commit(types.REQUEST_GROUP_STAGES_AND_EVENTS);
export const hideCustomStageForm = ({ commit }) => commit(types.HIDE_CUSTOM_STAGE_FORM);
export const showCustomStageForm = ({ commit }) => commit(types.SHOW_CUSTOM_STAGE_FORM);
export const receiveGroupLabelsSuccess = ({ commit }, data) =>
commit(types.RECEIVE_GROUP_LABELS_SUCCESS, data);
......@@ -197,7 +204,6 @@ export const createCustomStage = ({ dispatch, state }, data) => {
const {
selectedGroup: { fullPath },
} = state;
dispatch('requestCreateCustomStage');
return Api.cycleAnalyticsCreateStage(fullPath, data)
......@@ -249,7 +255,7 @@ export const receiveUpdateStageSuccess = ({ commit, dispatch }) => {
commit(types.RECEIVE_UPDATE_STAGE_RESPONSE);
createFlash(__(`Stage data updated`), 'notice');
dispatch('fetchCycleAnalyticsData');
dispatch('fetchGroupStagesAndEvents');
};
export const receiveUpdateStageError = ({ commit }) => {
......
......@@ -18,6 +18,7 @@ export const RECEIVE_STAGE_DATA_ERROR = 'RECEIVE_STAGE_DATA_ERROR';
export const HIDE_CUSTOM_STAGE_FORM = 'HIDE_CUSTOM_STAGE_FORM';
export const SHOW_CUSTOM_STAGE_FORM = 'SHOW_CUSTOM_STAGE_FORM';
export const EDIT_CUSTOM_STAGE = 'EDIT_CUSTOM_STAGE';
export const REQUEST_GROUP_LABELS = 'REQUEST_GROUP_LABELS';
export const RECEIVE_GROUP_LABELS_SUCCESS = 'RECEIVE_GROUP_LABELS_SUCCESS';
......
......@@ -25,7 +25,8 @@ export default {
},
[types.REQUEST_CYCLE_ANALYTICS_DATA](state) {
state.isLoading = true;
state.isAddingCustomStage = false;
state.isCreatingCustomStage = false;
state.isEditingCustomStage = false;
},
[types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS](state) {
state.errorCode = null;
......@@ -75,8 +76,34 @@ export default {
labelIds: [],
};
},
[types.SHOW_CUSTOM_STAGE_FORM](state) {
state.isCreatingCustomStage = true;
state.customStageFormInitData = {};
},
[types.EDIT_CUSTOM_STAGE](state, initData) {
console.log('EDIT_CUSTOM_STAGE::initData', initData);
const {
title: name,
startEventIdentifier,
endEventIdentifier,
startEventLabelId,
endEventLabelId,
} = initData;
state.isEditingCustomStage = true;
state.customStageFormInitData = {
...state.customStageFormInitData,
name,
startEventIdentifier,
endEventIdentifier,
startEventLabelId,
endEventLabelId,
};
},
[types.HIDE_CUSTOM_STAGE_FORM](state) {
state.isAddingCustomStage = false;
state.isEditingCustomStage = false;
state.isCreatingCustomStage = false;
state.customStageFormInitData = {};
},
[types.SHOW_CUSTOM_STAGE_FORM](state) {
state.isAddingCustomStage = true;
......
......@@ -14,8 +14,9 @@ export default () => ({
isEmptyStage: false,
errorCode: null,
isAddingCustomStage: false,
isSavingCustomStage: false,
isCreatingCustomStage: false,
isEditingCustomStage: false,
selectedGroup: null,
selectedProjectIds: [],
......
import Vue from 'vue';
import { mount } from '@vue/test-utils';
import CustomStageForm from 'ee/analytics/cycle_analytics/components/custom_stage_form.vue';
import { STAGE_ACTIONS } from 'ee/analytics/cycle_analytics/constants';
import {
groupLabels,
customStageEvents as events,
......@@ -12,10 +13,10 @@ import {
const initData = {
name: 'Cool stage pre',
startEvent: labelStartEvent.identifier,
startEventLabel: groupLabels[0].id,
stopEvent: labelStopEvent.identifier,
stopEventLabel: groupLabels[1].id,
startEventIdentifier: labelStartEvent.identifier,
startEventLabelId: groupLabels[0].id,
endEventIdentifier: labelStopEvent.identifier,
endEventLabelId: groupLabels[1].id,
};
describe('CustomStageForm', () => {
......@@ -31,15 +32,16 @@ describe('CustomStageForm', () => {
}
let wrapper = null;
const findEvent = ev => wrapper.emitted()[ev];
const sel = {
name: '[name="custom-stage-name"]',
startEvent: '[name="custom-stage-start-event"]',
startEventLabel: '[name="custom-stage-start-event-label"]',
stopEvent: '[name="custom-stage-stop-event"]',
stopEventLabel: '[name="custom-stage-stop-event-label"]',
submit: '.js-custom-stage-form-submit',
cancel: '.js-custom-stage-form-cancel',
name: '[name="add-stage-name"]',
startEvent: '[name="add-stage-start-event"]',
startEventLabel: '[name="add-stage-start-event-label"]',
endEvent: '[name="add-stage-stop-event"]',
endEventLabel: '[name="add-stage-stop-event-label"]',
submit: '.js-save-stage',
cancel: '.js-save-stage-cancel',
invalidFeedback: '.invalid-feedback',
};
......@@ -66,7 +68,7 @@ describe('CustomStageForm', () => {
describe.each([
['Name', sel.name, true],
['Start event', sel.startEvent, true],
['Stop event', sel.stopEvent, false],
['Stop event', sel.endEvent, false],
['Submit', sel.submit, false],
['Cancel', sel.cancel, false],
])('by default', (field, $sel, enabledState) => {
......@@ -119,7 +121,7 @@ describe('CustomStageForm', () => {
it('will display the start event label field if a label event is selected', done => {
wrapper.setData({
fields: {
startEvent: labelStartEvent.identifier,
startEventIdentifier: labelStartEvent.identifier,
},
});
......@@ -129,9 +131,9 @@ describe('CustomStageForm', () => {
});
});
it('will set the "startEventLabel" field when selected', done => {
it('will set the "startEventLabelId" field when selected', done => {
const selectedLabelId = groupLabels[0].id;
expect(wrapper.vm.fields.startEventLabel).toEqual(null);
expect(wrapper.vm.fields.startEventLabelId).toEqual(null);
wrapper.find(sel.startEvent).setValue(labelStartEvent.identifier);
Vue.nextTick(() => {
......@@ -142,7 +144,7 @@ describe('CustomStageForm', () => {
.trigger('click');
Vue.nextTick(() => {
expect(wrapper.vm.fields.startEventLabel).toEqual(selectedLabelId);
expect(wrapper.vm.fields.startEventLabelId).toEqual(selectedLabelId);
done();
});
});
......@@ -171,7 +173,7 @@ describe('CustomStageForm', () => {
});
it('is enabled when a start event is selected', done => {
const el = wrapper.find(sel.stopEvent);
const el = wrapper.find(sel.endEvent);
expect(el.attributes('disabled')).toEqual('disabled');
selectDropdownOption(wrapper, sel.startEvent, 1);
......@@ -243,10 +245,10 @@ describe('CustomStageForm', () => {
wrapper.setData({
fields: {
name: 'Cool stage',
startEvent: 'issue_created',
startEventLabel: null,
stopEvent: 'issue_stage_end',
stopEventLabel: null,
startEventIdentifier: 'issue_created',
startEventLabelId: null,
endEventIdentifier: 'issue_stage_end',
endEventLabelId: null,
},
});
});
......@@ -270,15 +272,15 @@ describe('CustomStageForm', () => {
});
it('will update the list of stop events', done => {
const se = wrapper.vm.stopEventOptions;
const se = wrapper.vm.endEventOptions;
selectDropdownOption(wrapper, sel.startEvent, 2);
Vue.nextTick(() => {
expect(se[1].value).not.toEqual(wrapper.vm.stopEventOptions[1].value);
expect(se[1].value).not.toEqual(wrapper.vm.endEventOptions[1].value);
done();
});
});
it('will disable the submit button until a valid stopEvent is selected', done => {
it('will disable the submit button until a valid endEvent is selected', done => {
selectDropdownOption(wrapper, sel.startEvent, 2);
Vue.nextTick(() => {
expect(wrapper.find(sel.submit).attributes('disabled')).toEqual('disabled');
......@@ -301,41 +303,41 @@ describe('CustomStageForm', () => {
});
it('will display the stop event label field if a label event is selected', done => {
expect(wrapper.find(sel.stopEventLabel).exists()).toEqual(false);
expect(wrapper.find(sel.endEventLabel).exists()).toEqual(false);
wrapper.setData({
fields: {
stopEvent: labelStopEvent.identifier,
startEvent: labelStartEvent.identifier,
endEventIdentifier: labelStopEvent.identifier,
startEventIdentifier: labelStartEvent.identifier,
},
});
Vue.nextTick(() => {
expect(wrapper.find(sel.stopEventLabel).exists()).toEqual(true);
expect(wrapper.find(sel.endEventLabel).exists()).toEqual(true);
done();
});
});
it('will set the "stopEventLabel" field when selected', done => {
it('will set the "endEventLabelId" field when selected', done => {
const selectedLabelId = groupLabels[1].id;
expect(wrapper.vm.fields.stopEventLabel).toEqual(null);
expect(wrapper.vm.fields.endEventLabelId).toEqual(null);
wrapper.setData({
fields: {
startEvent: labelStartEvent.identifier,
stopEvent: labelStopEvent.identifier,
startEventIdentifier: labelStartEvent.identifier,
endEventIdentifier: labelStopEvent.identifier,
},
});
Vue.nextTick(() => {
wrapper
.find(sel.stopEventLabel)
.find(sel.endEventLabel)
.findAll('.dropdown-item')
.at(2) // item at index 0 is 'select a label'
.trigger('click');
Vue.nextTick(() => {
expect(wrapper.vm.fields.stopEventLabel).toEqual(selectedLabelId);
expect(wrapper.vm.fields.endEventLabelId).toEqual(selectedLabelId);
done();
});
});
......@@ -350,7 +352,7 @@ describe('CustomStageForm', () => {
selectDropdownOption(wrapper, sel.startEvent, 1);
return Vue.nextTick(() => {
selectDropdownOption(wrapper, sel.stopEvent, 1);
selectDropdownOption(wrapper, sel.endEvent, 1);
});
});
......@@ -358,6 +360,10 @@ describe('CustomStageForm', () => {
wrapper.destroy();
});
it('has text `Edit stage`', () => {
expect(wrapper.find(sel.submit).text('value')).toEqual('Add stage');
});
it('is enabled when all required fields are filled', done => {
const btn = wrapper.find(sel.submit);
......@@ -389,19 +395,23 @@ describe('CustomStageForm', () => {
wrapper.destroy();
});
it('emits a `submit` event when clicked', () => {
expect(wrapper.emitted().submit).toBeUndefined();
it(`emits a ${STAGE_ACTIONS.SAVE} event when clicked`, () => {
let event = findEvent(STAGE_ACTIONS.SAVE);
expect(event).toBeUndefined();
wrapper.find(sel.submit).trigger('click');
expect(wrapper.emitted().submit).toBeTruthy();
expect(wrapper.emitted().submit.length).toEqual(1);
event = findEvent(STAGE_ACTIONS.SAVE);
expect(event).toBeTruthy();
expect(event.length).toEqual(1);
});
it('`submit` event receives the latest data', () => {
expect(wrapper.emitted().submit).toBeUndefined();
const startEv = startEvents[startEventIndex];
const selectedStopEvent = getDropdownOption(wrapper, sel.stopEvent, stopEventIndex);
let event = findEvent(STAGE_ACTIONS.SAVE);
expect(event).toBeUndefined();
const res = [
{
name: 'Cool stage',
......@@ -413,7 +423,8 @@ describe('CustomStageForm', () => {
];
wrapper.find(sel.submit).trigger('click');
expect(wrapper.emitted().submit[0]).toEqual(res);
event = findEvent(STAGE_ACTIONS.SAVE);
expect(event[0]).toEqual(res);
});
});
});
......@@ -443,8 +454,8 @@ describe('CustomStageForm', () => {
wrapper.setData({
fields: {
name: 'Cool stage pre',
startEvent: labelStartEvent.identifier,
stopEvent: labelStopEvent.identifier,
startEventIdentifier: labelStartEvent.identifier,
endEventIdentifier: labelStopEvent.identifier,
},
});
......@@ -453,11 +464,11 @@ describe('CustomStageForm', () => {
Vue.nextTick(() => {
expect(wrapper.vm.fields).toEqual({
name: '',
startEvent: '',
startEventLabel: null,
stopEvent: '',
stopEventLabel: null,
name: null,
startEventIdentifier: null,
startEventLabelId: null,
endEventIdentifier: null,
endEventLabelId: null,
});
done();
});
......@@ -465,7 +476,8 @@ describe('CustomStageForm', () => {
});
it('will emit the `cancel` event when clicked', done => {
expect(wrapper.emitted().cancel).toBeUndefined();
let ev = findEvent('cancel');
expect(ev).toBeUndefined();
wrapper.setData({
fields: {
......@@ -477,8 +489,9 @@ describe('CustomStageForm', () => {
wrapper.find(sel.cancel).trigger('click');
Vue.nextTick(() => {
expect(wrapper.emitted().cancel).toBeTruthy();
expect(wrapper.emitted().cancel.length).toEqual(1);
ev = findEvent('cancel');
expect(ev).toBeTruthy();
expect(ev.length).toEqual(1);
done();
});
});
......@@ -486,10 +499,11 @@ describe('CustomStageForm', () => {
});
});
describe('Prepopulated form', () => {
describe('Editing a custom stage', () => {
beforeEach(() => {
wrapper = createComponent(
{
isEditingCustomStage: true,
initialFields: {
...initData,
},
......@@ -515,8 +529,8 @@ describe('CustomStageForm', () => {
wrapper.setData({
fields: {
name: 'Cool stage pre',
startEvent: labelStartEvent.identifier,
stopEvent: labelStopEvent.identifier,
startEventIdentifier: labelStartEvent.identifier,
endEventIdentifier: labelStopEvent.identifier,
},
});
......@@ -533,7 +547,11 @@ describe('CustomStageForm', () => {
});
});
describe('Add stage button', () => {
describe('Edit stage button', () => {
it('has text `Edit stage`', () => {
expect(wrapper.find(sel.submit).text('value')).toEqual('Edit stage');
});
it('is disabled by default', () => {
expect(wrapper.find(sel.submit).attributes('disabled')).toEqual('disabled');
});
......@@ -564,8 +582,9 @@ describe('CustomStageForm', () => {
});
});
it('emits a `submit` event when clicked', done => {
expect(wrapper.emitted().submit).toBeUndefined();
it(`emits a ${STAGE_ACTIONS.EDIT} event when clicked`, done => {
let ev = findEvent(STAGE_ACTIONS.EDIT);
expect(ev).toBeUndefined();
wrapper.setData({
fields: {
......@@ -577,8 +596,9 @@ describe('CustomStageForm', () => {
wrapper.find(sel.submit).trigger('click');
Vue.nextTick(() => {
expect(wrapper.emitted().submit).toBeTruthy();
expect(wrapper.emitted().submit.length).toEqual(1);
ev = findEvent(STAGE_ACTIONS.EDIT);
expect(ev).toBeTruthy();
expect(ev.length).toEqual(1);
done();
});
});
......@@ -595,7 +615,7 @@ describe('CustomStageForm', () => {
wrapper.find(sel.submit).trigger('click');
Vue.nextTick(() => {
const submitted = wrapper.emitted().submit[0];
const submitted = findEvent(STAGE_ACTIONS.EDIT)[0];
expect(submitted).not.toEqual([initData]);
expect(submitted).toEqual([
{
......@@ -606,6 +626,7 @@ describe('CustomStageForm', () => {
name: 'Cool updated form',
},
]);
done();
});
});
......
......@@ -36,8 +36,9 @@ function createComponent(props = {}, shallow = false) {
isLoading: false,
isLoadingSummaryData: false,
isEmptyStage: false,
isAddingCustomStage: false,
isSavingCustomStage: false,
isCreatingCustomStage: false,
isEditingCustomStage: false,
noDataSvgPath,
noAccessSvgPath,
canEditStages: false,
......
......@@ -33,8 +33,9 @@ describe('Cycle analytics mutations', () => {
it.each`
mutation | stateKey | value
${types.HIDE_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${false}
${types.SHOW_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${true}
${types.HIDE_CUSTOM_STAGE_FORM} | ${'isCreatingCustomStage'} | ${false}
${types.SHOW_CUSTOM_STAGE_FORM} | ${'isCreatingCustomStage'} | ${true}
${types.EDIT_CUSTOM_STAGE} | ${'isEditingCustomStage'} | ${true}
${types.REQUEST_STAGE_DATA} | ${'isLoadingStage'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isLoadingStage'} | ${false}
......
......@@ -5196,6 +5196,12 @@ msgstr ""
msgid "CustomCycleAnalytics|Add stage"
msgstr ""
msgid "CustomCycleAnalytics|Edit stage"
msgstr ""
msgid "CustomCycleAnalytics|Editing stage"
msgstr ""
msgid "CustomCycleAnalytics|Enter a name for the stage"
msgstr ""
......
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