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
d43f2768
Commit
d43f2768
authored
Nov 23, 2020
by
Axel Garcia
Committed by
Illya Klymov
Nov 23, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add milestones select to swimlanes board sidebar
It uses gitlab/ui and GraphQL to render the milestones dropdown.
parent
651d6474
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
451 additions
and
4 deletions
+451
-4
app/assets/javascripts/boards/components/sidebar/board_editable_item.vue
...scripts/boards/components/sidebar/board_editable_item.vue
+9
-2
app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue
...ipts/boards/components/sidebar/board_sidebar_due_date.vue
+1
-1
app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
...rds/components/sidebar/board_sidebar_milestone_select.vue
+161
-0
app/assets/javascripts/boards/queries/group_milestones.query.graphql
...javascripts/boards/queries/group_milestones.query.graphql
+17
-0
app/assets/javascripts/boards/queries/issue.fragment.graphql
app/assets/javascripts/boards/queries/issue.fragment.graphql
+4
-0
app/assets/javascripts/boards/queries/issue_set_milestone.mutation.graphql
...ripts/boards/queries/issue_set_milestone.mutation.graphql
+12
-0
app/assets/javascripts/boards/stores/actions.js
app/assets/javascripts/boards/stores/actions.js
+25
-0
ee/app/assets/javascripts/boards/components/board_content_sidebar.vue
...s/javascripts/boards/components/board_content_sidebar.vue
+3
-0
ee/app/assets/javascripts/boards/components/sidebar/board_sidebar_weight_input.vue
.../boards/components/sidebar/board_sidebar_weight_input.vue
+1
-1
ee/app/assets/javascripts/boards/queries/issue.fragment.graphql
.../assets/javascripts/boards/queries/issue.fragment.graphql
+4
-0
ee/spec/frontend/boards/components/board_content_sidebar_spec.js
.../frontend/boards/components/board_content_sidebar_spec.js
+1
-0
locale/gitlab.pot
locale/gitlab.pot
+6
-0
spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
...components/sidebar/board_sidebar_milestone_select_spec.js
+152
-0
spec/frontend/boards/stores/actions_spec.js
spec/frontend/boards/stores/actions_spec.js
+55
-0
No files found.
app/assets/javascripts/boards/components/sidebar/board_editable_item.vue
View file @
d43f2768
...
...
@@ -50,6 +50,13 @@ export default {
}
window
.
removeEventListener
(
'
click
'
,
this
.
collapseWhenOffClick
);
},
toggle
({
emitEvent
=
true
}
=
{})
{
if
(
this
.
edit
)
{
this
.
collapse
({
emitEvent
});
}
else
{
this
.
expand
();
}
},
},
};
</
script
>
...
...
@@ -66,12 +73,12 @@ export default {
variant=
"link"
class=
"gl-text-gray-900! js-sidebar-dropdown-toggle"
data-testid=
"edit-button"
@
click=
"
expand
"
@
click=
"
toggle
"
>
{{
__
(
'
Edit
'
)
}}
</gl-button>
</div>
<div
v-show=
"!edit"
class=
"gl-text-gray-
4
00"
data-testid=
"collapsed-content"
>
<div
v-show=
"!edit"
class=
"gl-text-gray-
5
00"
data-testid=
"collapsed-content"
>
<slot
name=
"collapsed"
>
{{
__
(
'
None
'
)
}}
</slot>
</div>
<div
v-show=
"edit"
data-testid=
"expanded-content"
>
...
...
app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue
View file @
d43f2768
...
...
@@ -79,7 +79,7 @@ export default {
<span
class=
"gl-mx-2"
>
-
</span>
<gl-button
variant=
"link"
class=
"gl-text-gray-
4
00!"
class=
"gl-text-gray-
5
00!"
data-testid=
"reset-button"
:disabled=
"loading"
@
click=
"setDueDate(null)"
...
...
app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
0 → 100644
View file @
d43f2768
<
script
>
import
{
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
{
GlDropdown
,
GlDropdownItem
,
GlDropdownText
,
GlSearchBoxByType
,
GlDropdownDivider
,
GlLoadingIcon
,
}
from
'
@gitlab/ui
'
;
import
{
fetchPolicies
}
from
'
~/lib/graphql
'
;
import
BoardEditableItem
from
'
~/boards/components/sidebar/board_editable_item.vue
'
;
import
groupMilestones
from
'
../../queries/group_milestones.query.graphql
'
;
import
createFlash
from
'
~/flash
'
;
import
{
__
,
s__
}
from
'
~/locale
'
;
export
default
{
components
:
{
BoardEditableItem
,
GlDropdown
,
GlLoadingIcon
,
GlDropdownItem
,
GlDropdownText
,
GlSearchBoxByType
,
GlDropdownDivider
,
},
data
()
{
return
{
milestones
:
[],
searchTitle
:
''
,
loading
:
false
,
edit
:
false
,
};
},
apollo
:
{
milestones
:
{
fetchPolicy
:
fetchPolicies
.
CACHE_AND_NETWORK
,
query
:
groupMilestones
,
debounce
:
250
,
skip
()
{
return
!
this
.
edit
;
},
variables
()
{
return
{
fullPath
:
this
.
groupFullPath
,
searchTitle
:
this
.
searchTitle
,
state
:
'
active
'
,
includeDescendants
:
true
,
};
},
update
(
data
)
{
const
edges
=
data
?.
group
?.
milestones
?.
edges
??
[];
return
edges
.
map
(
item
=>
item
.
node
);
},
error
()
{
createFlash
({
message
:
this
.
$options
.
i18n
.
fetchMilestonesError
});
},
},
},
computed
:
{
...
mapGetters
({
issue
:
'
activeIssue
'
}),
hasMilestone
()
{
return
this
.
issue
.
milestone
!==
null
;
},
groupFullPath
()
{
const
{
referencePath
=
''
}
=
this
.
issue
;
return
referencePath
.
slice
(
0
,
referencePath
.
indexOf
(
'
/
'
));
},
projectPath
()
{
const
{
referencePath
=
''
}
=
this
.
issue
;
return
referencePath
.
slice
(
0
,
referencePath
.
indexOf
(
'
#
'
));
},
dropdownText
()
{
return
this
.
issue
.
milestone
?.
title
??
this
.
$options
.
i18n
.
noMilestone
;
},
},
mounted
()
{
this
.
$root
.
$on
(
'
bv::dropdown::hide
'
,
()
=>
{
this
.
$refs
.
sidebarItem
.
collapse
();
});
},
methods
:
{
...
mapActions
([
'
setActiveIssueMilestone
'
]),
handleOpen
()
{
this
.
edit
=
true
;
this
.
$refs
.
dropdown
.
show
();
},
async
setMilestone
(
milestoneId
)
{
this
.
loading
=
true
;
this
.
searchTitle
=
''
;
this
.
$refs
.
sidebarItem
.
collapse
();
try
{
const
input
=
{
milestoneId
,
projectPath
:
this
.
projectPath
};
await
this
.
setActiveIssueMilestone
(
input
);
}
catch
(
e
)
{
createFlash
({
message
:
this
.
$options
.
i18n
.
updateMilestoneError
});
}
finally
{
this
.
loading
=
false
;
}
},
},
i18n
:
{
milestone
:
__
(
'
Milestone
'
),
noMilestone
:
__
(
'
No milestone
'
),
assignMilestone
:
__
(
'
Assign milestone
'
),
noMilestonesFound
:
s__
(
'
Milestones|No milestones found
'
),
fetchMilestonesError
:
__
(
'
There was a problem fetching milestones.
'
),
updateMilestoneError
:
__
(
'
An error occurred while updating the milestone.
'
),
},
};
</
script
>
<
template
>
<board-editable-item
ref=
"sidebarItem"
:title=
"$options.i18n.milestone"
:loading=
"loading"
@
open=
"handleOpen()"
@
close=
"edit = false"
>
<template
v-if=
"hasMilestone"
#collapsed
>
<strong
class=
"gl-text-gray-900"
>
{{
issue
.
milestone
.
title
}}
</strong>
</
template
>
<
template
>
<gl-dropdown
ref=
"dropdown"
:text=
"dropdownText"
:header-text=
"$options.i18n.assignMilestone"
block
>
<gl-search-box-by-type
ref=
"search"
v-model.trim=
"searchTitle"
class=
"gl-m-3"
/>
<gl-dropdown-item
data-testid=
"no-milestone-item"
:is-check-item=
"true"
:is-checked=
"!issue.milestone"
@
click=
"setMilestone(null)"
>
{{
$options
.
i18n
.
noMilestone
}}
</gl-dropdown-item>
<gl-dropdown-divider
/>
<gl-loading-icon
v-if=
"$apollo.loading"
class=
"gl-py-4"
/>
<template
v-else-if=
"milestones.length > 0"
>
<gl-dropdown-item
v-for=
"milestone in milestones"
:key=
"milestone.id"
:is-check-item=
"true"
:is-checked=
"issue.milestone && milestone.id === issue.milestone.id"
data-testid=
"milestone-item"
@
click=
"setMilestone(milestone.id)"
>
{{
milestone
.
title
}}
</gl-dropdown-item>
</
template
>
<gl-dropdown-text
v-else
data-testid=
"no-milestones-found"
>
{{ $options.i18n.noMilestonesFound }}
</gl-dropdown-text>
</gl-dropdown>
</template>
</board-editable-item>
</template>
app/assets/javascripts/boards/queries/group_milestones.query.graphql
0 → 100644
View file @
d43f2768
query
groupMilestones
(
$fullPath
:
ID
!
$state
:
MilestoneStateEnum
$includeDescendants
:
Boolean
$searchTitle
:
String
)
{
group
(
fullPath
:
$fullPath
)
{
milestones
(
state
:
$state
,
includeDescendants
:
$includeDescendants
,
searchTitle
:
$searchTitle
)
{
edges
{
node
{
id
title
}
}
}
}
}
app/assets/javascripts/boards/queries/issue.fragment.graphql
View file @
d43f2768
...
...
@@ -11,6 +11,10 @@ fragment IssueNode on Issue {
webUrl
subscribed
relativePosition
milestone
{
id
title
}
assignees
{
nodes
{
...
User
...
...
app/assets/javascripts/boards/queries/issue_set_milestone.mutation.graphql
0 → 100644
View file @
d43f2768
mutation
issueSetMilestone
(
$input
:
UpdateIssueInput
!)
{
updateIssue
(
input
:
$input
)
{
issue
{
milestone
{
id
title
description
}
}
errors
}
}
app/assets/javascripts/boards/stores/actions.js
View file @
d43f2768
...
...
@@ -25,6 +25,7 @@ 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
'
;
import
issueSetSubscriptionMutation
from
'
../graphql/mutations/issue_set_subscription.mutation.graphql
'
;
import
issueSetMilestone
from
'
../queries/issue_set_milestone.mutation.graphql
'
;
const
notImplemented
=
()
=>
{
/* eslint-disable-next-line @gitlab/require-i18n-strings */
...
...
@@ -337,6 +338,30 @@ export default {
});
},
setActiveIssueMilestone
:
async
({
commit
,
getters
},
input
)
=>
{
const
{
activeIssue
}
=
getters
;
const
{
data
}
=
await
gqlClient
.
mutate
({
mutation
:
issueSetMilestone
,
variables
:
{
input
:
{
iid
:
String
(
activeIssue
.
iid
),
milestoneId
:
getIdFromGraphQLId
(
input
.
milestoneId
),
projectPath
:
input
.
projectPath
,
},
},
});
if
(
data
.
updateIssue
.
errors
?.
length
>
0
)
{
throw
new
Error
(
data
.
updateIssue
.
errors
);
}
commit
(
types
.
UPDATE_ISSUE_BY_ID
,
{
issueId
:
activeIssue
.
id
,
prop
:
'
milestone
'
,
value
:
data
.
updateIssue
.
issue
.
milestone
,
});
},
createNewIssue
:
({
commit
,
state
},
issueInput
)
=>
{
const
input
=
issueInput
;
const
{
boardType
,
endpoints
}
=
state
;
...
...
ee/app/assets/javascripts/boards/components/board_content_sidebar.vue
View file @
d43f2768
...
...
@@ -12,6 +12,7 @@ import BoardSidebarWeightInput from './sidebar/board_sidebar_weight_input.vue';
import
BoardSidebarLabelsSelect
from
'
~/boards/components/sidebar/board_sidebar_labels_select.vue
'
;
import
BoardSidebarDueDate
from
'
~/boards/components/sidebar/board_sidebar_due_date.vue
'
;
import
BoardSidebarSubscription
from
'
~/boards/components/sidebar/board_sidebar_subscription.vue
'
;
import
BoardSidebarMilestoneSelect
from
'
~/boards/components/sidebar/board_sidebar_milestone_select.vue
'
;
export
default
{
headerHeight
:
`
${
contentTop
()}
px`
,
...
...
@@ -25,6 +26,7 @@ export default {
BoardSidebarLabelsSelect
,
BoardSidebarDueDate
,
BoardSidebarSubscription
,
BoardSidebarMilestoneSelect
,
},
mixins
:
[
glFeatureFlagsMixin
()],
computed
:
{
...
...
@@ -59,6 +61,7 @@ export default {
<board-sidebar-labels-select
/>
<board-sidebar-due-date
/>
<board-sidebar-subscription
/>
<board-sidebar-milestone-select
/>
</
template
>
</gl-drawer>
</template>
ee/app/assets/javascripts/boards/components/sidebar/board_sidebar_weight_input.vue
View file @
d43f2768
...
...
@@ -78,7 +78,7 @@ export default {
<span
class=
"gl-mx-2"
>
-
</span>
<gl-button
variant=
"link"
class=
"gl-text-gray-
4
00!"
class=
"gl-text-gray-
5
00!"
data-testid=
"reset-button"
:disabled=
"loading"
@
click=
"setWeight(0)"
...
...
ee/app/assets/javascripts/boards/queries/issue.fragment.graphql
View file @
d43f2768
...
...
@@ -21,6 +21,10 @@ fragment IssueNode on Issue {
epic
{
id
}
milestone
{
id
title
}
assignees
{
nodes
{
...
User
...
...
ee/spec/frontend/boards/components/board_content_sidebar_spec.js
View file @
d43f2768
...
...
@@ -25,6 +25,7 @@ describe('ee/BoardContentSidebar', () => {
'
board-sidebar-labels-select
'
:
'
<div></div>
'
,
'
board-sidebar-due-date
'
:
'
<div></div>
'
,
'
board-sidebar-subscription
'
:
'
<div></div>
'
,
'
board-sidebar-milestone-select
'
:
'
<div></div>
'
,
},
});
};
...
...
locale/gitlab.pot
View file @
d43f2768
...
...
@@ -3243,6 +3243,9 @@ msgstr ""
msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while updating the milestone."
msgstr ""
msgid "An error occurred while validating group path"
msgstr ""
...
...
@@ -17599,6 +17602,9 @@ msgstr ""
msgid "Milestones|Milestone %{milestoneTitle} was not found"
msgstr ""
msgid "Milestones|No milestones found"
msgstr ""
msgid "Milestones|Ongoing Issues (open and assigned)"
msgstr ""
...
...
spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
0 → 100644
View file @
d43f2768
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
mockMilestone
as
TEST_MILESTONE
}
from
'
jest/boards/mock_data
'
;
import
BoardSidebarMilestoneSelect
from
'
~/boards/components/sidebar/board_sidebar_milestone_select.vue
'
;
import
BoardEditableItem
from
'
~/boards/components/sidebar/board_editable_item.vue
'
;
import
{
createStore
}
from
'
~/boards/stores
'
;
import
createFlash
from
'
~/flash
'
;
const
TEST_ISSUE
=
{
id
:
'
gid://gitlab/Issue/1
'
,
iid
:
9
,
referencePath
:
'
h/b#2
'
};
jest
.
mock
(
'
~/flash
'
);
describe
(
'
~/boards/components/sidebar/board_sidebar_milestone_select.vue
'
,
()
=>
{
let
wrapper
;
let
store
;
afterEach
(()
=>
{
wrapper
.
destroy
();
store
=
null
;
wrapper
=
null
;
});
const
createWrapper
=
({
milestone
=
null
}
=
{})
=>
{
store
=
createStore
();
store
.
state
.
issues
=
{
[
TEST_ISSUE
.
id
]:
{
...
TEST_ISSUE
,
milestone
}
};
store
.
state
.
activeId
=
TEST_ISSUE
.
id
;
wrapper
=
shallowMount
(
BoardSidebarMilestoneSelect
,
{
store
,
provide
:
{
canUpdate
:
true
,
},
data
:
()
=>
({
milestones
:
[
TEST_MILESTONE
],
}),
stubs
:
{
'
board-editable-item
'
:
BoardEditableItem
,
},
mocks
:
{
$apollo
:
{
loading
:
false
,
},
},
});
};
const
findCollapsed
=
()
=>
wrapper
.
find
(
'
[data-testid="collapsed-content"]
'
);
const
findLoader
=
()
=>
wrapper
.
find
(
GlLoadingIcon
);
const
findDropdownItem
=
()
=>
wrapper
.
find
(
'
[data-testid="milestone-item"]
'
);
const
findUnsetMilestoneItem
=
()
=>
wrapper
.
find
(
'
[data-testid="no-milestone-item"]
'
);
const
findNoMilestonesFoundItem
=
()
=>
wrapper
.
find
(
'
[data-testid="no-milestones-found"]
'
);
it
(
'
renders "None" when no milestone is selected
'
,
()
=>
{
createWrapper
();
expect
(
findCollapsed
().
text
()).
toBe
(
'
None
'
);
});
it
(
'
renders milestone title when set
'
,
()
=>
{
createWrapper
({
milestone
:
TEST_MILESTONE
});
expect
(
findCollapsed
().
text
()).
toContain
(
TEST_MILESTONE
.
title
);
});
it
(
'
shows loader while Apollo is loading
'
,
async
()
=>
{
createWrapper
({
milestone
:
TEST_MILESTONE
});
expect
(
findLoader
().
exists
()).
toBe
(
false
);
wrapper
.
vm
.
$apollo
.
loading
=
true
;
await
wrapper
.
vm
.
$nextTick
();
expect
(
findLoader
().
exists
()).
toBe
(
true
);
});
it
(
'
shows message when error or no milestones found
'
,
async
()
=>
{
createWrapper
();
wrapper
.
setData
({
milestones
:
[]
});
await
wrapper
.
vm
.
$nextTick
();
expect
(
findNoMilestonesFoundItem
().
text
()).
toBe
(
'
No milestones found
'
);
});
describe
(
'
when milestone is selected
'
,
()
=>
{
beforeEach
(
async
()
=>
{
createWrapper
();
jest
.
spyOn
(
wrapper
.
vm
,
'
setActiveIssueMilestone
'
).
mockImplementation
(()
=>
{
store
.
state
.
issues
[
TEST_ISSUE
.
id
].
milestone
=
TEST_MILESTONE
;
});
findDropdownItem
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
});
it
(
'
collapses sidebar and renders selected milestone
'
,
()
=>
{
expect
(
findCollapsed
().
isVisible
()).
toBe
(
true
);
expect
(
findCollapsed
().
text
()).
toContain
(
TEST_MILESTONE
.
title
);
});
it
(
'
commits change to the server
'
,
()
=>
{
expect
(
wrapper
.
vm
.
setActiveIssueMilestone
).
toHaveBeenCalledWith
({
milestoneId
:
TEST_MILESTONE
.
id
,
projectPath
:
'
h/b
'
,
});
});
});
describe
(
'
when milestone is set to "None"
'
,
()
=>
{
beforeEach
(
async
()
=>
{
createWrapper
({
milestone
:
TEST_MILESTONE
});
jest
.
spyOn
(
wrapper
.
vm
,
'
setActiveIssueMilestone
'
).
mockImplementation
(()
=>
{
store
.
state
.
issues
[
TEST_ISSUE
.
id
].
milestone
=
null
;
});
findUnsetMilestoneItem
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
});
it
(
'
collapses sidebar and renders "None"
'
,
()
=>
{
expect
(
findCollapsed
().
isVisible
()).
toBe
(
true
);
expect
(
findCollapsed
().
text
()).
toBe
(
'
None
'
);
});
it
(
'
commits change to the server
'
,
()
=>
{
expect
(
wrapper
.
vm
.
setActiveIssueMilestone
).
toHaveBeenCalledWith
({
milestoneId
:
null
,
projectPath
:
'
h/b
'
,
});
});
});
describe
(
'
when the mutation fails
'
,
()
=>
{
const
testMilestone
=
{
id
:
'
1
'
,
title
:
'
Former milestone
'
};
beforeEach
(
async
()
=>
{
createWrapper
({
milestone
:
testMilestone
});
jest
.
spyOn
(
wrapper
.
vm
,
'
setActiveIssueMilestone
'
).
mockImplementation
(()
=>
{
throw
new
Error
([
'
failed mutation
'
]);
});
findDropdownItem
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
});
it
(
'
collapses sidebar and renders former milestone
'
,
()
=>
{
expect
(
findCollapsed
().
isVisible
()).
toBe
(
true
);
expect
(
findCollapsed
().
text
()).
toContain
(
testMilestone
.
title
);
expect
(
createFlash
).
toHaveBeenCalled
();
});
});
});
spec/frontend/boards/stores/actions_spec.js
View file @
d43f2768
...
...
@@ -8,6 +8,7 @@ import {
mockIssue2WithModel
,
rawIssue
,
mockIssues
,
mockMilestone
,
labels
,
mockActiveIssue
,
}
from
'
../mock_data
'
;
...
...
@@ -885,6 +886,60 @@ describe('setActiveIssueSubscribed', () => {
});
});
describe
(
'
setActiveIssueMilestone
'
,
()
=>
{
const
state
=
{
issues
:
{
[
mockIssue
.
id
]:
mockIssue
}
};
const
getters
=
{
activeIssue
:
mockIssue
};
const
testMilestone
=
{
...
mockMilestone
,
id
:
'
gid://gitlab/Milestone/1
'
,
};
const
input
=
{
milestoneId
:
testMilestone
.
id
,
projectPath
:
'
h/b
'
,
};
it
(
'
should commit milestone after setting the issue
'
,
done
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
updateIssue
:
{
issue
:
{
milestone
:
testMilestone
,
},
errors
:
[],
},
},
});
const
payload
=
{
issueId
:
getters
.
activeIssue
.
id
,
prop
:
'
milestone
'
,
value
:
testMilestone
,
};
testAction
(
actions
.
setActiveIssueMilestone
,
input
,
{
...
state
,
...
getters
},
[
{
type
:
types
.
UPDATE_ISSUE_BY_ID
,
payload
,
},
],
[],
done
,
);
});
it
(
'
throws error if fails
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
)
.
mockResolvedValue
({
data
:
{
updateIssue
:
{
errors
:
[
'
failed mutation
'
]
}
}
});
await
expect
(
actions
.
setActiveIssueMilestone
({
getters
},
input
)).
rejects
.
toThrow
(
Error
);
});
});
describe
(
'
fetchBacklog
'
,
()
=>
{
expectNotImplemented
(
actions
.
fetchBacklog
);
});
...
...
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