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
07290d35
Commit
07290d35
authored
Jul 13, 2020
by
Axel García
Committed by
Miguel Rincon
Jul 17, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add test for the new epic button on epic header
Also some refactoring on the test and selectors
parent
c3a7d311
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
92 additions
and
70 deletions
+92
-70
ee/app/assets/javascripts/epic/components/epic_header.vue
ee/app/assets/javascripts/epic/components/epic_header.vue
+16
-13
ee/spec/frontend/epic/components/epic_header_spec.js
ee/spec/frontend/epic/components/epic_header_spec.js
+76
-57
No files found.
ee/app/assets/javascripts/epic/components/epic_header.vue
View file @
07290d35
...
@@ -45,12 +45,7 @@ export default {
...
@@ -45,12 +45,7 @@ export default {
return
this
.
isEpicOpen
?
__
(
'
Open
'
)
:
__
(
'
Closed
'
);
return
this
.
isEpicOpen
?
__
(
'
Open
'
)
:
__
(
'
Closed
'
);
},
},
actionButtonClass
()
{
actionButtonClass
()
{
// False positive css classes
return
`qa-close-reopen-epic-button
${
this
.
isEpicOpen
?
'
btn-close
'
:
'
btn-open
'
}
`
;
// https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/24
// eslint-disable-next-line @gitlab/require-i18n-strings
return
`js-btn-epic-action qa-close-reopen-epic-button
${
this
.
isEpicOpen
?
'
btn-close
'
:
'
btn-open
'
}
`
;
},
},
actionButtonText
()
{
actionButtonText
()
{
return
this
.
isEpicOpen
?
__
(
'
Close epic
'
)
:
__
(
'
Reopen epic
'
);
return
this
.
isEpicOpen
?
__
(
'
Close epic
'
)
:
__
(
'
Reopen epic
'
);
...
@@ -88,12 +83,17 @@ export default {
...
@@ -88,12 +83,17 @@ export default {
<div
<div
:class=
"
{ 'status-box-open': isEpicOpen, 'status-box-issue-closed': !isEpicOpen }"
:class=
"
{ 'status-box-open': isEpicOpen, 'status-box-issue-closed': !isEpicOpen }"
class="issuable-status-box status-box"
class="issuable-status-box status-box"
data-testid="status-box"
>
>
<gl-icon
:name=
"statusIcon"
class=
"d-block d-sm-none"
/>
<gl-icon
:name=
"statusIcon"
class=
"d-block d-sm-none"
/>
<span
class=
"d-none d-sm-block"
>
{{
statusText
}}
</span>
<span
class=
"d-none d-sm-block"
>
{{
statusText
}}
</span>
</div>
</div>
<div
class=
"issuable-meta"
>
<div
class=
"issuable-meta"
data-testid=
"author-details"
>
<div
v-if=
"confidential"
class=
"issuable-warning-icon inline"
>
<div
v-if=
"confidential"
class=
"issuable-warning-icon inline"
data-testid=
"confidential-icon"
>
<gl-icon
name=
"eye-slash"
class=
"icon"
/>
<gl-icon
name=
"eye-slash"
class=
"icon"
/>
</div>
</div>
{{
__
(
'
Opened
'
)
}}
{{
__
(
'
Opened
'
)
}}
...
@@ -117,14 +117,16 @@ export default {
...
@@ -117,14 +117,16 @@ export default {
</div>
</div>
<gl-button
<gl-button
:aria-label=
"__('Toggle sidebar')"
:aria-label=
"__('Toggle sidebar')"
class=
"float-right gl-display-block d-sm-none gl-align-self-center gutter-toggle issuable-gutter-toggle js-sidebar-toggle"
type=
"button"
type=
"button"
class=
"float-right gl-display-block d-sm-none gl-align-self-center gutter-toggle issuable-gutter-toggle"
data-testid=
"sidebar-toggle"
@
click=
"toggleSidebar(
{ sidebarCollapsed })"
@
click=
"toggleSidebar(
{ sidebarCollapsed })"
>
>
<i
class=
"fa fa-angle-double-left"
></i>
<i
class=
"fa fa-angle-double-left"
></i>
</gl-button>
</gl-button>
<div
<div
class=
"detail-page-header-actions gl-display-flex gl-flex-wrap gl-align-items-center gl-w-full gl-w-sm-auto js-issuable-actions"
class=
"detail-page-header-actions gl-display-flex gl-flex-wrap gl-align-items-center gl-w-full gl-sm-w-auto!"
data-testid=
"action-buttons"
>
>
<gl-button
<gl-button
v-if=
"canUpdate"
v-if=
"canUpdate"
...
@@ -132,7 +134,8 @@ export default {
...
@@ -132,7 +134,8 @@ export default {
:class=
"actionButtonClass"
:class=
"actionButtonClass"
category=
"secondary"
category=
"secondary"
variant=
"warning"
variant=
"warning"
class=
"gl-mt-3 gl-mt-sm-0 gl-w-full gl-w-sm-auto"
class=
"gl-mt-3 gl-sm-mt-0! gl-w-full gl-sm-w-auto!"
data-testid=
"toggle-status-button"
@
click=
"toggleEpicStatus(isEpicOpen)"
@
click=
"toggleEpicStatus(isEpicOpen)"
>
>
{{
actionButtonText
}}
{{
actionButtonText
}}
...
@@ -140,10 +143,10 @@ export default {
...
@@ -140,10 +143,10 @@ export default {
<gl-button
<gl-button
v-if=
"userCanCreate"
v-if=
"userCanCreate"
:href=
"newEpicWebUrl"
:href=
"newEpicWebUrl"
data-testid=
"new-epic-button"
class=
"gl-mt-3 gl-mt-sm-0 gl-ml-sm-3 gl-w-full gl-w-sm-auto"
category=
"secondary"
category=
"secondary"
variant=
"success"
variant=
"success"
class=
"gl-mt-3 gl-sm-mt-0! gl-sm-ml-3 gl-w-full gl-sm-w-auto!"
data-testid=
"new-epic-button"
>
>
{{
__
(
'
New epic
'
)
}}
{{
__
(
'
New epic
'
)
}}
</gl-button>
</gl-button>
...
...
ee/spec/frontend/epic/components/epic_header_spec.js
View file @
07290d35
import
Vue
from
'
vue
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
GlIcon
}
from
'
@gitlab/ui
'
;
import
UserAvatarLink
from
'
~/vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
UserAvatarLink
from
'
~/vue_shared/components/user_avatar/user_avatar_link.vue
'
;
...
@@ -11,13 +9,10 @@ import { statusType } from 'ee/epic/constants';
...
@@ -11,13 +9,10 @@ import { statusType } from 'ee/epic/constants';
import
{
mockEpicMeta
,
mockEpicData
}
from
'
../mock_data
'
;
import
{
mockEpicMeta
,
mockEpicData
}
from
'
../mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
describe
(
'
EpicHeaderComponent
'
,
()
=>
{
describe
(
'
EpicHeaderComponent
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
let
vm
;
let
store
;
let
store
;
let
features
=
{};
beforeEach
(()
=>
{
beforeEach
(()
=>
{
store
=
createStore
();
store
=
createStore
();
...
@@ -25,135 +20,159 @@ describe('EpicHeaderComponent', () => {
...
@@ -25,135 +20,159 @@ describe('EpicHeaderComponent', () => {
store
.
dispatch
(
'
setEpicData
'
,
mockEpicData
);
store
.
dispatch
(
'
setEpicData
'
,
mockEpicData
);
wrapper
=
shallowMount
(
EpicHeader
,
{
wrapper
=
shallowMount
(
EpicHeader
,
{
localVue
,
store
,
store
,
provide
:
{
glFeatures
:
features
,
},
});
});
vm
=
wrapper
.
vm
;
});
});
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
wrapper
=
null
;
});
});
const
findStatusBox
=
()
=>
wrapper
.
find
(
'
[data-testid="status-box"]
'
);
const
findConfidentialIcon
=
()
=>
wrapper
.
find
(
'
[data-testid="confidential-icon"]
'
).
find
(
GlIcon
);
const
findAuthorDetails
=
()
=>
wrapper
.
find
(
'
[data-testid="author-details"]
'
);
const
findActionButtons
=
()
=>
wrapper
.
find
(
'
[data-testid="action-buttons"]
'
);
const
findNewEpicButton
=
()
=>
wrapper
.
find
(
'
[data-testid="new-epic-button"]
'
);
const
findSidebarToggle
=
()
=>
wrapper
.
find
(
'
[data-testid="sidebar-toggle"]
'
);
describe
(
'
computed
'
,
()
=>
{
describe
(
'
computed
'
,
()
=>
{
describe
(
'
statusIcon
'
,
()
=>
{
describe
(
'
statusIcon
'
,
()
=>
{
it
(
'
returns string `issue-open-m` when `isEpicOpen` is true
'
,
()
=>
{
it
(
'
returns string `issue-open-m` when `isEpicOpen` is true
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
open
;
store
.
state
.
state
=
statusType
.
open
;
expect
(
vm
.
statusIcon
).
toBe
(
'
issue-open-m
'
);
expect
(
wrapper
.
vm
.
statusIcon
).
toBe
(
'
issue-open-m
'
);
});
});
it
(
'
returns string `mobile-issue-close` when `isEpicOpen` is false
'
,
()
=>
{
it
(
'
returns string `mobile-issue-close` when `isEpicOpen` is false
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
close
;
store
.
state
.
state
=
statusType
.
close
;
expect
(
vm
.
statusIcon
).
toBe
(
'
mobile-issue-close
'
);
expect
(
wrapper
.
vm
.
statusIcon
).
toBe
(
'
mobile-issue-close
'
);
});
});
});
});
describe
(
'
statusText
'
,
()
=>
{
describe
(
'
statusText
'
,
()
=>
{
it
(
'
returns string `Open` when `isEpicOpen` is true
'
,
()
=>
{
it
(
'
returns string `Open` when `isEpicOpen` is true
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
open
;
store
.
state
.
state
=
statusType
.
open
;
expect
(
vm
.
statusText
).
toBe
(
'
Open
'
);
expect
(
wrapper
.
vm
.
statusText
).
toBe
(
'
Open
'
);
});
});
it
(
'
returns string `Closed` when `isEpicOpen` is false
'
,
()
=>
{
it
(
'
returns string `Closed` when `isEpicOpen` is false
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
close
;
store
.
state
.
state
=
statusType
.
close
;
expect
(
vm
.
statusText
).
toBe
(
'
Closed
'
);
expect
(
wrapper
.
vm
.
statusText
).
toBe
(
'
Closed
'
);
});
});
});
});
describe
(
'
actionButtonClass
'
,
()
=>
{
describe
(
'
actionButtonClass
'
,
()
=>
{
it
(
'
returns
default button classes along with
`btn-close` when `isEpicOpen` is true
'
,
()
=>
{
it
(
'
returns `btn-close` when `isEpicOpen` is true
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
open
;
store
.
state
.
state
=
statusType
.
open
;
expect
(
vm
.
actionButtonClass
).
toBe
(
expect
(
wrapper
.
vm
.
actionButtonClass
).
toContain
(
'
btn-close
'
);
'
js-btn-epic-action qa-close-reopen-epic-button btn-close
'
,
);
});
});
it
(
'
returns
default button classes along with
`btn-open` when `isEpicOpen` is false
'
,
()
=>
{
it
(
'
returns `btn-open` when `isEpicOpen` is false
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
close
;
store
.
state
.
state
=
statusType
.
close
;
expect
(
vm
.
actionButtonClass
).
toBe
(
expect
(
wrapper
.
vm
.
actionButtonClass
).
toContain
(
'
btn-open
'
);
'
js-btn-epic-action qa-close-reopen-epic-button btn-open
'
,
);
});
});
});
});
describe
(
'
actionButtonText
'
,
()
=>
{
describe
(
'
actionButtonText
'
,
()
=>
{
it
(
'
returns string `Close epic` when `isEpicOpen` is true
'
,
()
=>
{
it
(
'
returns string `Close epic` when `isEpicOpen` is true
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
open
;
store
.
state
.
state
=
statusType
.
open
;
expect
(
vm
.
actionButtonText
).
toBe
(
'
Close epic
'
);
expect
(
wrapper
.
vm
.
actionButtonText
).
toBe
(
'
Close epic
'
);
});
});
it
(
'
returns string `Reopen epic` when `isEpicOpen` is false
'
,
()
=>
{
it
(
'
returns string `Reopen epic` when `isEpicOpen` is false
'
,
()
=>
{
vm
.
$
store
.
state
.
state
=
statusType
.
close
;
store
.
state
.
state
=
statusType
.
close
;
expect
(
vm
.
actionButtonText
).
toBe
(
'
Reopen epic
'
);
expect
(
wrapper
.
vm
.
actionButtonText
).
toBe
(
'
Reopen epic
'
);
});
});
});
});
});
});
describe
(
'
template
'
,
()
=>
{
describe
(
'
template
'
,
()
=>
{
it
(
'
renders component container element with class `detail-page-header`
'
,
()
=>
{
it
(
'
renders component container element with class `detail-page-header`
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
detail-page-header
'
)).
toBe
(
true
);
expect
(
wrapper
.
classes
()).
toContain
(
'
detail-page-header
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.detail-page-header-body
'
)).
not
.
toBeNull
();
expect
(
wrapper
.
find
(
'
.detail-page-header-body
'
).
exists
()).
toBeTruthy
();
});
});
it
(
'
renders epic status icon and text elements
'
,
()
=>
{
it
(
'
renders epic status icon and text elements
'
,
()
=>
{
const
status
El
=
wrapper
.
find
(
'
.issuable-status-box
'
);
const
status
Box
=
findStatusBox
(
);
expect
(
status
El
.
exists
()).
toBe
(
true
);
expect
(
status
Box
.
exists
()).
toBe
(
true
);
expect
(
status
El
.
find
(
GlIcon
).
props
(
'
name
'
)).
toBe
(
'
issue-open-m
'
);
expect
(
status
Box
.
find
(
GlIcon
).
props
(
'
name
'
)).
toBe
(
'
issue-open-m
'
);
expect
(
status
El
.
find
(
'
span
'
).
text
()).
toBe
(
'
Open
'
);
expect
(
status
Box
.
find
(
'
span
'
).
text
()).
toBe
(
'
Open
'
);
});
});
it
(
'
renders confidential icon when `confidential` prop is true
'
,
()
=>
{
it
(
'
renders confidential icon when `confidential` prop is true
'
,
()
=>
{
vm
.
$store
.
state
.
confidential
=
true
;
store
.
state
.
confidential
=
true
;
return
wrapper
.
vm
.
$nextTick
(()
=>
{
const
confidentialIcon
=
findConfidentialIcon
();
return
Vue
.
nextTick
(()
=>
{
expect
(
confidentialIcon
.
exists
()).
toBe
(
true
);
const
iconEl
=
wrapper
.
find
(
'
.issuable-warning-icon
'
).
find
(
GlIcon
);
expect
(
confidentialIcon
.
props
(
'
name
'
)).
toBe
(
'
eye-slash
'
);
expect
(
iconEl
.
exists
()).
toBe
(
true
);
expect
(
iconEl
.
props
(
'
name
'
)).
toBe
(
'
eye-slash
'
);
});
});
});
});
it
(
'
renders epic author details element
'
,
()
=>
{
it
(
'
renders epic author details element
'
,
()
=>
{
const
metaEl
=
wrapper
.
find
(
'
.issuable-meta
'
);
const
epicDetails
=
findAuthorDetails
(
);
expect
(
metaEl
.
exists
()).
toBe
(
true
);
expect
(
epicDetails
.
exists
()).
toBe
(
true
);
expect
(
metaEl
.
find
(
TimeagoTooltip
).
exists
()).
toBe
(
true
);
expect
(
epicDetails
.
find
(
TimeagoTooltip
).
exists
()).
toBe
(
true
);
expect
(
metaEl
.
find
(
UserAvatarLink
).
exists
()).
toBe
(
true
);
expect
(
epicDetails
.
find
(
UserAvatarLink
).
exists
()).
toBe
(
true
);
});
});
it
(
'
renders action buttons element
'
,
()
=>
{
it
(
'
renders action buttons element
'
,
()
=>
{
const
actionsEl
=
vm
.
$el
.
querySelector
(
'
.js-issuable-actions
'
);
const
actionButtons
=
findActionButtons
();
const
toggleStatusButton
=
actionButtons
.
find
(
'
[data-testid="toggle-status-button"]
'
);
expect
(
action
sEl
).
not
.
toBeNull
();
expect
(
action
Buttons
.
exists
()).
toBeTruthy
();
expect
(
actionsEl
.
querySelector
(
'
.js-btn-epic-action
'
)).
not
.
toBeNull
();
expect
(
toggleStatusButton
.
exists
()).
toBeTruthy
();
expect
(
actionsEl
.
querySelector
(
'
.js-btn-epic-action
'
).
innerText
.
trim
()).
toBe
(
'
Close epic
'
);
expect
(
toggleStatusButton
.
text
()).
toBe
(
'
Close epic
'
);
});
});
it
(
'
renders toggle sidebar button element
'
,
()
=>
{
it
(
'
renders toggle sidebar button element
'
,
()
=>
{
const
toggleButton
El
=
wrapper
.
find
(
'
.js-sidebar-toggle
'
);
const
toggleButton
=
findSidebarToggle
(
);
expect
(
toggleButton
El
.
exists
()).
toBe
(
true
);
expect
(
toggleButton
.
exists
()).
toBeTruthy
(
);
expect
(
toggleButton
El
.
attributes
(
'
aria-label
'
)).
toBe
(
'
Toggle sidebar
'
);
expect
(
toggleButton
.
attributes
(
'
aria-label
'
)).
toBe
(
'
Toggle sidebar
'
);
expect
(
toggleButton
El
.
classes
()).
toEqual
(
expect
(
toggleButton
.
classes
()).
toEqual
(
expect
.
arrayContaining
([(
'
d-block
'
,
'
d-sm-none
'
,
'
gutter-toggle
'
)]),
expect
.
arrayContaining
([(
'
d-block
'
,
'
d-sm-none
'
,
'
gutter-toggle
'
)]),
);
);
});
});
it
(
'
renders GitLab team member badge when `author.isGitlabEmployee` is `true`
'
,
()
=>
{
it
(
'
renders GitLab team member badge when `author.isGitlabEmployee` is `true`
'
,
()
=>
{
vm
.
$
store
.
state
.
author
.
isGitlabEmployee
=
true
;
store
.
state
.
author
.
isGitlabEmployee
=
true
;
// Wait for dynamic imports to resolve
// Wait for dynamic imports to resolve
return
new
Promise
(
setImmediate
).
then
(()
=>
{
return
new
Promise
(
setImmediate
).
then
(()
=>
{
expect
(
vm
.
$refs
.
gitlabTeamMemberBadge
).
not
.
toBeUndefined
();
expect
(
wrapper
.
vm
.
$refs
.
gitlabTeamMemberBadge
).
not
.
toBeUndefined
();
});
});
it
(
'
does not render new epic button without `createEpicForm` feature flag
'
,
()
=>
{
expect
(
findNewEpicButton
().
exists
()).
toBeFalsy
();
});
describe
(
'
with `createEpicForm` feature flag
'
,
()
=>
{
beforeAll
(()
=>
{
features
=
{
createEpicForm
:
true
};
});
it
(
'
renders new epic button if user can create it
'
,
()
=>
{
store
.
state
.
canCreate
=
true
;
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
findNewEpicButton
().
exists
()).
toBe
(
true
);
});
});
});
});
});
});
});
...
...
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