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
d82da588
Commit
d82da588
authored
Oct 28, 2019
by
Paul Gascou-Vaillancourt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate issue boards specs to Jest & VTU
Migrated boards specs that rely on tooltips to Jest & Vue Test Utils
parent
eafd98ec
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
388 additions
and
0 deletions
+388
-0
spec/frontend/boards/components/issue_time_estimate_spec.js
spec/frontend/boards/components/issue_time_estimate_spec.js
+81
-0
spec/frontend/boards/issue_card_spec.js
spec/frontend/boards/issue_card_spec.js
+307
-0
No files found.
spec/
javascripts
/boards/components/issue_time_estimate_spec.js
→
spec/
frontend
/boards/components/issue_time_estimate_spec.js
View file @
d82da588
import
Vue
from
'
vue
'
;
import
IssueTimeEstimate
from
'
~/boards/components/issue_time_estimate.vue
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
mountComponent
from
'
../../helpers/vue_mount_component_helper
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
describe
(
'
Issue Time Estimate component
'
,
()
=>
{
let
vm
;
let
wrapper
;
beforeEach
(()
=>
{
boardsStore
.
create
();
});
afterEach
(()
=>
{
vm
.
$
destroy
();
wrapper
.
destroy
();
});
describe
(
'
when limitToHours is false
'
,
()
=>
{
beforeEach
(()
=>
{
boardsStore
.
timeTracking
.
limitToHours
=
false
;
const
Component
=
Vue
.
extend
(
IssueTimeEstimate
);
vm
=
mountComponent
(
Component
,
{
wrapper
=
shallowMount
(
IssueTimeEstimate
,
{
propsData
:
{
estimate
:
374460
,
},
sync
:
false
,
});
});
it
(
'
renders the correct time estimate
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
time
'
).
textContent
.
trim
()).
toEqual
(
'
2w 3d 1m
'
);
expect
(
wrapper
.
find
(
'
time
'
)
.
text
()
.
trim
(),
).
toEqual
(
'
2w 3d 1m
'
);
});
it
(
'
renders expanded time estimate in tooltip
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-issue-time-estimate
'
).
textContent
).
toContain
(
'
2 weeks 3 days 1 minute
'
,
);
expect
(
wrapper
.
find
(
'
.js-issue-time-estimate
'
).
text
()).
toContain
(
'
2 weeks 3 days 1 minute
'
);
});
it
(
'
prevents tooltip xss
'
,
done
=>
{
const
alertSpy
=
spyOn
(
window
,
'
alert
'
);
vm
.
estimate
=
'
Foo <script>alert("XSS")</script>
'
;
vm
.
$nextTick
(()
=>
{
const
alertSpy
=
jest
.
spyOn
(
window
,
'
alert
'
);
wrapper
.
setProps
({
estimate
:
'
Foo <script>alert("XSS")</script>
'
});
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
alertSpy
).
not
.
toHaveBeenCalled
();
expect
(
vm
.
$el
.
querySelector
(
'
time
'
).
textContent
.
trim
()).
toEqual
(
'
0m
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-issue-time-estimate
'
).
textContent
).
toContain
(
'
0m
'
);
expect
(
wrapper
.
find
(
'
time
'
)
.
text
()
.
trim
(),
).
toEqual
(
'
0m
'
);
expect
(
wrapper
.
find
(
'
.js-issue-time-estimate
'
).
text
()).
toContain
(
'
0m
'
);
done
();
});
});
...
...
@@ -50,21 +57,25 @@ describe('Issue Time Estimate component', () => {
describe
(
'
when limitToHours is true
'
,
()
=>
{
beforeEach
(()
=>
{
boardsStore
.
timeTracking
.
limitToHours
=
true
;
const
Component
=
Vue
.
extend
(
IssueTimeEstimate
);
vm
=
mountComponent
(
Component
,
{
wrapper
=
shallowMount
(
IssueTimeEstimate
,
{
propsData
:
{
estimate
:
374460
,
},
sync
:
false
,
});
});
it
(
'
renders the correct time estimate
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
time
'
).
textContent
.
trim
()).
toEqual
(
'
104h 1m
'
);
expect
(
wrapper
.
find
(
'
time
'
)
.
text
()
.
trim
(),
).
toEqual
(
'
104h 1m
'
);
});
it
(
'
renders expanded time estimate in tooltip
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-issue-time-estimate
'
).
textContent
).
toContain
(
'
104 hours 1 minute
'
,
);
expect
(
wrapper
.
find
(
'
.js-issue-time-estimate
'
).
text
()).
toContain
(
'
104 hours 1 minute
'
);
});
});
});
spec/
javascripts
/boards/issue_card_spec.js
→
spec/
frontend
/boards/issue_card_spec.js
View file @
d82da588
/* global ListAssignee */
/* global ListLabel */
/* global ListIssue */
import
Vue
from
'
vue
'
;
/* global ListAssignee, ListLabel, ListIssue */
import
{
mount
}
from
'
@vue/test-utils
'
;
import
_
from
'
underscore
'
;
import
'
~/boards/models/label
'
;
import
'
~/boards/models/assignee
'
;
import
'
~/boards/models/issue
'
;
import
'
~/boards/models/list
'
;
import
IssueCardInner
from
'
~/boards/components/issue_card_inner.vue
'
;
import
{
listObj
}
from
'
./mock_data
'
;
import
{
listObj
}
from
'
.
./../javascripts/boards
/mock_data
'
;
import
store
from
'
~/boards/stores
'
;
describe
(
'
Issue card component
'
,
()
=>
{
...
...
@@ -19,6 +16,7 @@ describe('Issue card component', () => {
username
:
'
test
'
,
avatar
:
'
test_image
'
,
});
const
label1
=
new
ListLabel
({
id
:
3
,
title
:
'
testing 123
'
,
...
...
@@ -26,17 +24,13 @@ describe('Issue card component', () => {
text_color
:
'
white
'
,
description
:
'
test
'
,
});
let
component
;
let
wrapper
;
let
issue
;
let
list
;
beforeEach
(()
=>
{
setFixtures
(
'
<div class="test-container"></div>
'
);
list
=
{
...
listObj
,
type
:
'
label
'
,
};
list
=
{
...
listObj
,
type
:
'
label
'
};
issue
=
new
ListIssue
({
title
:
'
Testing
'
,
id
:
1
,
...
...
@@ -48,100 +42,91 @@ describe('Issue card component', () => {
real_path
:
'
/test/1
'
,
weight
:
1
,
});
component
=
new
Vue
({
el
:
document
.
querySelector
(
'
.test-container
'
),
store
,
components
:
{
'
issue-card
'
:
IssueCardInner
,
},
data
()
{
return
{
wrapper
=
mount
(
IssueCardInner
,
{
propsData
:
{
list
,
issue
,
issueLinkBase
:
'
/test
'
,
rootPath
:
'
/
'
,
};
},
template
:
`
<issue-card
:issue="issue"
:list="list"
:issue-link-base="issueLinkBase"
:root-path="rootPath"></issue-card>
`
,
store
,
sync
:
false
,
});
});
it
(
'
renders issue title
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-title
'
).
textContent
).
toContain
(
issue
.
title
);
expect
(
wrapper
.
find
(
'
.board-card-title
'
).
text
()
).
toContain
(
issue
.
title
);
});
it
(
'
includes issue base in link
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-title a
'
).
getAttribute
(
'
href
'
)).
toContain
(
'
/test
'
,
);
expect
(
wrapper
.
find
(
'
.board-card-title a
'
).
attributes
(
'
href
'
)).
toContain
(
'
/test
'
);
});
it
(
'
includes issue title on link
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-title a
'
).
getAttribute
(
'
title
'
)).
toBe
(
issue
.
title
,
);
expect
(
wrapper
.
find
(
'
.board-card-title a
'
).
attributes
(
'
title
'
)).
toBe
(
issue
.
title
);
});
it
(
'
does not render confidential icon
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.fa-eye-flash
'
)).
toBeNull
(
);
expect
(
wrapper
.
find
(
'
.fa-eye-flash
'
).
exists
()).
toBe
(
false
);
});
it
(
'
renders confidential icon
'
,
done
=>
{
component
.
issue
.
confidential
=
true
;
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.confidential-icon
'
)).
not
.
toBeNull
();
wrapper
.
setProps
({
issue
:
{
...
wrapper
.
props
(
'
issue
'
),
confidential
:
true
,
},
});
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
wrapper
.
find
(
'
.confidential-icon
'
).
exists
()).
toBe
(
true
);
done
();
});
});
it
(
'
renders issue ID with #
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-number
'
).
textContent
).
toContain
(
`#
${
issue
.
id
}
`
);
expect
(
wrapper
.
find
(
'
.board-card-number
'
).
text
()
).
toContain
(
`#
${
issue
.
id
}
`
);
});
describe
(
'
assignee
'
,
()
=>
{
it
(
'
does not render assignee
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee .avatar
'
)).
toBeNull
(
);
expect
(
wrapper
.
find
(
'
.board-card-assignee .avatar
'
).
exists
()).
toBe
(
false
);
});
describe
(
'
exists
'
,
()
=>
{
beforeEach
(
done
=>
{
component
.
issue
.
assignees
=
[
user
];
wrapper
.
setProps
({
issue
:
{
...
wrapper
.
props
(
'
issue
'
),
assignees
:
[
user
],
},
});
Vue
.
nextTick
(()
=>
done
()
);
wrapper
.
vm
.
$nextTick
(
done
);
});
it
(
'
renders assignee
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee .avatar
'
)).
not
.
toBeNull
(
);
expect
(
wrapper
.
find
(
'
.board-card-assignee .avatar
'
).
exists
()).
toBe
(
true
);
});
it
(
'
sets title
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-assignee-tooltip
'
).
textContent
).
toContain
(
`
${
user
.
name
}
`
,
);
expect
(
wrapper
.
find
(
'
.js-assignee-tooltip
'
).
text
()).
toContain
(
`
${
user
.
name
}
`
);
});
it
(
'
sets users path
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee a
'
).
getAttribute
(
'
href
'
)).
toBe
(
'
/test
'
,
);
expect
(
wrapper
.
find
(
'
.board-card-assignee a
'
).
attributes
(
'
href
'
)).
toBe
(
'
/test
'
);
});
it
(
'
renders avatar
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee img
'
)).
not
.
toBeNull
(
);
expect
(
wrapper
.
find
(
'
.board-card-assignee img
'
).
exists
()).
toBe
(
true
);
});
});
describe
(
'
assignee default avatar
'
,
()
=>
{
beforeEach
(
done
=>
{
component
.
issue
.
assignees
=
[
wrapper
.
setProps
({
issue
:
{
...
wrapper
.
props
(
'
issue
'
),
assignees
:
[
new
ListAssignee
(
{
id
:
1
,
...
...
@@ -150,14 +135,16 @@ describe('Issue card component', () => {
},
'
default_avatar
'
,
),
];
],
},
});
Vue
.
nextTick
(
done
);
wrapper
.
vm
.
$
nextTick
(
done
);
});
it
(
'
displays defaults avatar if users avatar is null
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee img
'
)).
not
.
toBeNull
(
);
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee img
'
).
getAttribute
(
'
src
'
)).
toBe
(
expect
(
wrapper
.
find
(
'
.board-card-assignee img
'
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
find
(
'
.board-card-assignee img
'
).
attributes
(
'
src
'
)).
toBe
(
'
default_avatar?width=24
'
,
);
});
...
...
@@ -166,7 +153,10 @@ describe('Issue card component', () => {
describe
(
'
multiple assignees
'
,
()
=>
{
beforeEach
(
done
=>
{
component
.
issue
.
assignees
=
[
wrapper
.
setProps
({
issue
:
{
...
wrapper
.
props
(
'
issue
'
),
assignees
:
[
new
ListAssignee
({
id
:
2
,
name
:
'
user2
'
,
...
...
@@ -185,18 +175,21 @@ describe('Issue card component', () => {
username
:
'
user4
'
,
avatar
:
'
test_image
'
,
}),
];
],
},
});
Vue
.
nextTick
(()
=>
done
()
);
wrapper
.
vm
.
$nextTick
(
done
);
});
it
(
'
renders all three assignees
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
All
(
'
.board-card-assignee .avatar
'
).
length
).
toEqual
(
3
);
expect
(
wrapper
.
find
All
(
'
.board-card-assignee .avatar
'
).
length
).
toEqual
(
3
);
});
describe
(
'
more than three assignees
'
,
()
=>
{
beforeEach
(
done
=>
{
component
.
issue
.
assignees
.
push
(
const
{
assignees
}
=
wrapper
.
props
(
'
issue
'
);
assignees
.
push
(
new
ListAssignee
({
id
:
5
,
name
:
'
user5
'
,
...
...
@@ -205,33 +198,54 @@ describe('Issue card component', () => {
}),
);
Vue
.
nextTick
(()
=>
done
());
wrapper
.
setProps
({
issue
:
{
...
wrapper
.
props
(
'
issue
'
),
assignees
,
},
});
wrapper
.
vm
.
$nextTick
(
done
);
});
it
(
'
renders more avatar counter
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee .avatar-counter
'
).
innerText
.
trim
(),
wrapper
.
find
(
'
.board-card-assignee .avatar-counter
'
)
.
text
()
.
trim
(),
).
toEqual
(
'
+2
'
);
});
it
(
'
renders two assignees
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
All
(
'
.board-card-assignee .avatar
'
).
length
).
toEqual
(
2
);
expect
(
wrapper
.
find
All
(
'
.board-card-assignee .avatar
'
).
length
).
toEqual
(
2
);
});
it
(
'
renders 99+ avatar counter
'
,
done
=>
{
for
(
let
i
=
5
;
i
<
104
;
i
+=
1
)
{
const
u
=
new
ListAssignee
({
const
assignees
=
[
...
wrapper
.
props
(
'
issue
'
).
assignees
,
...
_
.
range
(
5
,
103
).
map
(
i
=>
new
ListAssignee
({
id
:
i
,
name
:
'
name
'
,
username
:
'
username
'
,
avatar
:
'
test_image
'
,
}),
),
];
wrapper
.
setProps
({
issue
:
{
...
wrapper
.
props
(
'
issue
'
),
assignees
,
},
});
component
.
issue
.
assignees
.
push
(
u
);
}
Vue
.
nextTick
(()
=>
{
wrapper
.
vm
.
$
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.board-card-assignee .avatar-counter
'
).
innerText
.
trim
(),
wrapper
.
find
(
'
.board-card-assignee .avatar-counter
'
)
.
text
()
.
trim
(),
).
toEqual
(
'
99+
'
);
done
();
});
...
...
@@ -241,51 +255,50 @@ describe('Issue card component', () => {
describe
(
'
labels
'
,
()
=>
{
beforeEach
(
done
=>
{
component
.
issue
.
addLabel
(
label1
);
issue
.
addLabel
(
label1
);
wrapper
.
setProps
({
issue
:
{
...
issue
}
});
Vue
.
nextTick
(()
=>
done
()
);
wrapper
.
vm
.
$nextTick
(
done
);
});
it
(
'
does not render list label but renders all other labels
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
All
(
'
.badge
'
).
length
).
toBe
(
1
);
expect
(
wrapper
.
find
All
(
'
.badge
'
).
length
).
toBe
(
1
);
});
it
(
'
renders label
'
,
()
=>
{
const
nodes
=
[];
component
.
$el
.
querySelectorAll
(
'
.badge
'
).
forEach
(
label
=>
{
nodes
.
push
(
label
.
getAttribute
(
'
data-original-title
'
));
});
const
nodes
=
wrapper
.
findAll
(
'
.badge
'
)
.
wrappers
.
map
(
label
=>
label
.
attributes
(
'
data-original-title
'
));
expect
(
nodes
.
includes
(
label1
.
description
)).
toBe
(
true
);
});
it
(
'
sets label description as title
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.badge
'
).
getAttribute
(
'
data-original-title
'
)).
toContain
(
expect
(
wrapper
.
find
(
'
.badge
'
).
attributes
(
'
data-original-title
'
)).
toContain
(
label1
.
description
,
);
});
it
(
'
sets background color of button
'
,
()
=>
{
const
nodes
=
[];
component
.
$el
.
querySelectorAll
(
'
.badge
'
).
forEach
(
label
=>
{
nodes
.
push
(
label
.
style
.
backgroundColor
);
});
const
nodes
=
wrapper
.
findAll
(
'
.badge
'
)
.
wrappers
.
map
(
label
=>
label
.
element
.
style
.
backgroundColor
);
expect
(
nodes
.
includes
(
label1
.
color
)).
toBe
(
true
);
});
it
(
'
does not render label if label does not have an ID
'
,
done
=>
{
component
.
issue
.
addLabel
(
issue
.
addLabel
(
new
ListLabel
({
title
:
'
closed
'
,
}),
);
Vue
.
nextTick
()
wrapper
.
setProps
({
issue
:
{
...
issue
}
});
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.badge
'
).
length
).
toBe
(
1
);
expect
(
component
.
$el
.
textContent
).
not
.
toContain
(
'
closed
'
);
expect
(
wrapper
.
findAll
(
'
.badge
'
).
length
).
toBe
(
1
);
expect
(
wrapper
.
text
()).
not
.
toContain
(
'
closed
'
);
done
();
})
.
catch
(
done
.
fail
);
...
...
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