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
ec5b51d3
Commit
ec5b51d3
authored
Nov 03, 2020
by
Florie Guibert
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Boards - Create new issue in GraphQL
Add VueX action to create issue using graphQL mutation
parent
7472a375
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
408 additions
and
63 deletions
+408
-63
app/assets/javascripts/boards/components/board_list_new.vue
app/assets/javascripts/boards/components/board_list_new.vue
+1
-1
app/assets/javascripts/boards/components/board_new_issue.vue
app/assets/javascripts/boards/components/board_new_issue.vue
+6
-28
app/assets/javascripts/boards/components/board_new_issue_new.vue
...ets/javascripts/boards/components/board_new_issue_new.vue
+129
-0
app/assets/javascripts/boards/components/project_select.vue
app/assets/javascripts/boards/components/project_select.vue
+7
-5
app/assets/javascripts/boards/index.js
app/assets/javascripts/boards/index.js
+4
-0
app/assets/javascripts/boards/queries/issue_create.mutation.graphql
.../javascripts/boards/queries/issue_create.mutation.graphql
+10
-0
app/assets/javascripts/boards/stores/actions.js
app/assets/javascripts/boards/stores/actions.js
+34
-5
app/assets/javascripts/boards/stores/mutation_types.js
app/assets/javascripts/boards/stores/mutation_types.js
+2
-0
app/assets/javascripts/boards/stores/mutations.js
app/assets/javascripts/boards/stores/mutations.js
+16
-4
ee/app/assets/javascripts/boards/components/issues_lane_list.vue
...assets/javascripts/boards/components/issues_lane_list.vue
+1
-1
spec/frontend/boards/board_list_new_spec.js
spec/frontend/boards/board_list_new_spec.js
+2
-0
spec/frontend/boards/components/board_new_issue_new_spec.js
spec/frontend/boards/components/board_new_issue_new_spec.js
+115
-0
spec/frontend/boards/mock_data.js
spec/frontend/boards/mock_data.js
+2
-0
spec/frontend/boards/stores/actions_spec.js
spec/frontend/boards/stores/actions_spec.js
+39
-16
spec/frontend/boards/stores/mutations_spec.js
spec/frontend/boards/stores/mutations_spec.js
+40
-3
No files found.
app/assets/javascripts/boards/components/board_list_new.vue
View file @
ec5b51d3
<
script
>
import
{
mapActions
,
mapState
}
from
'
vuex
'
;
import
{
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
BoardNewIssue
from
'
./board_new_issue.vue
'
;
import
BoardNewIssue
from
'
./board_new_issue
_new
.vue
'
;
import
BoardCard
from
'
./board_card.vue
'
;
import
eventHub
from
'
../eventhub
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
...
...
app/assets/javascripts/boards/components/board_new_issue.vue
View file @
ec5b51d3
<
script
>
import
$
from
'
jquery
'
;
import
{
mapActions
,
mapGetters
}
from
'
vuex
'
;
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
getMilestone
}
from
'
ee_else_ce/boards/boards_util
'
;
import
ListIssue
from
'
ee_else_ce/boards/models/issue
'
;
...
...
@@ -9,6 +7,8 @@ import ProjectSelect from './project_select.vue';
import
boardsStore
from
'
../stores/boards_store
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
// This component is being replaced in favor of './board_new_issue_new.vue' for GraphQL boards
export
default
{
name
:
'
BoardNewIssue
'
,
components
:
{
...
...
@@ -31,23 +31,18 @@ export default {
};
},
computed
:
{
...
mapGetters
([
'
isSwimlanesOn
'
]),
disabled
()
{
if
(
this
.
groupId
)
{
return
this
.
title
===
''
||
!
this
.
selectedProject
.
name
;
}
return
this
.
title
===
''
;
},
shouldDisplaySwimlanes
()
{
return
this
.
glFeatures
.
boardsWithSwimlanes
&&
this
.
isSwimlanesOn
;
},
},
mounted
()
{
this
.
$refs
.
input
.
focus
();
eventHub
.
$on
(
'
setSelectedProject
'
,
this
.
setSelectedProject
);
},
methods
:
{
...
mapActions
([
'
addListIssue
'
,
'
addListIssueFailure
'
]),
submit
(
e
)
{
e
.
preventDefault
();
if
(
this
.
title
.
trim
()
===
''
)
return
Promise
.
resolve
();
...
...
@@ -74,31 +69,14 @@ export default {
eventHub
.
$emit
(
`scroll-board-list-
${
this
.
list
.
id
}
`
);
this
.
cancel
();
if
(
this
.
shouldDisplaySwimlanes
||
this
.
glFeatures
.
graphqlBoardLists
)
{
this
.
addListIssue
({
list
:
this
.
list
,
issue
,
position
:
0
});
}
return
this
.
list
.
newIssue
(
issue
)
.
then
(()
=>
{
// Need this because our jQuery very kindly disables buttons on ALL form submissions
$
(
this
.
$refs
.
submitButton
).
enable
();
if
(
!
this
.
shouldDisplaySwimlanes
&&
!
this
.
glFeatures
.
graphqlBoardLists
)
{
boardsStore
.
setIssueDetail
(
issue
);
boardsStore
.
setListDetail
(
this
.
list
);
}
boardsStore
.
setIssueDetail
(
issue
);
boardsStore
.
setListDetail
(
this
.
list
);
})
.
catch
(()
=>
{
// Need this because our jQuery very kindly disables buttons on ALL form submissions
$
(
this
.
$refs
.
submitButton
).
enable
();
// Remove the issue
if
(
this
.
shouldDisplaySwimlanes
||
this
.
glFeatures
.
graphqlBoardLists
)
{
this
.
addListIssueFailure
({
list
:
this
.
list
,
issue
});
}
else
{
this
.
list
.
removeIssue
(
issue
);
}
this
.
list
.
removeIssue
(
issue
);
// Show error message
this
.
error
=
true
;
...
...
@@ -137,7 +115,7 @@ export default {
<gl-button
ref=
"submitButton"
:disabled=
"disabled"
class=
"float-left"
class=
"float-left
js-no-auto-disable
"
variant=
"success"
category=
"primary"
type=
"submit"
...
...
app/assets/javascripts/boards/components/board_new_issue_new.vue
0 → 100644
View file @
ec5b51d3
<
script
>
import
{
mapActions
}
from
'
vuex
'
;
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
getMilestone
}
from
'
ee_else_ce/boards/boards_util
'
;
import
eventHub
from
'
../eventhub
'
;
import
ProjectSelect
from
'
./project_select.vue
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
{
__
}
from
'
~/locale
'
;
export
default
{
name
:
'
BoardNewIssue
'
,
i18n
:
{
submit
:
__
(
'
Submit issue
'
),
cancel
:
__
(
'
Cancel
'
),
},
components
:
{
ProjectSelect
,
GlButton
,
},
mixins
:
[
glFeatureFlagMixin
()],
props
:
{
list
:
{
type
:
Object
,
required
:
true
,
},
},
inject
:
[
'
groupId
'
,
'
weightFeatureAvailable
'
,
'
boardWeight
'
],
data
()
{
return
{
title
:
''
,
selectedProject
:
{},
};
},
computed
:
{
disabled
()
{
if
(
this
.
groupId
)
{
return
this
.
title
===
''
||
!
this
.
selectedProject
.
name
;
}
return
this
.
title
===
''
;
},
inputFieldId
()
{
// eslint-disable-next-line @gitlab/require-i18n-strings
return
`
${
this
.
list
.
id
}
-title`
;
},
},
mounted
()
{
this
.
$refs
.
input
.
focus
();
eventHub
.
$on
(
'
setSelectedProject
'
,
this
.
setSelectedProject
);
},
methods
:
{
...
mapActions
([
'
addListNewIssue
'
]),
submit
(
e
)
{
e
.
preventDefault
();
const
labels
=
this
.
list
.
label
?
[
this
.
list
.
label
]
:
[];
const
assignees
=
this
.
list
.
assignee
?
[
this
.
list
.
assignee
]
:
[];
const
milestone
=
getMilestone
(
this
.
list
);
const
weight
=
this
.
weightFeatureAvailable
?
this
.
boardWeight
:
undefined
;
const
{
title
}
=
this
;
eventHub
.
$emit
(
`scroll-board-list-
${
this
.
list
.
id
}
`
);
return
this
.
addListNewIssue
({
issueInput
:
{
title
,
labelIds
:
labels
?.
map
(
l
=>
l
.
id
),
assigneeIds
:
assignees
?.
map
(
a
=>
a
?.
id
),
milestoneId
:
milestone
?.
id
,
projectPath
:
this
.
selectedProject
.
path
,
weight
:
weight
>=
0
?
weight
:
null
,
},
list
:
this
.
list
,
}).
then
(()
=>
{
this
.
reset
();
});
},
reset
()
{
this
.
title
=
''
;
eventHub
.
$emit
(
`toggle-issue-form-
${
this
.
list
.
id
}
`
);
},
setSelectedProject
(
selectedProject
)
{
this
.
selectedProject
=
selectedProject
;
},
},
};
</
script
>
<
template
>
<div
class=
"board-new-issue-form"
>
<div
class=
"board-card position-relative p-3 rounded"
>
<form
ref=
"submitForm"
@
submit=
"submit"
>
<label
:for=
"inputFieldId"
class=
"label-bold"
>
{{
__
(
'
Title
'
)
}}
</label>
<input
:id=
"inputFieldId"
ref=
"input"
v-model=
"title"
class=
"form-control"
type=
"text"
name=
"issue_title"
autocomplete=
"off"
/>
<project-select
v-if=
"groupId"
:group-id=
"groupId"
:list=
"list"
/>
<div
class=
"clearfix gl-mt-3"
>
<gl-button
ref=
"submitButton"
:disabled=
"disabled"
class=
"float-left js-no-auto-disable"
variant=
"success"
category=
"primary"
type=
"submit"
>
{{
$options
.
i18n
.
submit
}}
</gl-button>
<gl-button
ref=
"cancelButton"
class=
"float-right"
type=
"button"
variant=
"default"
@
click=
"reset"
>
{{
$options
.
i18n
.
cancel
}}
</gl-button>
</div>
</form>
</div>
</div>
</
template
>
app/assets/javascripts/boards/components/project_select.vue
View file @
ec5b51d3
...
...
@@ -44,6 +44,7 @@ export default {
this
.
selectedProject
=
{
id
:
$el
.
data
(
'
project-id
'
),
name
:
$el
.
data
(
'
project-name
'
),
path
:
$el
.
data
(
'
project-path
'
),
};
eventHub
.
$emit
(
'
setSelectedProject
'
,
this
.
selectedProject
);
},
...
...
@@ -75,11 +76,12 @@ export default {
renderRow
(
project
)
{
return
`
<li>
<a href='#' class='dropdown-menu-link' data-project-id="
${
project
.
id
}
" data-project-name="
${
project
.
name
}
" data-project-name-with-namespace="
${
project
.
name_with_namespace
}
">
<a href='#' class='dropdown-menu-link'
data-project-id="
${
project
.
id
}
"
data-project-name="
${
project
.
name
}
"
data-project-name-with-namespace="
${
project
.
name_with_namespace
}
"
data-project-path="
${
project
.
path_with_namespace
}
"
>
${
escape
(
project
.
name_with_namespace
)}
</a>
</li>
...
...
app/assets/javascripts/boards/index.js
View file @
ec5b51d3
...
...
@@ -91,6 +91,10 @@ export default () => {
labelsManagePath
:
$boardApp
.
dataset
.
labelsManagePath
,
labelsFilterBasePath
:
$boardApp
.
dataset
.
labelsFilterBasePath
,
timeTrackingLimitToHours
:
parseBoolean
(
$boardApp
.
dataset
.
timeTrackingLimitToHours
),
weightFeatureAvailable
:
parseBoolean
(
$boardApp
.
dataset
.
weightFeatureAvailable
),
boardWeight
:
$boardApp
.
dataset
.
boardWeight
?
parseInt
(
$boardApp
.
dataset
.
boardWeight
,
10
)
:
null
,
},
store
,
apolloProvider
,
...
...
app/assets/javascripts/boards/queries/issue_create.mutation.graphql
0 → 100644
View file @
ec5b51d3
#import "ee_else_ce/boards/queries/issue.fragment.graphql"
mutation
CreateIssue
(
$input
:
CreateIssueInput
!)
{
createIssue
(
input
:
$input
)
{
issue
{
...
IssueNode
}
errors
}
}
app/assets/javascripts/boards/stores/actions.js
View file @
ec5b51d3
...
...
@@ -10,16 +10,18 @@ import {
formatListIssues
,
fullBoardId
,
formatListsPageInfo
,
formatIssue
,
}
from
'
../boards_util
'
;
import
boardStore
from
'
~/boards/stores/boards_store
'
;
import
updateAssignees
from
'
~/vue_shared/components/sidebar/queries/updateAssignees.mutation.graphql
'
;
import
listsIssuesQuery
from
'
../queries/lists_issues.query.graphql
'
;
import
boardLabelsQuery
from
'
../queries/board_labels.query.graphql
'
;
import
createBoardListMutation
from
'
../queries/board_list_create.mutation.graphql
'
;
import
updateBoardListMutation
from
'
../queries/board_list_update.mutation.graphql
'
;
import
issueMoveListMutation
from
'
../queries/issue_move_list.mutation.graphql
'
;
import
destroyBoardListMutation
from
'
../queries/board_list_destroy.mutation.graphql
'
;
import
updateAssignees
from
'
~/vue_shared/components/sidebar/queries/updateAssignees
.mutation.graphql
'
;
import
issueCreateMutation
from
'
../queries/issue_create
.mutation.graphql
'
;
import
issueSetLabels
from
'
../queries/issue_set_labels.mutation.graphql
'
;
import
issueSetDueDate
from
'
../queries/issue_set_due_date.mutation.graphql
'
;
...
...
@@ -330,16 +332,43 @@ export default {
});
},
createNewIssue
:
()
=>
{
notImplemented
();
createNewIssue
:
({
commit
,
state
},
issueInput
)
=>
{
const
input
=
issueInput
;
const
{
boardType
,
endpoints
}
=
state
;
if
(
boardType
===
BoardType
.
project
)
{
input
.
projectPath
=
endpoints
.
fullPath
;
}
return
gqlClient
.
mutate
({
mutation
:
issueCreateMutation
,
variables
:
{
input
},
})
.
then
(({
data
})
=>
{
if
(
data
.
createIssue
.
errors
.
length
)
{
commit
(
types
.
CREATE_ISSUE_FAILURE
);
}
else
{
return
data
.
createIssue
?.
issue
;
}
return
null
;
})
.
catch
(()
=>
commit
(
types
.
CREATE_ISSUE_FAILURE
));
},
addListIssue
:
({
commit
},
{
list
,
issue
,
position
})
=>
{
commit
(
types
.
ADD_ISSUE_TO_LIST
,
{
list
,
issue
,
position
});
},
addListIssueFailure
:
({
commit
},
{
list
,
issue
})
=>
{
commit
(
types
.
ADD_ISSUE_TO_LIST_FAILURE
,
{
list
,
issue
});
addListNewIssue
:
({
commit
,
dispatch
},
{
issueInput
,
list
})
=>
{
const
issue
=
formatIssue
({
...
issueInput
,
id
:
'
tmp
'
});
commit
(
types
.
ADD_ISSUE_TO_LIST
,
{
list
,
issue
,
position
:
0
});
dispatch
(
'
createNewIssue
'
,
issueInput
)
.
then
(
res
=>
{
commit
(
types
.
ADD_ISSUE_TO_LIST
,
{
list
,
issue
:
formatIssue
(
res
)
});
commit
(
types
.
REMOVE_ISSUE_FROM_LIST
,
{
list
,
issue
});
})
.
catch
(()
=>
commit
(
types
.
ADD_ISSUE_TO_LIST_FAILURE
,
{
list
,
issueId
:
issueInput
.
id
}));
},
setActiveIssueLabels
:
async
({
commit
,
getters
},
input
)
=>
{
...
...
app/assets/javascripts/boards/stores/mutation_types.js
View file @
ec5b51d3
...
...
@@ -17,6 +17,7 @@ export const REMOVE_LIST_FAILURE = 'REMOVE_LIST_FAILURE';
export
const
REQUEST_ISSUES_FOR_LIST
=
'
REQUEST_ISSUES_FOR_LIST
'
;
export
const
RECEIVE_ISSUES_FOR_LIST_FAILURE
=
'
RECEIVE_ISSUES_FOR_LIST_FAILURE
'
;
export
const
RECEIVE_ISSUES_FOR_LIST_SUCCESS
=
'
RECEIVE_ISSUES_FOR_LIST_SUCCESS
'
;
export
const
CREATE_ISSUE_FAILURE
=
'
CREATE_ISSUE_FAILURE
'
;
export
const
REQUEST_ADD_ISSUE
=
'
REQUEST_ADD_ISSUE
'
;
export
const
RECEIVE_ADD_ISSUE_SUCCESS
=
'
RECEIVE_ADD_ISSUE_SUCCESS
'
;
export
const
RECEIVE_ADD_ISSUE_ERROR
=
'
RECEIVE_ADD_ISSUE_ERROR
'
;
...
...
@@ -28,6 +29,7 @@ export const RECEIVE_UPDATE_ISSUE_SUCCESS = 'RECEIVE_UPDATE_ISSUE_SUCCESS';
export
const
RECEIVE_UPDATE_ISSUE_ERROR
=
'
RECEIVE_UPDATE_ISSUE_ERROR
'
;
export
const
ADD_ISSUE_TO_LIST
=
'
ADD_ISSUE_TO_LIST
'
;
export
const
ADD_ISSUE_TO_LIST_FAILURE
=
'
ADD_ISSUE_TO_LIST_FAILURE
'
;
export
const
REMOVE_ISSUE_FROM_LIST
=
'
REMOVE_ISSUE_FROM_LIST
'
;
export
const
SET_CURRENT_PAGE
=
'
SET_CURRENT_PAGE
'
;
export
const
TOGGLE_EMPTY_STATE
=
'
TOGGLE_EMPTY_STATE
'
;
export
const
SET_ACTIVE_ID
=
'
SET_ACTIVE_ID
'
;
...
...
app/assets/javascripts/boards/stores/mutations.js
View file @
ec5b51d3
...
...
@@ -201,16 +201,28 @@ export default {
notImplemented
();
},
[
mutationTypes
.
CREATE_ISSUE_FAILURE
]:
state
=>
{
state
.
error
=
s__
(
'
Boards|An error occurred while creating the issue. Please try again.
'
);
},
[
mutationTypes
.
ADD_ISSUE_TO_LIST
]:
(
state
,
{
list
,
issue
,
position
})
=>
{
const
listIssues
=
state
.
issuesByListId
[
list
.
id
];
listIssues
.
splice
(
position
,
0
,
issue
.
id
);
Vue
.
set
(
state
.
issuesByListId
,
list
.
id
,
listIssues
);
addIssueToList
({
state
,
listId
:
list
.
id
,
issueId
:
issue
.
id
,
atIndex
:
position
,
});
Vue
.
set
(
state
.
issues
,
issue
.
id
,
issue
);
},
[
mutationTypes
.
ADD_ISSUE_TO_LIST_FAILURE
]:
(
state
,
{
list
,
issue
})
=>
{
[
mutationTypes
.
ADD_ISSUE_TO_LIST_FAILURE
]:
(
state
,
{
list
,
issue
Id
})
=>
{
state
.
error
=
s__
(
'
Boards|An error occurred while creating the issue. Please try again.
'
);
removeIssueFromList
({
state
,
listId
:
list
.
id
,
issueId
});
},
[
mutationTypes
.
REMOVE_ISSUE_FROM_LIST
]:
(
state
,
{
list
,
issue
})
=>
{
removeIssueFromList
({
state
,
listId
:
list
.
id
,
issueId
:
issue
.
id
});
Vue
.
delete
(
state
.
issues
,
issue
.
id
);
},
[
mutationTypes
.
SET_CURRENT_PAGE
]:
()
=>
{
...
...
ee/app/assets/javascripts/boards/components/issues_lane_list.vue
View file @
ec5b51d3
...
...
@@ -5,7 +5,7 @@ import { GlLoadingIcon } from '@gitlab/ui';
import
defaultSortableConfig
from
'
~/sortable/sortable_config
'
;
import
BoardCardLayout
from
'
~/boards/components/board_card_layout.vue
'
;
import
eventHub
from
'
~/boards/eventhub
'
;
import
BoardNewIssue
from
'
~/boards/components/board_new_issue.vue
'
;
import
BoardNewIssue
from
'
~/boards/components/board_new_issue
_new
.vue
'
;
import
{
ISSUABLE
}
from
'
~/boards/constants
'
;
export
default
{
...
...
spec/frontend/boards/board_list_new_spec.js
View file @
ec5b51d3
...
...
@@ -77,6 +77,8 @@ const createComponent = ({
provide
:
{
groupId
:
null
,
rootPath
:
'
/
'
,
weightFeatureAvailable
:
false
,
boardWeight
:
null
,
},
});
...
...
spec/frontend/boards/components/board_new_issue_new_spec.js
0 → 100644
View file @
ec5b51d3
import
Vuex
from
'
vuex
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
BoardNewIssue
from
'
~/boards/components/board_new_issue_new.vue
'
;
import
'
~/boards/models/list
'
;
import
{
mockListsWithModel
}
from
'
../mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
describe
(
'
Issue boards new issue form
'
,
()
=>
{
let
wrapper
;
let
vm
;
const
addListNewIssuesSpy
=
jest
.
fn
();
const
findSubmitButton
=
()
=>
wrapper
.
find
({
ref
:
'
submitButton
'
});
const
findCancelButton
=
()
=>
wrapper
.
find
({
ref
:
'
cancelButton
'
});
const
findSubmitForm
=
()
=>
wrapper
.
find
({
ref
:
'
submitForm
'
});
const
submitIssue
=
()
=>
{
const
dummySubmitEvent
=
{
preventDefault
()
{},
};
return
findSubmitForm
().
trigger
(
'
submit
'
,
dummySubmitEvent
);
};
beforeEach
(()
=>
{
const
store
=
new
Vuex
.
Store
({
state
:
{},
actions
:
{
addListNewIssue
:
addListNewIssuesSpy
},
getters
:
{},
});
wrapper
=
shallowMount
(
BoardNewIssue
,
{
propsData
:
{
disabled
:
false
,
list
:
mockListsWithModel
[
0
],
},
store
,
localVue
,
provide
:
{
groupId
:
null
,
weightFeatureAvailable
:
false
,
boardWeight
:
null
,
},
});
vm
=
wrapper
.
vm
;
return
vm
.
$nextTick
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
calls submit if submit button is clicked
'
,
async
()
=>
{
jest
.
spyOn
(
wrapper
.
vm
,
'
submit
'
).
mockImplementation
();
wrapper
.
setData
({
title
:
'
Testing Title
'
});
await
vm
.
$nextTick
();
await
submitIssue
();
expect
(
wrapper
.
vm
.
submit
).
toHaveBeenCalled
();
});
it
(
'
disables submit button if title is empty
'
,
()
=>
{
expect
(
findSubmitButton
().
props
().
disabled
).
toBe
(
true
);
});
it
(
'
enables submit button if title is not empty
'
,
async
()
=>
{
wrapper
.
setData
({
title
:
'
Testing Title
'
});
await
vm
.
$nextTick
();
expect
(
wrapper
.
find
({
ref
:
'
input
'
}).
element
.
value
).
toBe
(
'
Testing Title
'
);
expect
(
findSubmitButton
().
props
().
disabled
).
toBe
(
false
);
});
it
(
'
clears title after clicking cancel
'
,
async
()
=>
{
findCancelButton
().
trigger
(
'
click
'
);
await
vm
.
$nextTick
();
expect
(
vm
.
title
).
toBe
(
''
);
});
describe
(
'
submit success
'
,
()
=>
{
it
(
'
creates new issue
'
,
async
()
=>
{
wrapper
.
setData
({
title
:
'
submit issue
'
});
await
vm
.
$nextTick
();
await
submitIssue
();
expect
(
addListNewIssuesSpy
).
toHaveBeenCalled
();
});
it
(
'
enables button after submit
'
,
async
()
=>
{
jest
.
spyOn
(
wrapper
.
vm
,
'
submit
'
).
mockImplementation
();
wrapper
.
setData
({
title
:
'
submit issue
'
});
await
vm
.
$nextTick
();
await
submitIssue
();
expect
(
findSubmitButton
().
props
().
disabled
).
toBe
(
false
);
});
it
(
'
clears title after submit
'
,
async
()
=>
{
wrapper
.
setData
({
title
:
'
submit issue
'
});
await
vm
.
$nextTick
();
await
submitIssue
();
await
vm
.
$nextTick
();
expect
(
vm
.
title
).
toBe
(
''
);
});
});
});
spec/frontend/boards/mock_data.js
View file @
ec5b51d3
...
...
@@ -291,6 +291,7 @@ export const mockLists = [
assignee
:
null
,
milestone
:
null
,
loading
:
false
,
issuesSize
:
1
,
},
{
id
:
'
gid://gitlab/List/2
'
,
...
...
@@ -308,6 +309,7 @@ export const mockLists = [
assignee
:
null
,
milestone
:
null
,
loading
:
false
,
issuesSize
:
0
,
},
];
...
...
spec/frontend/boards/stores/actions_spec.js
View file @
ec5b51d3
...
...
@@ -674,40 +674,63 @@ describe('setAssignees', () => {
});
describe
(
'
createNewIssue
'
,
()
=>
{
expectNotImplemented
(
actions
.
createNewIssue
);
});
const
state
=
{
boardType
:
'
group
'
,
endpoints
:
{
fullPath
:
'
gitlab-org/gitlab
'
,
},
};
describe
(
'
addListIssue
'
,
()
=>
{
it
(
'
should commit UPDATE_LIST_FAILURE mutation when API returns an error
'
,
done
=>
{
const
payload
=
{
list
:
mockLists
[
0
],
issue
:
mockIssue
,
position
:
0
,
};
it
(
'
should return issue from API on success
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
createIssue
:
{
issue
:
mockIssue
,
errors
:
[],
},
},
});
const
result
=
await
actions
.
createNewIssue
({
state
},
mockIssue
);
expect
(
result
).
toEqual
(
mockIssue
);
});
it
(
'
should commit CREATE_ISSUE_FAILURE mutation when API returns an error
'
,
done
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
createIssue
:
{
issue
:
{},
errors
:
[{
foo
:
'
bar
'
}],
},
},
});
const
payload
=
mockIssue
;
testAction
(
actions
.
addList
Issue
,
actions
.
createNew
Issue
,
payload
,
{}
,
[{
type
:
types
.
ADD_ISSUE_TO_LIST
,
payload
}],
state
,
[{
type
:
types
.
CREATE_ISSUE_FAILURE
}],
[],
done
,
);
});
});
describe
(
'
addListIssue
Failure
'
,
()
=>
{
it
(
'
should commit
UPDATE_LIST_FAILURE mutation when API returns an error
'
,
done
=>
{
describe
(
'
addListIssue
'
,
()
=>
{
it
(
'
should commit
ADD_ISSUE_TO_LIST mutation
'
,
done
=>
{
const
payload
=
{
list
:
mockLists
[
0
],
issue
:
mockIssue
,
position
:
0
,
};
testAction
(
actions
.
addListIssue
Failure
,
actions
.
addListIssue
,
payload
,
{},
[{
type
:
types
.
ADD_ISSUE_TO_LIST
_FAILURE
,
payload
}],
[{
type
:
types
.
ADD_ISSUE_TO_LIST
,
payload
}],
[],
done
,
);
...
...
spec/frontend/boards/stores/mutations_spec.js
View file @
ec5b51d3
...
...
@@ -442,6 +442,14 @@ describe('Board Store Mutations', () => {
expectNotImplemented
(
mutations
.
RECEIVE_UPDATE_ISSUE_ERROR
);
});
describe
(
'
CREATE_ISSUE_FAILURE
'
,
()
=>
{
it
(
'
sets error message on state
'
,
()
=>
{
mutations
.
CREATE_ISSUE_FAILURE
(
state
);
expect
(
state
.
error
).
toBe
(
'
An error occurred while creating the issue. Please try again.
'
);
});
});
describe
(
'
ADD_ISSUE_TO_LIST
'
,
()
=>
{
it
(
'
adds issue to issues state and issue id in list in issuesByListId
'
,
()
=>
{
const
listIssues
=
{
...
...
@@ -455,17 +463,45 @@ describe('Board Store Mutations', () => {
...
state
,
issuesByListId
:
listIssues
,
issues
,
boardLists
:
initialBoardListsState
,
};
mutations
.
ADD_ISSUE_TO_LIST
(
state
,
{
list
:
mockLists
[
0
],
issue
:
mockIssue2
});
expect
(
state
.
boardLists
[
'
gid://gitlab/List/1
'
].
issuesSize
).
toBe
(
1
);
mutations
.
ADD_ISSUE_TO_LIST
(
state
,
{
list
:
mockListsWithModel
[
0
],
issue
:
mockIssue2
});
expect
(
state
.
issuesByListId
[
'
gid://gitlab/List/1
'
]).
toContain
(
mockIssue2
.
id
);
expect
(
state
.
issues
[
mockIssue2
.
id
]).
toEqual
(
mockIssue2
);
expect
(
state
.
boardLists
[
'
gid://gitlab/List/1
'
].
issuesSize
).
toBe
(
2
);
});
});
describe
(
'
ADD_ISSUE_TO_LIST_FAILURE
'
,
()
=>
{
it
(
'
removes issue id from list in issuesByListId
'
,
()
=>
{
it
(
'
removes issue id from list in issuesByListId and sets error message
'
,
()
=>
{
const
listIssues
=
{
'
gid://gitlab/List/1
'
:
[
mockIssue
.
id
,
mockIssue2
.
id
],
};
const
issues
=
{
'
1
'
:
mockIssue
,
'
2
'
:
mockIssue2
,
};
state
=
{
...
state
,
issuesByListId
:
listIssues
,
issues
,
boardLists
:
initialBoardListsState
,
};
mutations
.
ADD_ISSUE_TO_LIST_FAILURE
(
state
,
{
list
:
mockLists
[
0
],
issueId
:
mockIssue2
.
id
});
expect
(
state
.
issuesByListId
[
'
gid://gitlab/List/1
'
]).
not
.
toContain
(
mockIssue2
.
id
);
expect
(
state
.
error
).
toBe
(
'
An error occurred while creating the issue. Please try again.
'
);
});
});
describe
(
'
REMOVE_ISSUE_FROM_LIST
'
,
()
=>
{
it
(
'
removes issue id from list in issuesByListId and deletes issue from state
'
,
()
=>
{
const
listIssues
=
{
'
gid://gitlab/List/1
'
:
[
mockIssue
.
id
,
mockIssue2
.
id
],
};
...
...
@@ -481,9 +517,10 @@ describe('Board Store Mutations', () => {
boardLists
:
initialBoardListsState
,
};
mutations
.
ADD_ISSUE_TO_LIST_FAILURE
(
state
,
{
list
:
mockLists
[
0
],
issue
:
mockIssue2
});
mutations
.
ADD_ISSUE_TO_LIST_FAILURE
(
state
,
{
list
:
mockLists
[
0
],
issue
Id
:
mockIssue2
.
id
});
expect
(
state
.
issuesByListId
[
'
gid://gitlab/List/1
'
]).
not
.
toContain
(
mockIssue2
.
id
);
expect
(
state
.
issues
).
not
.
toContain
(
mockIssue2
);
});
});
...
...
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