Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
817f6d4d
Commit
817f6d4d
authored
May 15, 2020
by
Ezekiel Kigbo
Committed by
Illya Klymov
May 15, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move custom stage specs to folder
Moves the specs specifically for custom stages into a separate dir
parent
f35bf8cb
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
590 additions
and
426 deletions
+590
-426
ee/app/assets/javascripts/analytics/cycle_analytics/components/base.vue
...javascripts/analytics/cycle_analytics/components/base.vue
+4
-18
ee/app/assets/javascripts/analytics/cycle_analytics/components/custom_stage_form.vue
...nalytics/cycle_analytics/components/custom_stage_form.vue
+66
-76
ee/app/assets/javascripts/analytics/cycle_analytics/components/stage_table_nav.vue
.../analytics/cycle_analytics/components/stage_table_nav.vue
+1
-5
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/actions.js
...cs/cycle_analytics/store/modules/custom_stages/actions.js
+4
-1
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/mutation_types.js
...e_analytics/store/modules/custom_stages/mutation_types.js
+2
-1
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/mutations.js
.../cycle_analytics/store/modules/custom_stages/mutations.js
+6
-1
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/state.js
...tics/cycle_analytics/store/modules/custom_stages/state.js
+1
-0
ee/spec/frontend/analytics/cycle_analytics/components/custom_stage_form_spec.js
...tics/cycle_analytics/components/custom_stage_form_spec.js
+149
-94
ee/spec/frontend/analytics/cycle_analytics/mock_data.js
ee/spec/frontend/analytics/cycle_analytics/mock_data.js
+2
-2
ee/spec/frontend/analytics/cycle_analytics/store/actions_spec.js
.../frontend/analytics/cycle_analytics/store/actions_spec.js
+0
-164
ee/spec/frontend/analytics/cycle_analytics/store/modules/custom_stages/actions_spec.js
...cle_analytics/store/modules/custom_stages/actions_spec.js
+261
-0
ee/spec/frontend/analytics/cycle_analytics/store/modules/custom_stages/getters_spec.js
...cle_analytics/store/modules/custom_stages/getters_spec.js
+15
-0
ee/spec/frontend/analytics/cycle_analytics/store/modules/custom_stages/mutations_spec.js
...e_analytics/store/modules/custom_stages/mutations_spec.js
+78
-0
ee/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
...rontend/analytics/cycle_analytics/store/mutations_spec.js
+1
-64
No files found.
ee/app/assets/javascripts/analytics/cycle_analytics/components/base.vue
View file @
817f6d4d
...
...
@@ -70,14 +70,9 @@ export default {
'
endDate
'
,
'
medians
'
,
]),
...
mapState
(
'
customStages
'
,
[
'
isSavingCustomStage
'
,
'
isCreatingCustomStage
'
,
'
isEditingCustomStage
'
,
'
formEvents
'
,
'
formErrors
'
,
'
formInitialData
'
,
]),
// NOTE: formEvents are fetched in the same request as the list of stages (fetchGroupStagesAndEvents)
// so i think its ok to bind formEvents here even though its only used as a prop to the custom-stage-form
...
mapState
(
'
customStages
'
,
[
'
isCreatingCustomStage
'
,
'
formEvents
'
]),
...
mapGetters
([
'
hasNoAccessError
'
,
'
currentGroupPath
'
,
...
...
@@ -106,9 +101,6 @@ export default {
isLoadingTypeOfWork
()
{
return
this
.
isLoadingTasksByTypeChartTopLabels
||
this
.
isLoadingTasksByTypeChart
;
},
isUpdatingCustomStage
()
{
return
this
.
isEditingCustomStage
&&
this
.
isSavingCustomStage
;
},
hasDateRangeSet
()
{
return
this
.
startDate
&&
this
.
endDate
;
},
...
...
@@ -169,6 +161,7 @@ export default {
this
.
showCreateForm
();
},
onShowEditStageForm
(
initData
=
{})
{
this
.
setSelectedStage
(
initData
);
this
.
showEditForm
(
initData
);
},
onCreateCustomStage
(
data
)
{
...
...
@@ -299,7 +292,6 @@ export default {
:stages=
"activeStages"
:medians=
"medians"
:is-creating-custom-stage=
"isCreatingCustomStage"
:custom-stage-form-active=
"customStageFormActive"
:can-edit-stages=
"true"
:custom-ordering=
"enableCustomOrdering"
@
reorderStage=
"onStageReorder"
...
...
@@ -311,14 +303,8 @@ export default {
/>
</
template
>
<
template
v-if=
"customStageFormActive"
#content
>
<gl-loading-icon
v-if=
"isUpdatingCustomStage"
class=
"mt-4"
size=
"md"
/>
<custom-stage-form
v-else
:events=
"formEvents"
:is-saving-custom-stage=
"isSavingCustomStage"
:initial-fields=
"formInitialData"
:is-editing-custom-stage=
"isEditingCustomStage"
:errors=
"formErrors"
@
createStage=
"onCreateCustomStage"
@
updateStage=
"onUpdateCustomStage"
@
clearErrors=
"$emit('clearFormErrors')"
...
...
ee/app/assets/javascripts/analytics/cycle_analytics/components/custom_stage_form.vue
View file @
817f6d4d
<
script
>
import
{
mapGetters
}
from
'
vuex
'
;
import
{
mapGetters
,
mapState
}
from
'
vuex
'
;
import
{
isEqual
}
from
'
lodash
'
;
import
{
GlFormGroup
,
...
...
@@ -33,23 +33,37 @@ const defaultFields = {
endEventLabelId
:
null
,
};
export
const
initializeFormData
=
({
emptyFieldState
,
initialFields
,
errors
})
=>
{
const
defaultErrors
=
initialFields
?.
endEventIdentifier
?
{
...
emptyFieldState
,
endEventIdentifier
:
null
}
const
defaultErrors
=
{
id
:
[],
name
:
[],
startEventIdentifier
:
[],
startEventLabelId
:
[],
endEventIdentifier
:
[],
endEventLabelId
:
[],
};
const
ERRORS
=
{
START_EVENT_REQUIRED
:
s__
(
'
CustomCycleAnalytics|Please select a start event first
'
),
STAGE_NAME_EXISTS
:
s__
(
'
CustomCycleAnalytics|Stage name already exists
'
),
INVALID_EVENT_PAIRS
:
s__
(
'
CustomCycleAnalytics|Start event changed, please select a valid stop event
'
,
),
};
export
const
initializeFormData
=
({
emptyFieldState
=
defaultFields
,
fields
,
errors
})
=>
{
const
initErrors
=
fields
?.
endEventIdentifier
?
defaultErrors
:
{
...
emptyFieldState
,
endEventIdentifier
:
initialFields
&&
!
initialFields
.
startEventIdentifier
?
[
s__
(
'
CustomCycleAnalytics|Please select a start event first
'
)]
:
null
,
...
defaultErrors
,
endEventIdentifier
:
!
fields
?.
startEventIdentifier
?
[
ERRORS
.
START_EVENT_REQUIRED
]
:
[],
};
return
{
fields
:
{
...
emptyFieldState
,
...
initialF
ields
,
...
f
ields
,
},
fieldE
rrors
:
{
...
defaul
tErrors
,
e
rrors
:
{
...
ini
tErrors
,
...
errors
,
},
};
...
...
@@ -72,42 +86,23 @@ export default {
type
:
Array
,
required
:
true
,
},
initialFields
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
{},
},
isSavingCustomStage
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
isEditingCustomStage
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
errors
:
{
type
:
Object
,
required
:
false
,
default
:
null
,
},
},
data
()
{
const
{
initialFields
=
{},
errors
=
null
}
=
this
;
const
{
fields
,
fieldErrors
}
=
initializeFormData
({
emptyFieldState
:
defaultFields
,
initialFields
,
errors
,
});
return
{
labelEvents
:
getLabelEventsIdentifiers
(
this
.
events
),
fields
,
fieldErrors
,
fields
:
{}
,
errors
:
[]
,
};
},
computed
:
{
...
mapGetters
([
'
hiddenStages
'
]),
...
mapState
(
'
customStages
'
,
[
'
isLoading
'
,
'
isSavingCustomStage
'
,
'
isEditingCustomStage
'
,
'
formInitialData
'
,
'
formErrors
'
,
]),
startEventOptions
()
{
return
[
{
value
:
null
,
text
:
s__
(
'
CustomCycleAnalytics|Select start event
'
)
},
...
...
@@ -132,8 +127,7 @@ export default {
},
hasErrors
()
{
return
(
this
.
eventMismatchError
||
Object
.
values
(
this
.
fieldErrors
).
some
(
errArray
=>
errArray
?.
length
)
this
.
eventMismatchError
||
Object
.
values
(
this
.
errors
).
some
(
errArray
=>
errArray
?.
length
)
);
},
isComplete
()
{
...
...
@@ -162,7 +156,7 @@ export default {
);
},
isDirty
()
{
return
!
isEqual
(
this
.
initialFields
,
this
.
fields
)
&&
!
isEqual
(
defaultFields
,
this
.
f
ields
);
return
!
isEqual
(
this
.
fields
,
this
.
formInitialData
||
defaultF
ields
);
},
eventMismatchError
()
{
const
{
...
...
@@ -188,35 +182,39 @@ export default {
},
},
watch
:
{
initialFields
(
newFields
)
{
formInitialData
(
newFields
=
{}
)
{
this
.
fields
=
{
...
defaultFields
,
...
newFields
,
};
},
errors
(
newErrors
)
{
this
.
fieldErrors
=
{
...
defaultFields
,
formErrors
(
newErrors
=
{})
{
this
.
errors
=
{
...
newErrors
,
};
},
},
mounted
()
{
this
.
resetFields
();
},
methods
:
{
handleCancel
()
{
const
{
initialFields
=
{},
errors
=
null
}
=
this
;
const
formData
=
initializeFormData
({
emptyFieldState
:
defaultFields
,
initialFields
,
errors
,
resetFields
()
{
const
{
formInitialData
,
formErrors
}
=
this
;
const
{
fields
,
errors
}
=
initializeFormData
({
fields
:
formInitialData
,
errors
:
formErrors
,
});
this
.
$set
(
this
,
'
fields
'
,
formData
.
fields
);
this
.
$set
(
this
,
'
fieldErrors
'
,
formData
.
fieldErrors
);
this
.
fields
=
{
...
fields
};
this
.
errors
=
{
...
errors
};
},
handleCancel
()
{
this
.
resetFields
();
this
.
$emit
(
'
cancel
'
);
},
handleSave
()
{
const
data
=
convertObjectPropsToSnakeCase
(
this
.
fields
);
if
(
this
.
isEditingCustomStage
)
{
const
{
id
}
=
this
.
initialF
ields
;
const
{
id
}
=
this
.
f
ields
;
this
.
$emit
(
STAGE_ACTIONS
.
UPDATE
,
{
...
data
,
id
});
}
else
{
this
.
$emit
(
STAGE_ACTIONS
.
CREATE
,
data
);
...
...
@@ -229,31 +227,22 @@ export default {
this
.
fields
[
key
]
=
null
;
},
hasFieldErrors
(
key
)
{
return
this
.
fieldE
rrors
[
key
]?.
length
>
0
;
return
this
.
e
rrors
[
key
]?.
length
>
0
;
},
fieldErrorMessage
(
key
)
{
return
this
.
fieldE
rrors
[
key
]?.
join
(
'
\n
'
);
return
this
.
e
rrors
[
key
]?.
join
(
'
\n
'
);
},
onUpdateNameField
()
{
if
(
DEFAULT_STAGE_NAMES
.
includes
(
this
.
fields
.
name
.
toLowerCase
()))
{
this
.
$set
(
this
.
fieldErrors
,
'
name
'
,
[
s__
(
'
CustomCycleAnalytics|Stage name already exists
'
),
]);
}
else
{
this
.
$set
(
this
.
fieldErrors
,
'
name
'
,
[]);
}
this
.
errors
.
name
=
DEFAULT_STAGE_NAMES
.
includes
(
this
.
fields
.
name
.
toLowerCase
())
?
[
ERRORS
.
STAGE_NAME_EXISTS
]
:
[];
},
onUpdateStartEventField
()
{
const
initVal
=
this
.
initialFields
?.
endEventIdentifier
?
this
.
initialFields
.
endEventIdentifier
:
null
;
this
.
$set
(
this
.
fields
,
'
endEventIdentifier
'
,
initVal
);
this
.
$set
(
this
.
fieldErrors
,
'
endEventIdentifier
'
,
[
s__
(
'
CustomCycleAnalytics|Start event changed, please select a valid stop event
'
),
]);
this
.
fields
.
endEventIdentifier
=
null
;
this
.
errors
.
endEventIdentifier
=
[
ERRORS
.
INVALID_EVENT_PAIRS
];
},
onUpdateEndEventField
()
{
this
.
$set
(
this
.
fieldErrors
,
'
endEventIdentifier
'
,
null
)
;
this
.
errors
.
endEventIdentifier
=
[]
;
},
handleRecoverStage
(
id
)
{
this
.
$emit
(
STAGE_ACTIONS
.
UPDATE
,
{
id
,
hidden
:
false
});
...
...
@@ -262,7 +251,10 @@ export default {
};
</
script
>
<
template
>
<form
class=
"custom-stage-form m-4 mt-0"
>
<div
v-if=
"isLoading"
>
<gl-loading-icon
class=
"mt-4"
size=
"md"
/>
</div>
<form
v-else
class=
"custom-stage-form m-4 mt-0"
>
<div
class=
"mb-1 d-flex flex-row justify-content-between"
>
<h4>
{{
formTitle
}}
</h4>
<gl-dropdown
:text=
"__('Recover hidden stage')"
class=
"js-recover-hidden-stage-dropdown"
>
...
...
@@ -366,7 +358,6 @@ export default {
</gl-form-group>
</div>
</div>
<div
class=
"custom-stage-form-actions"
>
<button
:disabled=
"!isDirty"
...
...
@@ -386,7 +377,6 @@ export default {
{{ saveStageText }}
</button>
</div>
<div
class=
"mt-2"
>
<gl-sprintf
:message=
"
...
...
ee/app/assets/javascripts/analytics/cycle_analytics/components/stage_table_nav.vue
View file @
817f6d4d
...
...
@@ -29,10 +29,6 @@ export default {
type
:
Boolean
,
required
:
true
,
},
customStageFormActive
:
{
type
:
Boolean
,
required
:
true
,
},
canEditStages
:
{
type
:
Boolean
,
required
:
true
,
...
...
@@ -106,7 +102,7 @@ export default {
<add-stage-button
v-if=
"canEditStages"
:class=
"$options.noDragClass"
:active=
"
customStageFormActiv
e"
:active=
"
isCreatingCustomStag
e"
@
showform=
"$emit('showAddStageForm')"
/>
</ul>
...
...
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/actions.js
View file @
817f6d4d
...
...
@@ -15,15 +15,18 @@ export const hideForm = ({ commit }) => {
};
export
const
showCreateForm
=
({
commit
})
=>
{
commit
(
types
.
SET_LOADING
);
commit
(
types
.
SET_FORM_INITIAL_DATA
);
commit
(
types
.
SHOW_CREATE_FORM
);
removeFlash
();
};
export
const
showEditForm
=
({
commit
,
dispatch
},
selectedStage
=
{})
=>
{
commit
(
types
.
SET_LOADING
);
commit
(
types
.
SET_FORM_INITIAL_DATA
,
selectedStage
);
commit
(
types
.
SHOW_EDIT_FORM
);
dispatch
(
'
setSelectedStage
'
,
selectedStage
,
{
root
:
true
});
dispatch
(
'
clearSavingCustomStage
'
);
commit
(
types
.
SHOW_EDIT_FORM
);
removeFlash
();
};
...
...
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/mutation_types.js
View file @
817f6d4d
export
const
SET_LOADING
=
'
SET_LOADING
'
;
export
const
SET_STAGE_EVENTS
=
'
SET_STAGE_EVENTS
'
;
export
const
SET_STAGE_FORM_ERRORS
=
'
SET_STAGE_FORM_ERRORS
'
;
export
const
SET_FORM_INITIAL_DATA
=
'
SET_FORM_INITIAL_DATA
'
;
export
const
SET_SAVING_CUSTOM_STAGE
=
'
SET_SAVING_CUSTOM_STAGE
'
;
export
const
CLEAR_SAVING_CUSTOM_STAGE
=
'
CLEAR_SAVING_CUSTOM_STAGE
'
;
export
const
HIDE_FORM
=
'
SHOW
_FORM
'
;
export
const
HIDE_FORM
=
'
HIDE
_FORM
'
;
export
const
SHOW_CREATE_FORM
=
'
SHOW_CREATE_FORM
'
;
export
const
SHOW_EDIT_FORM
=
'
SHOW_EDIT_FORM
'
;
export
const
CLEAR_FORM_ERRORS
=
'
CLEAR_FORM_ERRORS
'
;
...
...
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/mutations.js
View file @
817f6d4d
...
...
@@ -31,21 +31,26 @@ export default {
state
.
formErrors
=
convertObjectPropsToCamelCase
(
errors
,
{
deep
:
true
});
},
[
types
.
SET_FORM_INITIAL_DATA
](
state
,
rawStageData
=
null
)
{
state
.
formInitialData
=
extractFormFields
(
rawStageData
)
;
state
.
formInitialData
=
rawStageData
?
extractFormFields
(
rawStageData
)
:
null
;
},
[
types
.
SET_SAVING_CUSTOM_STAGE
](
state
)
{
state
.
isSavingCustomStage
=
true
;
},
[
types
.
SET_LOADING
](
state
)
{
state
.
isLoadingCustomStage
=
true
;
},
[
types
.
CLEAR_SAVING_CUSTOM_STAGE
](
state
)
{
state
.
isSavingCustomStage
=
false
;
},
[
types
.
SHOW_CREATE_FORM
](
state
)
{
state
.
isLoadingCustomStage
=
false
;
state
.
isEditingCustomStage
=
false
;
state
.
isCreatingCustomStage
=
true
;
state
.
formInitialData
=
null
;
state
.
formErrors
=
null
;
},
[
types
.
SHOW_EDIT_FORM
](
state
)
{
state
.
isLoadingCustomStage
=
false
;
state
.
isCreatingCustomStage
=
false
;
state
.
isEditingCustomStage
=
true
;
state
.
formErrors
=
null
;
...
...
ee/app/assets/javascripts/analytics/cycle_analytics/store/modules/custom_stages/state.js
View file @
817f6d4d
export
default
()
=>
({
isLoadingCustomStage
:
false
,
isSavingCustomStage
:
false
,
isCreatingCustomStage
:
false
,
isEditingCustomStage
:
false
,
...
...
ee/spec/frontend/analytics/cycle_analytics/components/custom_stage_form_spec.js
View file @
817f6d4d
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
axios
from
'
axios
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
c
reateStore
from
'
ee/analytics/cycle_analytics/store
'
;
import
c
ustomStagesStore
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages
'
;
import
{
createLocalVue
,
mount
}
from
'
@vue/test-utils
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
CustomStageForm
,
{
...
...
@@ -20,7 +19,7 @@ import {
customStageFormErrors
,
}
from
'
../mock_data
'
;
const
init
Data
=
{
const
formInitial
Data
=
{
id
:
74
,
name
:
'
Cool stage pre
'
,
startEventIdentifier
:
labelStartEvent
.
identifier
,
...
...
@@ -32,16 +31,37 @@ const initData = {
const
MERGE_REQUEST_CREATED
=
'
merge_request_created
'
;
const
MERGE_REQUEST_CLOSED
=
'
merge_request_closed
'
;
let
store
=
null
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
const
fakeStore
=
({
initialState
,
initialRootGetters
})
=>
new
Vuex
.
Store
({
getters
:
{
currentGroupPath
:
()
=>
'
fake
'
,
hiddenStages
:
()
=>
[],
...
initialRootGetters
,
},
modules
:
{
customStages
:
{
...
customStagesStore
,
state
:
{
isLoading
:
false
,
...
initialState
,
},
},
},
});
describe
(
'
CustomStageForm
'
,
()
=>
{
function
createComponent
(
props
=
{},
stubs
=
{})
{
store
=
createStore
();
function
createComponent
({
initialState
=
{},
initialRootGetters
=
{},
stubs
=
{},
props
=
{},
}
=
{})
{
return
mount
(
CustomStageForm
,
{
localVue
,
store
,
store
:
fakeStore
({
initialState
,
initialRootGetters
})
,
propsData
:
{
events
,
...
props
,
...
...
@@ -98,7 +118,7 @@ describe('CustomStageForm', () => {
stopEventDropdownIndex
=
mergeRequestClosedDropdownIndex
,
}
=
{})
{
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
startEventDropdownIndex
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
selectDropdownOption
(
wrapper
,
sel
.
endEvent
,
stopEventDropdownIndex
);
});
}
...
...
@@ -117,7 +137,7 @@ describe('CustomStageForm', () => {
beforeEach
(()
=>
{
mock
=
mockGroupLabelsRequest
();
wrapper
=
createComponent
(
{}
);
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
...
...
@@ -155,7 +175,7 @@ describe('CustomStageForm', () => {
describe
(
'
Name
'
,
()
=>
{
describe
(
'
with a reserved name
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
(
{}
);
wrapper
=
createComponent
();
return
setNameField
(
wrapper
,
'
issue
'
);
});
...
...
@@ -174,7 +194,7 @@ describe('CustomStageForm', () => {
describe
(
'
Start event
'
,
()
=>
{
describe
(
'
with events
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
(
{}
);
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
...
...
@@ -229,7 +249,7 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
sel
.
startEventLabel
).
exists
()).
toEqual
(
true
);
});
});
...
...
@@ -246,7 +266,7 @@ describe('CustomStageForm', () => {
.
findAll
(
'
.dropdown-item
'
)
.
at
(
1
)
// item at index 0 is 'select a label'
.
trigger
(
'
click
'
);
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
})
.
then
(()
=>
{
expect
(
wrapper
.
vm
.
fields
.
startEventLabelId
).
toEqual
(
selectedLabelId
);
...
...
@@ -265,12 +285,14 @@ describe('CustomStageForm', () => {
});
it
(
'
notifies that a start event needs to be selected first
'
,
()
=>
{
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
wrapper
.
text
()).
toContain
(
'
Please select a start event first
'
);
});
});
it
(
'
clears notification when a start event is selected
'
,
()
=>
{
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
startEventDropdownIndex
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
text
()).
not
.
toContain
(
'
Please select a start event first
'
);
});
});
...
...
@@ -280,7 +302,7 @@ describe('CustomStageForm', () => {
expect
(
el
.
attributes
(
'
disabled
'
)).
toEqual
(
'
disabled
'
);
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
startEventDropdownIndex
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
el
.
attributes
(
'
disabled
'
)).
toBeUndefined
();
});
});
...
...
@@ -292,7 +314,7 @@ describe('CustomStageForm', () => {
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
startEventDropdownIndex
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
stopOptions
=
wrapper
.
find
(
sel
.
endEvent
);
selectedStartEvent
.
allowedEndEvents
.
forEach
(
identifier
=>
{
expect
(
stopOptions
.
html
()).
toContain
(
identifier
);
...
...
@@ -308,7 +330,7 @@ describe('CustomStageForm', () => {
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
startEventDropdownIndex
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
stopOptions
=
wrapper
.
find
(
sel
.
endEvent
);
possibleEndEvents
.
forEach
(({
name
,
identifier
})
=>
{
...
...
@@ -325,7 +347,7 @@ describe('CustomStageForm', () => {
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
startEventArrayIndex
+
1
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
stopOptions
=
wrapper
.
find
(
sel
.
endEvent
);
excludedEndEvents
.
forEach
(({
name
,
identifier
})
=>
{
...
...
@@ -355,10 +377,16 @@ describe('CustomStageForm', () => {
wrapper
.
destroy
();
});
it
(
'
notifies that a start event needs to be selected first
'
,
()
=>
{
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
wrapper
.
text
()).
toContain
(
'
Please select a start event first
'
);
});
});
it
(
'
will notify if the current start and stop event pair is not valid
'
,
()
=>
{
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
2
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
sel
.
invalidFeedback
).
exists
()).
toEqual
(
true
);
expect
(
wrapper
.
find
(
sel
.
invalidFeedback
).
text
()).
toContain
(
'
Start event changed, please select a valid stop event
'
,
...
...
@@ -369,14 +397,14 @@ describe('CustomStageForm', () => {
it
(
'
will update the list of stop events
'
,
()
=>
{
const
se
=
wrapper
.
vm
.
endEventOptions
;
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
2
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
se
[
1
].
value
).
not
.
toEqual
(
wrapper
.
vm
.
endEventOptions
[
1
].
value
);
});
});
it
(
'
will disable the submit button until a valid endEvent is selected
'
,
()
=>
{
selectDropdownOption
(
wrapper
,
sel
.
startEvent
,
2
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
sel
.
submit
).
attributes
(
'
disabled
'
)).
toEqual
(
'
disabled
'
);
});
});
...
...
@@ -384,7 +412,7 @@ describe('CustomStageForm', () => {
describe
(
'
Stop event label
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
(
{}
);
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
...
...
@@ -405,7 +433,7 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
sel
.
endEventLabel
).
exists
()).
toEqual
(
true
);
});
});
...
...
@@ -429,7 +457,7 @@ describe('CustomStageForm', () => {
.
at
(
2
)
// item at index 0 is 'select a label'
.
trigger
(
'
click
'
);
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
})
.
then
(()
=>
{
expect
(
wrapper
.
vm
.
fields
.
endEventLabelId
).
toEqual
(
selectedLabelId
);
...
...
@@ -440,7 +468,7 @@ describe('CustomStageForm', () => {
describe
(
'
Add stage button
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
(
{}
);
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
...
...
@@ -468,11 +496,11 @@ describe('CustomStageForm', () => {
const
stopEventDropdownIndex
=
1
;
beforeEach
(()
=>
{
wrapper
=
createComponent
(
{}
);
wrapper
=
createComponent
();
wrapper
.
find
(
sel
.
name
).
setValue
(
'
Cool stage
'
);
return
Vue
.
nextTick
().
then
(()
=>
setEventDropdowns
({
startEventDropdownIndex
,
stopEventDropdownIndex
}),
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
setEventDropdowns
({
startEventDropdownIndex
,
stopEventDropdownIndex
})
);
});
afterEach
(()
=>
{
...
...
@@ -485,7 +513,7 @@ describe('CustomStageForm', () => {
wrapper
.
find
(
sel
.
submit
).
trigger
(
'
click
'
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
event
=
findEvent
(
STAGE_ACTIONS
.
CREATE
);
expect
(
event
).
toBeTruthy
();
expect
(
event
).
toHaveLength
(
1
);
...
...
@@ -510,7 +538,7 @@ describe('CustomStageForm', () => {
];
wrapper
.
find
(
sel
.
submit
).
trigger
(
'
click
'
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
event
=
findEvent
(
STAGE_ACTIONS
.
CREATE
);
expect
(
event
[
0
]).
toEqual
(
res
);
});
...
...
@@ -520,7 +548,7 @@ describe('CustomStageForm', () => {
describe
(
'
Cancel button
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
(
{}
);
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
...
...
@@ -533,7 +561,7 @@ describe('CustomStageForm', () => {
expect
(
btn
.
attributes
(
'
disabled
'
)).
toEqual
(
'
disabled
'
);
wrapper
.
find
(
sel
.
name
).
setValue
(
'
Cool stage
'
);
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
btn
.
attributes
(
'
disabled
'
)).
toBeUndefined
();
});
});
...
...
@@ -547,11 +575,12 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
()
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
wrapper
.
find
(
sel
.
cancel
).
trigger
(
'
click
'
);
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
})
.
then
(()
=>
{
expect
(
wrapper
.
vm
.
fields
).
toEqual
({
...
...
@@ -575,10 +604,11 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
()
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
wrapper
.
find
(
sel
.
cancel
).
trigger
(
'
click
'
);
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
})
.
then
(()
=>
{
ev
=
findEvent
(
'
cancel
'
);
...
...
@@ -590,12 +620,12 @@ describe('CustomStageForm', () => {
describe
(
'
isSavingCustomStage=true
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
(
{
wrapper
=
createComponent
(
{
initialState
:
{
isSavingCustomStage
:
true
,
},
false
,
);
});
return
wrapper
.
vm
.
$nextTick
(
);
});
it
(
'
displays a loading icon
'
,
()
=>
{
...
...
@@ -606,19 +636,13 @@ describe('CustomStageForm', () => {
describe
(
'
Editing a custom stage
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
initialState
:
{
isEditingCustomStage
:
true
,
initialFields
:
{
...
initData
,
formInitialData
,
},
});
wrapper
.
setData
({
fields
:
{
...
initData
,
},
});
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$nextTick
();
});
afterEach
(()
=>
{
...
...
@@ -635,13 +659,14 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
()
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
wrapper
.
find
(
sel
.
cancel
).
trigger
(
'
click
'
);
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
})
.
then
(()
=>
{
expect
(
wrapper
.
vm
.
fields
).
toEqual
({
...
init
Data
});
expect
(
wrapper
.
vm
.
fields
).
toEqual
({
...
formInitial
Data
});
});
});
});
...
...
@@ -662,7 +687,7 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
sel
.
submit
).
attributes
(
'
disabled
'
)).
toBeUndefined
();
});
});
...
...
@@ -674,7 +699,7 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
().
then
(()
=>
{
return
wrapper
.
vm
.
$
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
sel
.
submit
).
attributes
(
'
disabled
'
)).
toEqual
(
'
disabled
'
);
});
});
...
...
@@ -689,10 +714,11 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
()
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
wrapper
.
find
(
sel
.
submit
).
trigger
(
'
click
'
);
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
})
.
then
(()
=>
{
ev
=
findEvent
(
STAGE_ACTIONS
.
UPDATE
);
...
...
@@ -708,17 +734,18 @@ describe('CustomStageForm', () => {
},
});
return
Vue
.
nextTick
()
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
wrapper
.
find
(
sel
.
submit
).
trigger
(
'
click
'
);
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
})
.
then
(()
=>
{
const
submitted
=
findEvent
(
STAGE_ACTIONS
.
UPDATE
)[
0
];
expect
(
submitted
).
not
.
toEqual
([
init
Data
]);
expect
(
submitted
).
not
.
toEqual
([
formInitial
Data
]);
expect
(
submitted
).
toEqual
([
{
id
:
init
Data
.
id
,
id
:
formInitial
Data
.
id
,
start_event_identifier
:
labelStartEvent
.
identifier
,
start_event_label_id
:
groupLabels
[
0
].
id
,
end_event_identifier
:
labelStopEvent
.
identifier
,
...
...
@@ -733,11 +760,10 @@ describe('CustomStageForm', () => {
describe
(
'
isSavingCustomStage=true
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
initialState
:
{
isEditingCustomStage
:
true
,
initialFields
:
{
...
initData
,
},
isSavingCustomStage
:
true
,
},
});
});
it
(
'
displays a loading icon
'
,
()
=>
{
...
...
@@ -749,11 +775,12 @@ describe('CustomStageForm', () => {
describe
(
'
With errors
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
initialFields
:
initData
,
errors
:
customStageFormErrors
,
initialState
:
{
formErrors
:
customStageFormErrors
,
},
});
return
Vue
.
nextTick
();
return
wrapper
.
vm
.
$
nextTick
();
});
afterEach
(()
=>
{
...
...
@@ -775,7 +802,9 @@ describe('CustomStageForm', () => {
};
beforeEach
(()
=>
{
wrapper
=
createComponent
({},
formFieldStubs
);
wrapper
=
createComponent
({
stubs
:
formFieldStubs
,
});
});
describe
(
'
without hidden stages
'
,
()
=>
{
...
...
@@ -795,8 +824,12 @@ describe('CustomStageForm', () => {
describe
(
'
with hidden stages
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({},
formFieldStubs
);
store
.
state
.
stages
=
[{
id
:
'
my-stage
'
,
title
:
'
My default stage
'
,
hidden
:
true
}];
wrapper
=
createComponent
({
stubs
:
formFieldStubs
,
initialRootGetters
:
{
hiddenStages
:
()
=>
[{
id
:
'
my-stage
'
,
title
:
'
My default stage
'
,
hidden
:
true
}],
},
});
});
it
(
'
has stages available to recover
'
,
()
=>
{
...
...
@@ -825,26 +858,46 @@ describe('CustomStageForm', () => {
});
describe
(
'
initializeFormData
'
,
()
=>
{
const
emptyFieldState
=
{
id
:
null
,
name
:
null
,
startEventIdentifier
:
null
,
startEventLabelId
:
null
,
endEventIdentifier
:
null
,
endEventLabelId
:
null
,
};
const
emptyErrorsState
=
{
id
:
[],
name
:
[],
startEventIdentifier
:
[],
startEventLabelId
:
[],
endEventIdentifier
:
[],
endEventLabelId
:
[],
};
describe
(
'
without a startEventIdentifier
'
,
()
=>
{
it
(
'
with no errors
'
,
()
=>
{
const
res
=
initializeFormData
({
initialFields
:
{},
emptyFieldState
,
fields
:
{},
});
expect
(
res
.
fields
).
toEqual
(
{}
);
expect
(
res
.
fieldErrors
).
toEqual
({
expect
(
res
.
fields
).
toEqual
(
emptyFieldState
);
expect
(
res
.
errors
).
toMatchObject
({
endEventIdentifier
:
[
'
Please select a start event first
'
],
});
});
it
(
'
with field errors
'
,
()
=>
{
const
res
=
initializeFormData
({
initialFields
:
{},
emptyFieldState
,
fields
:
{},
errors
:
{
name
:
[
'
is reserved
'
],
},
});
expect
(
res
.
fields
).
toEqual
(
{}
);
expect
(
res
.
fieldErrors
).
toEqual
({
expect
(
res
.
fields
).
toEqual
(
emptyFieldState
);
expect
(
res
.
errors
).
toMatchObject
({
endEventIdentifier
:
[
'
Please select a start event first
'
],
name
:
[
'
is reserved
'
],
});
...
...
@@ -854,29 +907,31 @@ describe('CustomStageForm', () => {
describe
(
'
with a startEventIdentifier
'
,
()
=>
{
it
(
'
with no errors
'
,
()
=>
{
const
res
=
initializeFormData
({
initialFields
:
{
emptyFieldState
,
fields
:
{
startEventIdentifier
:
'
start-event
'
,
},
errors
:
{},
});
expect
(
res
.
fields
).
toEqual
({
startEventIdentifier
:
'
start-event
'
});
expect
(
res
.
fieldErrors
).
toEqual
({
endEventIdentifier
:
null
,
expect
(
res
.
fields
).
toEqual
({
...
emptyFieldState
,
startEventIdentifier
:
'
start-event
'
});
expect
(
res
.
errors
).
toMatchObject
({
endEventIdentifier
:
[]
,
});
});
it
(
'
with field errors
'
,
()
=>
{
const
res
=
initializeFormData
({
initialFields
:
{
emptyFieldState
,
fields
:
{
startEventIdentifier
:
'
start-event
'
,
},
errors
:
{
name
:
[
'
is reserved
'
],
},
});
expect
(
res
.
fields
).
toEqual
({
startEventIdentifier
:
'
start-event
'
});
expect
(
res
.
fieldErrors
).
toEqual
({
endEventIdentifier
:
null
,
expect
(
res
.
fields
).
toEqual
({
...
emptyFieldState
,
startEventIdentifier
:
'
start-event
'
});
expect
(
res
.
errors
).
toMatchObject
({
endEventIdentifier
:
[]
,
name
:
[
'
is reserved
'
],
});
});
...
...
@@ -885,7 +940,8 @@ describe('CustomStageForm', () => {
describe
(
'
with all fields set
'
,
()
=>
{
it
(
'
with no errors
'
,
()
=>
{
const
res
=
initializeFormData
({
initialFields
:
{
emptyFieldState
,
fields
:
{
id
:
1
,
name
:
'
cool-stage
'
,
startEventIdentifier
:
'
start-event
'
,
...
...
@@ -903,14 +959,13 @@ describe('CustomStageForm', () => {
startEventLabelId
:
10
,
endEventLabelId
:
20
,
});
expect
(
res
.
fieldErrors
).
toEqual
({
endEventIdentifier
:
null
,
});
expect
(
res
.
errors
).
toEqual
(
emptyErrorsState
);
});
it
(
'
with field errors
'
,
()
=>
{
const
res
=
initializeFormData
({
initialFields
:
{
emptyFieldState
,
fields
:
{
id
:
1
,
name
:
'
cool-stage
'
,
startEventIdentifier
:
'
start-event
'
,
...
...
@@ -922,6 +977,7 @@ describe('CustomStageForm', () => {
name
:
[
'
is reserved
'
],
},
});
expect
(
res
.
fields
).
toEqual
({
id
:
1
,
name
:
'
cool-stage
'
,
...
...
@@ -930,8 +986,7 @@ describe('CustomStageForm', () => {
startEventLabelId
:
10
,
endEventLabelId
:
20
,
});
expect
(
res
.
fieldErrors
).
toEqual
({
endEventIdentifier
:
null
,
expect
(
res
.
errors
).
toMatchObject
({
name
:
[
'
is reserved
'
],
});
});
...
...
ee/spec/frontend/analytics/cycle_analytics/mock_data.js
View file @
817f6d4d
...
...
@@ -130,8 +130,8 @@ export const rawCustomStage = {
export
const
medians
=
stageMedians
;
const
{
events
:
rawCustomStageEvents
}
=
customizableStagesAndE
vents
;
const
camelCasedStageEvents
=
rawCustomStageEvents
.
map
(
deepCamelCase
);
export
const
rawCustomStageEvents
=
customizableStagesAndEvents
.
e
vents
;
export
const
camelCasedStageEvents
=
rawCustomStageEvents
.
map
(
deepCamelCase
);
export
const
customStageLabelEvents
=
camelCasedStageEvents
.
filter
(
ev
=>
ev
.
type
===
'
label
'
);
export
const
customStageStartEvents
=
camelCasedStageEvents
.
filter
(
ev
=>
ev
.
canBeStartEvent
);
...
...
ee/spec/frontend/analytics/cycle_analytics/store/actions_spec.js
View file @
817f6d4d
...
...
@@ -4,8 +4,6 @@ import testAction from 'helpers/vuex_action_helper';
import
*
as
getters
from
'
ee/analytics/cycle_analytics/store/getters
'
;
import
*
as
actions
from
'
ee/analytics/cycle_analytics/store/actions
'
;
import
*
as
types
from
'
ee/analytics/cycle_analytics/store/mutation_types
'
;
import
*
as
customStageActions
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/actions
'
;
import
*
as
customStageTypes
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/mutation_types
'
;
import
createFlash
from
'
~/flash
'
;
import
httpStatusCodes
from
'
~/lib/utils/http_status
'
;
import
{
...
...
@@ -684,136 +682,6 @@ describe('Cycle analytics actions', () => {
});
});
describe
(
'
createStage
'
,
()
=>
{
describe
(
'
with valid data
'
,
()
=>
{
const
customStageData
=
{
startEventIdentifier
:
'
start_event
'
,
endEventIdentifier
:
'
end_event
'
,
name
:
'
cool-new-stage
'
,
};
beforeEach
(()
=>
{
state
=
{
...
state
,
selectedGroup
};
mock
.
onPost
(
endpoints
.
baseStagesEndpointstageData
).
reply
(
201
,
customStageData
);
});
it
(
`dispatches the 'receiveCreateStageSuccess' action`
,
()
=>
testAction
(
customStageActions
.
createStage
,
customStageData
,
state
,
[],
[
{
type
:
'
clearFormErrors
'
},
{
type
:
'
setSavingCustomStage
'
},
{
type
:
'
receiveCreateStageSuccess
'
,
payload
:
{
data
:
customStageData
,
status
:
201
},
},
],
));
});
describe
(
'
with errors
'
,
()
=>
{
const
message
=
'
failed
'
;
const
errors
=
{
endEventIdentifier
:
[
'
Cant be blank
'
],
};
const
customStageData
=
{
startEventIdentifier
:
'
start_event
'
,
endEventIdentifier
:
''
,
name
:
'
cool-new-stage
'
,
};
beforeEach
(()
=>
{
state
=
{
...
state
,
selectedGroup
};
mock
.
onPost
(
endpoints
.
baseStagesEndpointstageData
)
.
reply
(
httpStatusCodes
.
UNPROCESSABLE_ENTITY
,
{
message
,
errors
,
});
});
it
(
`dispatches the 'receiveCreateStageError' action`
,
()
=>
testAction
(
customStageActions
.
createStage
,
customStageData
,
state
,
[],
[
{
type
:
'
clearFormErrors
'
},
{
type
:
'
setSavingCustomStage
'
},
{
type
:
'
receiveCreateStageError
'
,
payload
:
{
data
:
customStageData
,
errors
,
message
,
status
:
httpStatusCodes
.
UNPROCESSABLE_ENTITY
,
},
},
],
));
});
});
describe
(
'
receiveCreateStageError
'
,
()
=>
{
const
response
=
{
data
:
{
name
:
'
uh oh
'
},
};
beforeEach
(()
=>
{});
it
(
'
will commit the RECEIVE_CREATE_STAGE_ERROR mutation
'
,
()
=>
testAction
(
customStageActions
.
receiveCreateStageError
,
response
,
state
,
[{
type
:
customStageTypes
.
RECEIVE_CREATE_STAGE_ERROR
}],
[
{
type
:
'
setStageFormErrors
'
,
payload
:
{},
},
],
));
it
(
'
will flash an error message
'
,
()
=>
{
return
customStageActions
.
receiveCreateStageError
(
{
dispatch
:
()
=>
Promise
.
resolve
(),
commit
:
()
=>
{},
},
response
,
)
.
then
(()
=>
{
shouldFlashAMessage
(
'
There was a problem saving your custom stage, please try again
'
);
});
});
describe
(
'
with a stage name error
'
,
()
=>
{
it
(
'
will flash an error message
'
,
()
=>
{
return
customStageActions
.
receiveCreateStageError
(
{
dispatch
:
()
=>
Promise
.
resolve
(),
commit
:
()
=>
{},
},
{
...
response
,
status
:
httpStatusCodes
.
UNPROCESSABLE_ENTITY
,
errors
:
{
name
:
[
'
is reserved
'
]
},
},
)
.
then
(()
=>
{
shouldFlashAMessage
(
"
'uh oh' stage already exists
"
);
});
});
});
});
describe
(
'
initializeCycleAnalytics
'
,
()
=>
{
let
mockDispatch
;
let
mockCommit
;
...
...
@@ -873,38 +741,6 @@ describe('Cycle analytics actions', () => {
));
});
describe
(
'
receiveCreateStageSuccess
'
,
()
=>
{
const
response
=
{
data
:
{
title
:
'
COOL
'
,
},
};
it
(
'
will dispatch fetchGroupStagesAndEvents
'
,
()
=>
testAction
(
customStageActions
.
receiveCreateStageSuccess
,
response
,
state
,
[{
type
:
customStageTypes
.
RECEIVE_CREATE_STAGE_SUCCESS
}],
[{
type
:
'
fetchGroupStagesAndEvents
'
,
payload
:
null
},
{
type
:
'
clearSavingCustomStage
'
}],
));
describe
(
'
with an error
'
,
()
=>
{
it
(
'
will flash an error message
'
,
()
=>
customStageActions
.
receiveCreateStageSuccess
(
{
dispatch
:
()
=>
Promise
.
reject
(),
commit
:
()
=>
{},
},
response
,
)
.
then
(()
=>
{
shouldFlashAMessage
(
'
There was a problem refreshing the data, please try again
'
);
}));
});
});
describe
(
'
reorderStage
'
,
()
=>
{
const
stageId
=
'
cool-stage
'
;
const
payload
=
{
id
:
stageId
,
move_after_id
:
'
2
'
,
move_before_id
:
'
8
'
};
...
...
ee/spec/frontend/analytics/cycle_analytics/store/modules/custom_stages/actions_spec.js
0 → 100644
View file @
817f6d4d
import
axios
from
'
axios
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
testAction
from
'
helpers/vuex_action_helper
'
;
import
*
as
actions
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/actions
'
;
import
*
as
types
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/mutation_types
'
;
import
createFlash
from
'
~/flash
'
;
import
httpStatusCodes
from
'
~/lib/utils/http_status
'
;
import
{
selectedGroup
,
endpoints
,
rawCustomStage
}
from
'
../../../mock_data
'
;
jest
.
mock
(
'
~/flash
'
);
describe
(
'
Custom stage actions
'
,
()
=>
{
let
state
;
let
mock
;
const
selectedStage
=
rawCustomStage
;
const
shouldFlashAMessage
=
(
msg
,
type
=
null
)
=>
{
const
args
=
type
?
[
msg
,
type
]
:
[
msg
];
expect
(
createFlash
).
toHaveBeenCalledWith
(...
args
);
};
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
});
afterEach
(()
=>
{
mock
.
restore
();
state
=
{
selectedGroup
:
null
};
});
describe
(
'
createStage
'
,
()
=>
{
describe
(
'
with valid data
'
,
()
=>
{
const
customStageData
=
{
startEventIdentifier
:
'
start_event
'
,
endEventIdentifier
:
'
end_event
'
,
name
:
'
cool-new-stage
'
,
};
beforeEach
(()
=>
{
state
=
{
...
state
,
selectedGroup
};
mock
.
onPost
(
endpoints
.
baseStagesEndpointstageData
).
reply
(
201
,
customStageData
);
});
it
(
`dispatches the 'receiveCreateStageSuccess' action`
,
()
=>
testAction
(
actions
.
createStage
,
customStageData
,
state
,
[],
[
{
type
:
'
clearFormErrors
'
},
{
type
:
'
setSavingCustomStage
'
},
{
type
:
'
receiveCreateStageSuccess
'
,
payload
:
{
data
:
customStageData
,
status
:
201
},
},
],
));
});
describe
(
'
with errors
'
,
()
=>
{
const
message
=
'
failed
'
;
const
errors
=
{
endEventIdentifier
:
[
'
Cant be blank
'
],
};
const
customStageData
=
{
startEventIdentifier
:
'
start_event
'
,
endEventIdentifier
:
''
,
name
:
'
cool-new-stage
'
,
};
beforeEach
(()
=>
{
state
=
{
...
state
,
selectedGroup
};
mock
.
onPost
(
endpoints
.
baseStagesEndpointstageData
)
.
reply
(
httpStatusCodes
.
UNPROCESSABLE_ENTITY
,
{
message
,
errors
,
});
});
it
(
`dispatches the 'receiveCreateStageError' action`
,
()
=>
testAction
(
actions
.
createStage
,
customStageData
,
state
,
[],
[
{
type
:
'
clearFormErrors
'
},
{
type
:
'
setSavingCustomStage
'
},
{
type
:
'
receiveCreateStageError
'
,
payload
:
{
data
:
customStageData
,
errors
,
message
,
status
:
httpStatusCodes
.
UNPROCESSABLE_ENTITY
,
},
},
],
));
});
});
describe
(
'
receiveCreateStageError
'
,
()
=>
{
const
response
=
{
data
:
{
name
:
'
uh oh
'
},
};
beforeEach
(()
=>
{});
it
(
'
will commit the RECEIVE_CREATE_STAGE_ERROR mutation
'
,
()
=>
testAction
(
actions
.
receiveCreateStageError
,
response
,
state
,
[{
type
:
types
.
RECEIVE_CREATE_STAGE_ERROR
}],
[{
type
:
'
setStageFormErrors
'
,
payload
:
{}
}],
));
it
(
'
will flash an error message
'
,
()
=>
{
return
actions
.
receiveCreateStageError
(
{
dispatch
:
()
=>
Promise
.
resolve
(),
commit
:
()
=>
{},
},
response
,
)
.
then
(()
=>
{
shouldFlashAMessage
(
'
There was a problem saving your custom stage, please try again
'
);
});
});
describe
(
'
with a stage name error
'
,
()
=>
{
it
(
'
will flash an error message
'
,
()
=>
{
return
actions
.
receiveCreateStageError
(
{
dispatch
:
()
=>
Promise
.
resolve
(),
commit
:
()
=>
{},
},
{
...
response
,
status
:
httpStatusCodes
.
UNPROCESSABLE_ENTITY
,
errors
:
{
name
:
[
'
is reserved
'
]
},
},
)
.
then
(()
=>
{
shouldFlashAMessage
(
"
'uh oh' stage already exists
"
);
});
});
});
});
describe
(
'
receiveCreateStageSuccess
'
,
()
=>
{
const
response
=
{
data
:
{
title
:
'
COOL
'
,
},
};
it
(
'
will dispatch fetchGroupStagesAndEvents
'
,
()
=>
testAction
(
actions
.
receiveCreateStageSuccess
,
response
,
state
,
[{
type
:
types
.
RECEIVE_CREATE_STAGE_SUCCESS
}],
[{
type
:
'
fetchGroupStagesAndEvents
'
,
payload
:
null
},
{
type
:
'
clearSavingCustomStage
'
}],
));
describe
(
'
with an error
'
,
()
=>
{
it
(
'
will flash an error message
'
,
()
=>
actions
.
receiveCreateStageSuccess
(
{
dispatch
:
()
=>
Promise
.
reject
(),
commit
:
()
=>
{},
},
response
,
)
.
then
(()
=>
{
shouldFlashAMessage
(
'
There was a problem refreshing the data, please try again
'
);
}));
});
});
describe
(
'
setStageFormErrors
'
,
()
=>
{
it
(
'
commits the "SET_STAGE_FORM_ERRORS" mutation
'
,
()
=>
{
return
testAction
(
actions
.
setStageFormErrors
,
[],
state
,
[{
type
:
types
.
SET_STAGE_FORM_ERRORS
,
payload
:
[]
}],
[],
);
});
});
describe
(
'
clearFormErrors
'
,
()
=>
{
it
(
'
commits the "CLEAR_FORM_ERRORS" mutation
'
,
()
=>
{
return
testAction
(
actions
.
clearFormErrors
,
[],
state
,
[{
type
:
types
.
CLEAR_FORM_ERRORS
}],
[],
);
});
});
describe
(
'
setStageEvents
'
,
()
=>
{
it
(
'
commits the "SET_STAGE_EVENTS" mutation
'
,
()
=>
{
return
testAction
(
actions
.
setStageEvents
,
[],
state
,
[{
type
:
types
.
SET_STAGE_EVENTS
,
payload
:
[]
}],
[],
);
});
});
describe
(
'
hideForm
'
,
()
=>
{
it
(
'
commits the "HIDE_FORM" mutation
'
,
()
=>
{
return
testAction
(
actions
.
hideForm
,
null
,
state
,
[{
type
:
types
.
HIDE_FORM
}],
[]);
});
});
describe
(
'
showCreateForm
'
,
()
=>
{
it
(
'
commits the "SHOW_CREATE_FORM" mutation
'
,
()
=>
{
return
testAction
(
actions
.
showCreateForm
,
null
,
state
,
[
{
type
:
types
.
SET_LOADING
},
{
type
:
types
.
SET_FORM_INITIAL_DATA
},
{
type
:
types
.
SHOW_CREATE_FORM
},
],
[],
);
});
});
describe
(
'
showEditForm
'
,
()
=>
{
it
(
'
commits the "SHOW_EDIT_FORM" mutation with initial data
'
,
()
=>
{
return
testAction
(
actions
.
showEditForm
,
selectedStage
,
state
,
[
{
type
:
types
.
SET_LOADING
},
{
type
:
types
.
SET_FORM_INITIAL_DATA
,
payload
:
rawCustomStage
},
{
type
:
types
.
SHOW_EDIT_FORM
},
],
[{
type
:
'
setSelectedStage
'
,
payload
:
rawCustomStage
},
{
type
:
'
clearSavingCustomStage
'
}],
);
});
});
});
ee/spec/frontend/analytics/cycle_analytics/store/modules/custom_stages/getters_spec.js
0 → 100644
View file @
817f6d4d
import
*
as
getters
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/getters
'
;
describe
(
'
Custom stages getters
'
,
()
=>
{
describe
.
each
`
state | result
${{
isCreatingCustomStage
:
true
,
isEditingCustomStage
:
true
}
} |
${
true
}
${{
isCreatingCustomStage
:
false
,
isEditingCustomStage
:
true
}
} |
${
true
}
${{
isCreatingCustomStage
:
true
,
isEditingCustomStage
:
false
}
} |
${
true
}
${{
isCreatingCustomStage
:
false
,
isEditingCustomStage
:
false
}
} |
${
false
}
`
(
'
customStageFormActive
'
,
({
state
,
result
})
=>
{
it
(
`with state
${
state
}
returns
${
result
}
`
,
()
=>
{
expect
(
getters
.
customStageFormActive
(
state
)).
toEqual
(
result
);
});
});
});
ee/spec/frontend/analytics/cycle_analytics/store/modules/custom_stages/mutations_spec.js
0 → 100644
View file @
817f6d4d
import
mutations
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/mutations
'
;
import
*
as
types
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/mutation_types
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
rawCustomStageEvents
,
camelCasedStageEvents
,
rawCustomStage
}
from
'
../../../mock_data
'
;
let
state
=
null
;
describe
(
'
Custom stage mutations
'
,
()
=>
{
beforeEach
(()
=>
{
state
=
{};
});
afterEach
(()
=>
{
state
=
null
;
});
it
.
each
`
mutation | stateKey | value
${
types
.
HIDE_FORM
}
|
${
'
isCreatingCustomStage
'
}
|
${
false
}
${
types
.
HIDE_FORM
}
|
${
'
isEditingCustomStage
'
}
|
${
false
}
${
types
.
HIDE_FORM
}
|
${
'
formErrors
'
}
|
${
null
}
${
types
.
HIDE_FORM
}
|
${
'
formInitialData
'
}
|
${
null
}
${
types
.
CLEAR_FORM_ERRORS
}
|
${
'
formErrors
'
}
|
${
null
}
${
types
.
SHOW_CREATE_FORM
}
|
${
'
isCreatingCustomStage
'
}
|
${
true
}
${
types
.
SHOW_CREATE_FORM
}
|
${
'
isEditingCustomStage
'
}
|
${
false
}
${
types
.
SHOW_CREATE_FORM
}
|
${
'
formErrors
'
}
|
${
null
}
${
types
.
SHOW_CREATE_FORM
}
|
${
'
formInitialData
'
}
|
${
null
}
${
types
.
SHOW_EDIT_FORM
}
|
${
'
isEditingCustomStage
'
}
|
${
true
}
${
types
.
SHOW_EDIT_FORM
}
|
${
'
isCreatingCustomStage
'
}
|
${
false
}
${
types
.
SHOW_EDIT_FORM
}
|
${
'
formErrors
'
}
|
${
null
}
${
types
.
RECEIVE_CREATE_STAGE_SUCCESS
}
|
${
'
formErrors
'
}
|
${
null
}
${
types
.
RECEIVE_CREATE_STAGE_SUCCESS
}
|
${
'
formInitialData
'
}
|
${
null
}
${
types
.
RECEIVE_CREATE_STAGE_ERROR
}
|
${
'
isSavingCustomStage
'
}
|
${
false
}
${
types
.
SET_SAVING_CUSTOM_STAGE
}
|
${
'
isSavingCustomStage
'
}
|
${
true
}
${
types
.
CLEAR_SAVING_CUSTOM_STAGE
}
|
${
'
isSavingCustomStage
'
}
|
${
false
}
${
types
.
SET_LOADING
}
|
${
'
isLoadingCustomStage
'
}
|
${
true
}
`
(
'
$mutation will set $stateKey=$value
'
,
({
mutation
,
stateKey
,
value
})
=>
{
mutations
[
mutation
](
state
);
expect
(
state
[
stateKey
]).
toEqual
(
value
);
});
describe
(
`
${
types
.
SET_STAGE_EVENTS
}
`
,
()
=>
{
it
(
'
will set formEvents
'
,
()
=>
{
state
=
{};
mutations
[
types
.
SET_STAGE_EVENTS
](
state
,
rawCustomStageEvents
);
expect
(
state
.
formEvents
).
toEqual
(
camelCasedStageEvents
);
});
});
describe
(
`
${
types
.
SET_STAGE_FORM_ERRORS
}
`
,
()
=>
{
const
mockFormError
=
{
start_identifier
:
[
'
Cant be blank
'
]
};
it
(
'
will set formErrors
'
,
()
=>
{
state
=
{};
mutations
[
types
.
SET_STAGE_FORM_ERRORS
](
state
,
mockFormError
);
expect
(
state
.
formErrors
).
toEqual
(
convertObjectPropsToCamelCase
(
mockFormError
));
});
});
describe
(
`
${
types
.
SET_FORM_INITIAL_DATA
}
`
,
()
=>
{
const
mockStage
=
{
endEventIdentifier
:
'
issue_first_added_to_board
'
,
endEventLabelId
:
null
,
id
:
18
,
name
:
'
Coolest beans stage
'
,
startEventIdentifier
:
'
issue_first_mentioned_in_commit
'
,
startEventLabelId
:
null
,
};
it
(
'
will set formInitialData
'
,
()
=>
{
state
=
{};
mutations
[
types
.
SET_FORM_INITIAL_DATA
](
state
,
rawCustomStage
);
expect
(
state
.
formInitialData
).
toEqual
(
mockStage
);
});
});
});
ee/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
View file @
817f6d4d
import
mutations
from
'
ee/analytics/cycle_analytics/store/mutations
'
;
import
*
as
types
from
'
ee/analytics/cycle_analytics/store/mutation_types
'
;
import
customStageMutations
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/mutations
'
;
import
*
as
customStageTypes
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages/mutation_types
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
issueStage
,
...
...
@@ -13,9 +10,8 @@ import {
totalStage
,
startDate
,
endDate
,
customizableStagesAndEvents
,
selectedProjects
,
rawCustomStage
,
customizableStagesAndEvents
,
}
from
'
../mock_data
'
;
let
state
=
null
;
...
...
@@ -70,65 +66,6 @@ describe('Cycle analytics mutations', () => {
},
);
describe
(
'
Custom stage mutations
'
,
()
=>
{
beforeEach
(()
=>
{
state
=
{};
});
afterEach
(()
=>
{
state
=
null
;
});
it
.
each
`
mutation | stateKey | value
${
customStageTypes
.
HIDE_FORM
}
|
${
'
isCreatingCustomStage
'
}
|
${
false
}
${
customStageTypes
.
HIDE_FORM
}
|
${
'
isEditingCustomStage
'
}
|
${
false
}
${
customStageTypes
.
HIDE_FORM
}
|
${
'
formErrors
'
}
|
${
null
}
${
customStageTypes
.
HIDE_FORM
}
|
${
'
formInitialData
'
}
|
${
null
}
${
customStageTypes
.
SHOW_CREATE_FORM
}
|
${
'
isCreatingCustomStage
'
}
|
${
true
}
${
customStageTypes
.
SHOW_CREATE_FORM
}
|
${
'
isEditingCustomStage
'
}
|
${
false
}
${
customStageTypes
.
SHOW_CREATE_FORM
}
|
${
'
formErrors
'
}
|
${
null
}
${
customStageTypes
.
SHOW_EDIT_FORM
}
|
${
'
isEditingCustomStage
'
}
|
${
true
}
${
customStageTypes
.
SHOW_EDIT_FORM
}
|
${
'
isCreatingCustomStage
'
}
|
${
false
}
${
customStageTypes
.
SHOW_EDIT_FORM
}
|
${
'
formErrors
'
}
|
${
null
}
${
customStageTypes
.
RECEIVE_CREATE_STAGE_ERROR
}
|
${
'
isSavingCustomStage
'
}
|
${
false
}
${
customStageTypes
.
SET_SAVING_CUSTOM_STAGE
}
|
${
'
isSavingCustomStage
'
}
|
${
true
}
${
customStageTypes
.
CLEAR_SAVING_CUSTOM_STAGE
}
|
${
'
isSavingCustomStage
'
}
|
${
false
}
`
(
'
$mutation will set $stateKey=$value
'
,
({
mutation
,
stateKey
,
value
})
=>
{
customStageMutations
[
mutation
](
state
);
expect
(
state
[
stateKey
]).
toEqual
(
value
);
});
describe
(
`
${
customStageTypes
.
SET_STAGE_FORM_ERRORS
}
`
,
()
=>
{
const
mockFormError
=
{
start_identifier
:
[
'
Cant be blank
'
]
};
it
(
'
will set formErrors
'
,
()
=>
{
state
=
{};
customStageMutations
[
customStageTypes
.
SET_STAGE_FORM_ERRORS
](
state
,
mockFormError
);
expect
(
state
.
formErrors
).
toEqual
(
convertObjectPropsToCamelCase
(
mockFormError
));
});
});
describe
(
`
${
customStageTypes
.
SET_FORM_INITIAL_DATA
}
`
,
()
=>
{
const
mockStage
=
{
id
:
18
,
name
:
'
Coolest beans stage
'
,
startEventIdentifier
:
'
issue_first_mentioned_in_commit
'
,
startEventLabelId
:
null
,
endEventIdentifier
:
'
issue_first_added_to_board
'
,
endEventLabelId
:
null
,
};
it
(
'
will set formInitialData
'
,
()
=>
{
state
=
{};
customStageMutations
[
customStageTypes
.
SET_FORM_INITIAL_DATA
](
state
,
rawCustomStage
);
expect
(
state
.
formInitialData
).
toEqual
(
mockStage
);
});
});
});
describe
(
`
${
types
.
RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS
}
`
,
()
=>
{
it
(
'
will set isLoading=false and errorCode=null
'
,
()
=>
{
mutations
[
types
.
RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS
](
state
,
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment