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
8fa2932d
Commit
8fa2932d
authored
Feb 02, 2018
by
Filipa Lacerda
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ph-axios-2' into 'master'
More conversions to axios See merge request gitlab-org/gitlab-ce!16800
parents
f88fbd2d
965ff965
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
719 additions
and
588 deletions
+719
-588
app/assets/javascripts/issue.js
app/assets/javascripts/issue.js
+18
-22
app/assets/javascripts/job.js
app/assets/javascripts/job.js
+19
-6
app/assets/javascripts/labels_select.js
app/assets/javascripts/labels_select.js
+81
-81
app/assets/javascripts/lib/utils/ajax_cache.js
app/assets/javascripts/lib/utils/ajax_cache.js
+13
-19
app/assets/javascripts/lib/utils/axios_utils.js
app/assets/javascripts/lib/utils/axios_utils.js
+4
-0
app/assets/javascripts/lib/utils/common_utils.js
app/assets/javascripts/lib/utils/common_utils.js
+6
-12
app/assets/javascripts/merge_conflicts/merge_conflict_service.js
...ets/javascripts/merge_conflicts/merge_conflict_service.js
+3
-11
app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
...ets/javascripts/merge_conflicts/merge_conflicts_bundle.js
+9
-10
app/assets/javascripts/merge_request_tabs.js
app/assets/javascripts/merge_request_tabs.js
+25
-22
app/assets/javascripts/milestone.js
app/assets/javascripts/milestone.js
+8
-10
app/assets/javascripts/milestone_select.js
app/assets/javascripts/milestone_select.js
+58
-61
app/assets/javascripts/notes.js
app/assets/javascripts/notes.js
+13
-10
spec/javascripts/issue_spec.js
spec/javascripts/issue_spec.js
+78
-49
spec/javascripts/job_spec.js
spec/javascripts/job_spec.js
+135
-117
spec/javascripts/labels_issue_sidebar_spec.js
spec/javascripts/labels_issue_sidebar_spec.js
+27
-16
spec/javascripts/lib/utils/ajax_cache_spec.js
spec/javascripts/lib/utils/ajax_cache_spec.js
+27
-41
spec/javascripts/lib/utils/common_utils_spec.js
spec/javascripts/lib/utils/common_utils_spec.js
+1
-13
spec/javascripts/merge_request_tabs_spec.js
spec/javascripts/merge_request_tabs_spec.js
+66
-30
spec/javascripts/notes_spec.js
spec/javascripts/notes_spec.js
+128
-58
No files found.
app/assets/javascripts/issue.js
View file @
8fa2932d
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */
import
'
vendor/jquery.waitforimages
'
;
import
'
vendor/jquery.waitforimages
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
addDelimiter
}
from
'
./lib/utils/text_utility
'
;
import
{
addDelimiter
}
from
'
./lib/utils/text_utility
'
;
import
F
lash
from
'
./flash
'
;
import
f
lash
from
'
./flash
'
;
import
TaskList
from
'
./task_list
'
;
import
TaskList
from
'
./task_list
'
;
import
CreateMergeRequestDropdown
from
'
./create_merge_request_dropdown
'
;
import
CreateMergeRequestDropdown
from
'
./create_merge_request_dropdown
'
;
import
IssuablesHelper
from
'
./helpers/issuables_helper
'
;
import
IssuablesHelper
from
'
./helpers/issuables_helper
'
;
...
@@ -42,12 +43,8 @@ export default class Issue {
...
@@ -42,12 +43,8 @@ export default class Issue {
this
.
disableCloseReopenButton
(
$button
);
this
.
disableCloseReopenButton
(
$button
);
url
=
$button
.
attr
(
'
href
'
);
url
=
$button
.
attr
(
'
href
'
);
return
$
.
ajax
({
return
axios
.
put
(
url
)
type
:
'
PUT
'
,
.
then
(({
data
})
=>
{
url
:
url
})
.
fail
(()
=>
new
Flash
(
issueFailMessage
))
.
done
((
data
)
=>
{
const
isClosedBadge
=
$
(
'
div.status-box-issue-closed
'
);
const
isClosedBadge
=
$
(
'
div.status-box-issue-closed
'
);
const
isOpenBadge
=
$
(
'
div.status-box-open
'
);
const
isOpenBadge
=
$
(
'
div.status-box-open
'
);
const
projectIssuesCounter
=
$
(
'
.issue_counter
'
);
const
projectIssuesCounter
=
$
(
'
.issue_counter
'
);
...
@@ -74,9 +71,10 @@ export default class Issue {
...
@@ -74,9 +71,10 @@ export default class Issue {
}
}
}
}
}
else
{
}
else
{
new
F
lash
(
issueFailMessage
);
f
lash
(
issueFailMessage
);
}
}
})
})
.
catch
(()
=>
flash
(
issueFailMessage
))
.
then
(()
=>
{
.
then
(()
=>
{
this
.
disableCloseReopenButton
(
$button
,
false
);
this
.
disableCloseReopenButton
(
$button
,
false
);
});
});
...
@@ -115,24 +113,22 @@ export default class Issue {
...
@@ -115,24 +113,22 @@ export default class Issue {
static
initMergeRequests
()
{
static
initMergeRequests
()
{
var
$container
;
var
$container
;
$container
=
$
(
'
#merge-requests
'
);
$container
=
$
(
'
#merge-requests
'
);
return
$
.
getJSON
(
$container
.
data
(
'
url
'
)).
fail
(
function
()
{
return
axios
.
get
(
$container
.
data
(
'
url
'
))
return
new
Flash
(
'
Failed to load referenced merge requests
'
);
.
then
(({
data
})
=>
{
}).
done
(
function
(
data
)
{
if
(
'
html
'
in
data
)
{
if
(
'
html
'
in
data
)
{
$container
.
html
(
data
.
html
);
return
$container
.
html
(
data
.
html
);
}
}
}).
catch
(()
=>
flash
(
'
Failed to load referenced merge requests
'
));
});
}
}
static
initRelatedBranches
()
{
static
initRelatedBranches
()
{
var
$container
;
var
$container
;
$container
=
$
(
'
#related-branches
'
);
$container
=
$
(
'
#related-branches
'
);
return
$
.
getJSON
(
$container
.
data
(
'
url
'
)).
fail
(
function
()
{
return
axios
.
get
(
$container
.
data
(
'
url
'
))
return
new
Flash
(
'
Failed to load related branches
'
);
.
then
(({
data
})
=>
{
}).
done
(
function
(
data
)
{
if
(
'
html
'
in
data
)
{
if
(
'
html
'
in
data
)
{
$container
.
html
(
data
.
html
);
return
$container
.
html
(
data
.
html
);
}
}
}).
catch
(()
=>
flash
(
'
Failed to load related branches
'
));
});
}
}
}
}
app/assets/javascripts/job.js
View file @
8fa2932d
import
_
from
'
underscore
'
;
import
_
from
'
underscore
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
visitUrl
}
from
'
./lib/utils/url_utility
'
;
import
{
visitUrl
}
from
'
./lib/utils/url_utility
'
;
import
bp
from
'
./breakpoints
'
;
import
bp
from
'
./breakpoints
'
;
import
{
numberToHumanSize
}
from
'
./lib/utils/number_utils
'
;
import
{
numberToHumanSize
}
from
'
./lib/utils/number_utils
'
;
...
@@ -8,6 +9,7 @@ export default class Job {
...
@@ -8,6 +9,7 @@ export default class Job {
constructor
(
options
)
{
constructor
(
options
)
{
this
.
timeout
=
null
;
this
.
timeout
=
null
;
this
.
state
=
null
;
this
.
state
=
null
;
this
.
fetchingStatusFavicon
=
false
;
this
.
options
=
options
||
$
(
'
.js-build-options
'
).
data
();
this
.
options
=
options
||
$
(
'
.js-build-options
'
).
data
();
this
.
pagePath
=
this
.
options
.
pagePath
;
this
.
pagePath
=
this
.
options
.
pagePath
;
...
@@ -171,12 +173,23 @@ export default class Job {
...
@@ -171,12 +173,23 @@ export default class Job {
}
}
getBuildTrace
()
{
getBuildTrace
()
{
return
$
.
ajax
({
return
axios
.
get
(
`
${
this
.
pagePath
}
/trace.json`
,
{
url
:
`
${
this
.
pagePath
}
/trace.json`
,
params
:
{
state
:
this
.
state
},
data
:
{
state
:
this
.
state
},
})
})
.
done
((
log
)
=>
{
.
then
((
res
)
=>
{
setCiStatusFavicon
(
`
${
this
.
pagePath
}
/status.json`
);
const
log
=
res
.
data
;
if
(
!
this
.
fetchingStatusFavicon
)
{
this
.
fetchingStatusFavicon
=
true
;
setCiStatusFavicon
(
`
${
this
.
pagePath
}
/status.json`
)
.
then
(()
=>
{
this
.
fetchingStatusFavicon
=
false
;
})
.
catch
(()
=>
{
this
.
fetchingStatusFavicon
=
false
;
});
}
if
(
log
.
state
)
{
if
(
log
.
state
)
{
this
.
state
=
log
.
state
;
this
.
state
=
log
.
state
;
...
@@ -217,7 +230,7 @@ export default class Job {
...
@@ -217,7 +230,7 @@ export default class Job {
visitUrl
(
this
.
pagePath
);
visitUrl
(
this
.
pagePath
);
}
}
})
})
.
fail
(()
=>
{
.
catch
(()
=>
{
this
.
$buildRefreshAnimation
.
remove
();
this
.
$buildRefreshAnimation
.
remove
();
})
})
.
then
(()
=>
{
.
then
(()
=>
{
...
...
app/assets/javascripts/labels_select.js
View file @
8fa2932d
...
@@ -2,9 +2,12 @@
...
@@ -2,9 +2,12 @@
/* global Issuable */
/* global Issuable */
/* global ListLabel */
/* global ListLabel */
import
_
from
'
underscore
'
;
import
_
from
'
underscore
'
;
import
{
__
}
from
'
./locale
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
IssuableBulkUpdateActions
from
'
./issuable_bulk_update_actions
'
;
import
IssuableBulkUpdateActions
from
'
./issuable_bulk_update_actions
'
;
import
DropdownUtils
from
'
./filtered_search/dropdown_utils
'
;
import
DropdownUtils
from
'
./filtered_search/dropdown_utils
'
;
import
CreateLabelDropdown
from
'
./create_label
'
;
import
CreateLabelDropdown
from
'
./create_label
'
;
import
flash
from
'
./flash
'
;
export
default
class
LabelsSelect
{
export
default
class
LabelsSelect
{
constructor
(
els
,
options
=
{})
{
constructor
(
els
,
options
=
{})
{
...
@@ -82,99 +85,96 @@ export default class LabelsSelect {
...
@@ -82,99 +85,96 @@ export default class LabelsSelect {
}
}
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
return
$
.
ajax
({
axios
.
put
(
issueUpdateURL
,
data
)
type
:
'
PUT
'
,
.
then
(({
data
})
=>
{
url
:
issueUpdateURL
,
var
labelCount
,
template
,
labelTooltipTitle
,
labelTitles
;
dataType
:
'
JSON
'
,
$loading
.
fadeOut
();
data
:
data
$dropdown
.
trigger
(
'
loaded.gl.dropdown
'
);
}).
done
(
function
(
data
)
{
$selectbox
.
hide
();
var
labelCount
,
template
,
labelTooltipTitle
,
labelTitles
;
data
.
issueURLSplit
=
issueURLSplit
;
$loading
.
fadeOut
();
labelCount
=
0
;
$dropdown
.
trigger
(
'
loaded.gl.dropdown
'
);
if
(
data
.
labels
.
length
)
{
$selectbox
.
hide
();
template
=
labelHTMLTemplate
(
data
);
data
.
issueURLSplit
=
issueURLSplit
;
labelCount
=
data
.
labels
.
length
;
labelCount
=
0
;
}
if
(
data
.
labels
.
length
)
{
else
{
template
=
labelHTMLTemplate
(
data
);
template
=
labelNoneHTMLTemplate
;
labelCount
=
data
.
labels
.
length
;
}
}
$value
.
removeAttr
(
'
style
'
).
html
(
template
);
else
{
$sidebarCollapsedValue
.
text
(
labelCount
);
template
=
labelNoneHTMLTemplate
;
}
$value
.
removeAttr
(
'
style
'
).
html
(
template
);
$sidebarCollapsedValue
.
text
(
labelCount
);
if
(
data
.
labels
.
length
)
{
if
(
data
.
labels
.
length
)
{
labelTitles
=
data
.
labels
.
map
(
function
(
label
)
{
labelTitles
=
data
.
labels
.
map
(
function
(
label
)
{
return
label
.
title
;
return
label
.
title
;
});
});
if
(
labelTitles
.
length
>
5
)
{
if
(
labelTitles
.
length
>
5
)
{
labelTitles
=
labelTitles
.
slice
(
0
,
5
);
labelTitles
=
labelTitles
.
slice
(
0
,
5
);
labelTitles
.
push
(
'
and
'
+
(
data
.
labels
.
length
-
5
)
+
'
more
'
);
labelTitles
.
push
(
'
and
'
+
(
data
.
labels
.
length
-
5
)
+
'
more
'
);
}
}
labelTooltipTitle
=
labelTitles
.
join
(
'
,
'
);
labelTooltipTitle
=
labelTitles
.
join
(
'
,
'
);
}
}
else
{
else
{
labelTooltipTitle
=
''
;
labelTooltipTitle
=
''
;
$sidebarLabelTooltip
.
tooltip
(
'
destroy
'
);
$sidebarLabelTooltip
.
tooltip
(
'
destroy
'
);
}
}
$sidebarLabelTooltip
$sidebarLabelTooltip
.
attr
(
'
title
'
,
labelTooltipTitle
)
.
attr
(
'
title
'
,
labelTooltipTitle
)
.
tooltip
(
'
fixTitle
'
);
.
tooltip
(
'
fixTitle
'
);
$
(
'
.has-tooltip
'
,
$value
).
tooltip
({
$
(
'
.has-tooltip
'
,
$value
).
tooltip
({
container
:
'
body
'
container
:
'
body
'
});
});
});
})
.
catch
(()
=>
flash
(
__
(
'
Error saving label update.
'
)));
};
};
$dropdown
.
glDropdown
({
$dropdown
.
glDropdown
({
showMenuAbove
:
showMenuAbove
,
showMenuAbove
:
showMenuAbove
,
data
:
function
(
term
,
callback
)
{
data
:
function
(
term
,
callback
)
{
return
$
.
ajax
({
axios
.
get
(
labelUrl
)
url
:
labelUrl
.
then
((
res
)
=>
{
}).
done
(
function
(
data
)
{
let
data
=
_
.
chain
(
res
.
data
).
groupBy
(
function
(
label
)
{
data
=
_
.
chain
(
data
).
groupBy
(
function
(
label
)
{
return
label
.
title
;
return
label
.
title
;
}).
map
(
function
(
label
)
{
}).
map
(
function
(
label
)
{
var
color
;
var
color
;
color
=
_
.
map
(
label
,
function
(
dup
)
{
color
=
_
.
map
(
label
,
function
(
dup
)
{
return
dup
.
color
;
return
dup
.
color
;
});
return
{
id
:
label
[
0
].
id
,
title
:
label
[
0
].
title
,
color
:
color
,
duplicate
:
color
.
length
>
1
};
}).
value
();
if
(
$dropdown
.
hasClass
(
'
js-extra-options
'
))
{
var
extraData
=
[];
if
(
showNo
)
{
extraData
.
unshift
({
id
:
0
,
title
:
'
No Label
'
});
});
return
{
id
:
label
[
0
].
id
,
title
:
label
[
0
].
title
,
color
:
color
,
duplicate
:
color
.
length
>
1
};
}).
value
();
if
(
$dropdown
.
hasClass
(
'
js-extra-options
'
))
{
var
extraData
=
[];
if
(
showNo
)
{
extraData
.
unshift
({
id
:
0
,
title
:
'
No Label
'
});
}
if
(
showAny
)
{
extraData
.
unshift
({
isAny
:
true
,
title
:
'
Any Label
'
});
}
if
(
extraData
.
length
)
{
extraData
.
push
(
'
divider
'
);
data
=
extraData
.
concat
(
data
);
}
}
}
if
(
showAny
)
{
extraData
.
unshift
({
isAny
:
true
,
title
:
'
Any Label
'
});
}
if
(
extraData
.
length
)
{
extraData
.
push
(
'
divider
'
);
data
=
extraData
.
concat
(
data
);
}
}
callback
(
data
);
callback
(
data
);
if
(
showMenuAbove
)
{
if
(
showMenuAbove
)
{
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
}
}
});
})
.
catch
(()
=>
flash
(
__
(
'
Error fetching labels.
'
)));
},
},
renderRow
:
function
(
label
,
instance
)
{
renderRow
:
function
(
label
,
instance
)
{
var
$a
,
$li
,
color
,
colorEl
,
indeterminate
,
removesAll
,
selectedClass
,
spacing
,
i
,
marked
,
dropdownName
,
dropdownValue
;
var
$a
,
$li
,
color
,
colorEl
,
indeterminate
,
removesAll
,
selectedClass
,
spacing
,
i
,
marked
,
dropdownName
,
dropdownValue
;
...
...
app/assets/javascripts/lib/utils/ajax_cache.js
View file @
8fa2932d
import
axios
from
'
./axios_utils
'
;
import
Cache
from
'
./cache
'
;
import
Cache
from
'
./cache
'
;
class
AjaxCache
extends
Cache
{
class
AjaxCache
extends
Cache
{
...
@@ -18,25 +19,18 @@ class AjaxCache extends Cache {
...
@@ -18,25 +19,18 @@ class AjaxCache extends Cache {
let
pendingRequest
=
this
.
pendingRequests
[
endpoint
];
let
pendingRequest
=
this
.
pendingRequests
[
endpoint
];
if
(
!
pendingRequest
)
{
if
(
!
pendingRequest
)
{
pendingRequest
=
new
Promise
((
resolve
,
reject
)
=>
{
pendingRequest
=
axios
.
get
(
endpoint
)
// jQuery 2 is not Promises/A+ compatible (missing catch)
.
then
(({
data
})
=>
{
$
.
ajax
(
endpoint
)
// eslint-disable-line promise/catch-or-return
this
.
internalStorage
[
endpoint
]
=
data
;
.
then
(
data
=>
resolve
(
data
),
delete
this
.
pendingRequests
[
endpoint
];
(
jqXHR
,
textStatus
,
errorThrown
)
=>
{
})
const
error
=
new
Error
(
`
${
endpoint
}
:
${
errorThrown
}
`
);
.
catch
((
e
)
=>
{
error
.
textStatus
=
textStatus
;
const
error
=
new
Error
(
`
${
endpoint
}
:
${
e
.
message
}
`
);
reject
(
error
);
error
.
textStatus
=
e
.
message
;
},
);
delete
this
.
pendingRequests
[
endpoint
];
})
throw
error
;
.
then
((
data
)
=>
{
});
this
.
internalStorage
[
endpoint
]
=
data
;
delete
this
.
pendingRequests
[
endpoint
];
})
.
catch
((
error
)
=>
{
delete
this
.
pendingRequests
[
endpoint
];
throw
error
;
});
this
.
pendingRequests
[
endpoint
]
=
pendingRequest
;
this
.
pendingRequests
[
endpoint
]
=
pendingRequest
;
}
}
...
...
app/assets/javascripts/lib/utils/axios_utils.js
View file @
8fa2932d
...
@@ -19,6 +19,10 @@ axios.interceptors.response.use((config) => {
...
@@ -19,6 +19,10 @@ axios.interceptors.response.use((config) => {
window
.
activeVueResources
-=
1
;
window
.
activeVueResources
-=
1
;
return
config
;
return
config
;
},
(
e
)
=>
{
window
.
activeVueResources
-=
1
;
return
Promise
.
reject
(
e
);
});
});
export
default
axios
;
export
default
axios
;
...
...
app/assets/javascripts/lib/utils/common_utils.js
View file @
8fa2932d
import
{
getLocationHash
}
from
'
./url_utility
'
;
import
axios
from
'
./axios_utils
'
;
import
axios
from
'
./axios_utils
'
;
import
{
getLocationHash
}
from
'
./url_utility
'
;
export
const
getPagePath
=
(
index
=
0
)
=>
$
(
'
body
'
).
attr
(
'
data-page
'
).
split
(
'
:
'
)[
index
];
export
const
getPagePath
=
(
index
=
0
)
=>
$
(
'
body
'
).
attr
(
'
data-page
'
).
split
(
'
:
'
)[
index
];
...
@@ -28,16 +28,11 @@ export const isInIssuePage = () => {
...
@@ -28,16 +28,11 @@ export const isInIssuePage = () => {
return
page
===
'
issues
'
&&
action
===
'
show
'
;
return
page
===
'
issues
'
&&
action
===
'
show
'
;
};
};
export
const
ajaxGet
=
url
=>
$
.
ajax
({
export
const
ajaxGet
=
url
=>
axios
.
get
(
url
,
{
type
:
'
GET
'
,
params
:
{
format
:
'
js
'
},
url
,
responseType
:
'
text
'
,
dataType
:
'
script
'
,
}).
then
(({
data
})
=>
{
});
$
.
globalEval
(
data
);
export
const
ajaxPost
=
(
url
,
data
)
=>
$
.
ajax
({
type
:
'
POST
'
,
url
,
data
,
});
});
export
const
rstrip
=
(
val
)
=>
{
export
const
rstrip
=
(
val
)
=>
{
...
@@ -412,7 +407,6 @@ window.gl.utils = {
...
@@ -412,7 +407,6 @@ window.gl.utils = {
getGroupSlug
,
getGroupSlug
,
isInIssuePage
,
isInIssuePage
,
ajaxGet
,
ajaxGet
,
ajaxPost
,
rstrip
,
rstrip
,
updateTooltipTitle
,
updateTooltipTitle
,
disableButtonIfEmptyField
,
disableButtonIfEmptyField
,
...
...
app/assets/javascripts/merge_conflicts/merge_conflict_service.js
View file @
8fa2932d
/* eslint-disable no-param-reassign, comma-dangle */
/* eslint-disable no-param-reassign, comma-dangle */
import
axios
from
'
../lib/utils/axios_utils
'
;
((
global
)
=>
{
((
global
)
=>
{
global
.
mergeConflicts
=
global
.
mergeConflicts
||
{};
global
.
mergeConflicts
=
global
.
mergeConflicts
||
{};
...
@@ -10,20 +11,11 @@
...
@@ -10,20 +11,11 @@
}
}
fetchConflictsData
()
{
fetchConflictsData
()
{
return
$
.
ajax
({
return
axios
.
get
(
this
.
conflictsPath
);
dataType
:
'
json
'
,
url
:
this
.
conflictsPath
});
}
}
submitResolveConflicts
(
data
)
{
submitResolveConflicts
(
data
)
{
return
$
.
ajax
({
return
axios
.
post
(
this
.
resolveConflictsPath
,
data
);
url
:
this
.
resolveConflictsPath
,
data
:
JSON
.
stringify
(
data
),
contentType
:
'
application/json
'
,
dataType
:
'
json
'
,
method
:
'
POST
'
});
}
}
}
}
...
...
app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
View file @
8fa2932d
...
@@ -38,24 +38,23 @@ $(() => {
...
@@ -38,24 +38,23 @@ $(() => {
showDiffViewTypeSwitcher
()
{
return
mergeConflictsStore
.
fileTextTypePresent
();
}
showDiffViewTypeSwitcher
()
{
return
mergeConflictsStore
.
fileTextTypePresent
();
}
},
},
created
()
{
created
()
{
mergeConflictsService
mergeConflictsService
.
fetchConflictsData
()
.
fetchConflictsData
()
.
then
(({
data
})
=>
{
.
done
((
data
)
=>
{
if
(
data
.
type
===
'
error
'
)
{
if
(
data
.
type
===
'
error
'
)
{
mergeConflictsStore
.
setFailedRequest
(
data
.
message
);
mergeConflictsStore
.
setFailedRequest
(
data
.
message
);
}
else
{
}
else
{
mergeConflictsStore
.
setConflictsData
(
data
);
mergeConflictsStore
.
setConflictsData
(
data
);
}
}
})
.
error
(()
=>
{
mergeConflictsStore
.
setFailedRequest
();
})
.
always
(()
=>
{
mergeConflictsStore
.
setLoadingState
(
false
);
mergeConflictsStore
.
setLoadingState
(
false
);
this
.
$nextTick
(()
=>
{
this
.
$nextTick
(()
=>
{
syntaxHighlight
(
$
(
'
.js-syntax-highlight
'
));
syntaxHighlight
(
$
(
'
.js-syntax-highlight
'
));
});
});
})
.
catch
(()
=>
{
mergeConflictsStore
.
setLoadingState
(
false
);
mergeConflictsStore
.
setFailedRequest
();
});
});
},
},
methods
:
{
methods
:
{
...
@@ -82,10 +81,10 @@ $(() => {
...
@@ -82,10 +81,10 @@ $(() => {
mergeConflictsService
mergeConflictsService
.
submitResolveConflicts
(
mergeConflictsStore
.
getCommitData
())
.
submitResolveConflicts
(
mergeConflictsStore
.
getCommitData
())
.
done
((
data
)
=>
{
.
then
(({
data
}
)
=>
{
window
.
location
.
href
=
data
.
redirect_to
;
window
.
location
.
href
=
data
.
redirect_to
;
})
})
.
error
(()
=>
{
.
catch
(()
=>
{
mergeConflictsStore
.
setSubmitState
(
false
);
mergeConflictsStore
.
setSubmitState
(
false
);
new
Flash
(
'
Failed to save merge conflicts resolutions. Please try again!
'
);
new
Flash
(
'
Failed to save merge conflicts resolutions. Please try again!
'
);
});
});
...
...
app/assets/javascripts/merge_request_tabs.js
View file @
8fa2932d
/* eslint-disable no-new, class-methods-use-this */
/* eslint-disable no-new, class-methods-use-this */
import
Cookies
from
'
js-cookie
'
;
import
Cookies
from
'
js-cookie
'
;
import
Flash
from
'
./flash
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
flash
from
'
./flash
'
;
import
BlobForkSuggestion
from
'
./blob/blob_fork_suggestion
'
;
import
BlobForkSuggestion
from
'
./blob/blob_fork_suggestion
'
;
import
initChangesDropdown
from
'
./init_changes_dropdown
'
;
import
initChangesDropdown
from
'
./init_changes_dropdown
'
;
import
bp
from
'
./breakpoints
'
;
import
bp
from
'
./breakpoints
'
;
...
@@ -244,15 +245,22 @@ export default class MergeRequestTabs {
...
@@ -244,15 +245,22 @@ export default class MergeRequestTabs {
if
(
this
.
commitsLoaded
)
{
if
(
this
.
commitsLoaded
)
{
return
;
return
;
}
}
this
.
ajaxGet
({
url
:
`
${
source
}
.json`
,
this
.
toggleLoading
(
true
);
success
:
(
data
)
=>
{
axios
.
get
(
`
${
source
}
.json`
)
.
then
(({
data
})
=>
{
document
.
querySelector
(
'
div#commits
'
).
innerHTML
=
data
.
html
;
document
.
querySelector
(
'
div#commits
'
).
innerHTML
=
data
.
html
;
localTimeAgo
(
$
(
'
.js-timeago
'
,
'
div#commits
'
));
localTimeAgo
(
$
(
'
.js-timeago
'
,
'
div#commits
'
));
this
.
commitsLoaded
=
true
;
this
.
commitsLoaded
=
true
;
this
.
scrollToElement
(
'
#commits
'
);
this
.
scrollToElement
(
'
#commits
'
);
},
});
this
.
toggleLoading
(
false
);
})
.
catch
(()
=>
{
this
.
toggleLoading
(
false
);
flash
(
'
An error occurred while fetching this tab.
'
);
});
}
}
mountPipelinesView
()
{
mountPipelinesView
()
{
...
@@ -283,9 +291,10 @@ export default class MergeRequestTabs {
...
@@ -283,9 +291,10 @@ export default class MergeRequestTabs {
// some pages like MergeRequestsController#new has query parameters on that anchor
// some pages like MergeRequestsController#new has query parameters on that anchor
const
urlPathname
=
parseUrlPathname
(
source
);
const
urlPathname
=
parseUrlPathname
(
source
);
this
.
ajaxGet
({
this
.
toggleLoading
(
true
);
url
:
`
${
urlPathname
}
.json
${
location
.
search
}
`
,
success
:
(
data
)
=>
{
axios
.
get
(
`
${
urlPathname
}
.json
${
location
.
search
}
`
)
.
then
(({
data
})
=>
{
const
$container
=
$
(
'
#diffs
'
);
const
$container
=
$
(
'
#diffs
'
);
$container
.
html
(
data
.
html
);
$container
.
html
(
data
.
html
);
...
@@ -335,8 +344,13 @@ export default class MergeRequestTabs {
...
@@ -335,8 +344,13 @@ export default class MergeRequestTabs {
// (discussion and diff tabs) and `:target` only applies to the first
// (discussion and diff tabs) and `:target` only applies to the first
anchor
.
addClass
(
'
target
'
);
anchor
.
addClass
(
'
target
'
);
}
}
},
});
this
.
toggleLoading
(
false
);
})
.
catch
(()
=>
{
this
.
toggleLoading
(
false
);
flash
(
'
An error occurred while fetching this tab.
'
);
});
}
}
// Show or hide the loading spinner
// Show or hide the loading spinner
...
@@ -346,17 +360,6 @@ export default class MergeRequestTabs {
...
@@ -346,17 +360,6 @@ export default class MergeRequestTabs {
$
(
'
.mr-loading-status .loading
'
).
toggle
(
status
);
$
(
'
.mr-loading-status .loading
'
).
toggle
(
status
);
}
}
ajaxGet
(
options
)
{
const
defaults
=
{
beforeSend
:
()
=>
this
.
toggleLoading
(
true
),
error
:
()
=>
new
Flash
(
'
An error occurred while fetching this tab.
'
,
'
alert
'
),
complete
:
()
=>
this
.
toggleLoading
(
false
),
dataType
:
'
json
'
,
type
:
'
GET
'
,
};
$
.
ajax
(
$
.
extend
({},
defaults
,
options
));
}
diffViewType
()
{
diffViewType
()
{
return
$
(
'
.inline-parallel-buttons a.active
'
).
data
(
'
view-type
'
);
return
$
(
'
.inline-parallel-buttons a.active
'
).
data
(
'
view-type
'
);
}
}
...
...
app/assets/javascripts/milestone.js
View file @
8fa2932d
import
Flash
from
'
./flash
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
flash
from
'
./flash
'
;
export
default
class
Milestone
{
export
default
class
Milestone
{
constructor
()
{
constructor
()
{
...
@@ -33,15 +34,12 @@ export default class Milestone {
...
@@ -33,15 +34,12 @@ export default class Milestone {
const
tabElId
=
$target
.
attr
(
'
href
'
);
const
tabElId
=
$target
.
attr
(
'
href
'
);
if
(
endpoint
&&
!
$target
.
hasClass
(
'
is-loaded
'
))
{
if
(
endpoint
&&
!
$target
.
hasClass
(
'
is-loaded
'
))
{
$
.
ajax
({
axios
.
get
(
endpoint
)
url
:
endpoint
,
.
then
(({
data
})
=>
{
dataType
:
'
JSON
'
,
$
(
tabElId
).
html
(
data
.
html
);
})
$target
.
addClass
(
'
is-loaded
'
);
.
fail
(()
=>
new
Flash
(
'
Error loading milestone tab
'
))
})
.
done
((
data
)
=>
{
.
catch
(()
=>
flash
(
'
Error loading milestone tab
'
));
$
(
tabElId
).
html
(
data
.
html
);
$target
.
addClass
(
'
is-loaded
'
);
});
}
}
}
}
}
}
app/assets/javascripts/milestone_select.js
View file @
8fa2932d
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
/* global Issuable */
/* global Issuable */
/* global ListMilestone */
/* global ListMilestone */
import
_
from
'
underscore
'
;
import
_
from
'
underscore
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
timeFor
}
from
'
./lib/utils/datetime_utility
'
;
import
{
timeFor
}
from
'
./lib/utils/datetime_utility
'
;
export
default
class
MilestoneSelect
{
export
default
class
MilestoneSelect
{
...
@@ -52,48 +53,47 @@ export default class MilestoneSelect {
...
@@ -52,48 +53,47 @@ export default class MilestoneSelect {
}
}
return
$dropdown
.
glDropdown
({
return
$dropdown
.
glDropdown
({
showMenuAbove
:
showMenuAbove
,
showMenuAbove
:
showMenuAbove
,
data
:
(
term
,
callback
)
=>
$
.
ajax
({
data
:
(
term
,
callback
)
=>
axios
.
get
(
milestonesUrl
)
url
:
milestonesUrl
.
then
(({
data
})
=>
{
}).
done
((
data
)
=>
{
const
extraOptions
=
[];
const
extraOptions
=
[];
if
(
showAny
)
{
if
(
showAny
)
{
extraOptions
.
push
({
extraOptions
.
push
({
id
:
0
,
id
:
0
,
name
:
''
,
name
:
''
,
title
:
'
Any Milestone
'
title
:
'
Any Milestone
'
});
});
}
}
if
(
showNo
)
{
if
(
showNo
)
{
extraOptions
.
push
({
extraOptions
.
push
({
id
:
-
1
,
id
:
-
1
,
name
:
'
No Milestone
'
,
name
:
'
No Milestone
'
,
title
:
'
No Milestone
'
title
:
'
No Milestone
'
});
});
}
}
if
(
showUpcoming
)
{
if
(
showUpcoming
)
{
extraOptions
.
push
({
extraOptions
.
push
({
id
:
-
2
,
id
:
-
2
,
name
:
'
#upcoming
'
,
name
:
'
#upcoming
'
,
title
:
'
Upcoming
'
title
:
'
Upcoming
'
});
});
}
}
if
(
showStarted
)
{
if
(
showStarted
)
{
extraOptions
.
push
({
extraOptions
.
push
({
id
:
-
3
,
id
:
-
3
,
name
:
'
#started
'
,
name
:
'
#started
'
,
title
:
'
Started
'
title
:
'
Started
'
});
});
}
}
if
(
extraOptions
.
length
)
{
if
(
extraOptions
.
length
)
{
extraOptions
.
push
(
'
divider
'
);
extraOptions
.
push
(
'
divider
'
);
}
}
callback
(
extraOptions
.
concat
(
data
));
callback
(
extraOptions
.
concat
(
data
));
if
(
showMenuAbove
)
{
if
(
showMenuAbove
)
{
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
}
}
$
(
`[data-milestone-id="
${
selectedMilestone
}
"] > a`
).
addClass
(
'
is-active
'
);
$
(
`[data-milestone-id="
${
selectedMilestone
}
"] > a`
).
addClass
(
'
is-active
'
);
}),
}),
renderRow
:
milestone
=>
`
renderRow
:
milestone
=>
`
<li data-milestone-id="
${
milestone
.
name
}
">
<li data-milestone-id="
${
milestone
.
name
}
">
<a href='#' class='dropdown-menu-milestone-link'>
<a href='#' class='dropdown-menu-milestone-link'>
...
@@ -200,26 +200,23 @@ export default class MilestoneSelect {
...
@@ -200,26 +200,23 @@ export default class MilestoneSelect {
data
[
abilityName
].
milestone_id
=
selected
!=
null
?
selected
:
null
;
data
[
abilityName
].
milestone_id
=
selected
!=
null
?
selected
:
null
;
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
return
$
.
ajax
({
return
axios
.
put
(
issueUpdateURL
,
data
)
type
:
'
PUT
'
,
.
then
(({
data
})
=>
{
url
:
issueUpdateURL
,
$dropdown
.
trigger
(
'
loaded.gl.dropdown
'
);
data
:
data
$loading
.
fadeOut
();
}).
done
((
data
)
=>
{
$selectBox
.
hide
();
$dropdown
.
trigger
(
'
loaded.gl.dropdown
'
);
$value
.
css
(
'
display
'
,
''
);
$loading
.
fadeOut
();
if
(
data
.
milestone
!=
null
)
{
$selectBox
.
hide
();
data
.
milestone
.
full_path
=
this
.
currentProject
.
full_path
;
$value
.
css
(
'
display
'
,
''
);
data
.
milestone
.
remaining
=
timeFor
(
data
.
milestone
.
due_date
);
if
(
data
.
milestone
!=
null
)
{
data
.
milestone
.
name
=
data
.
milestone
.
title
;
data
.
milestone
.
full_path
=
this
.
currentProject
.
full_path
;
$value
.
html
(
milestoneLinkTemplate
(
data
.
milestone
));
data
.
milestone
.
remaining
=
timeFor
(
data
.
milestone
.
due_date
);
return
$sidebarCollapsedValue
.
find
(
'
span
'
).
html
(
collapsedSidebarLabelTemplate
(
data
.
milestone
));
data
.
milestone
.
name
=
data
.
milestone
.
title
;
}
else
{
$value
.
html
(
milestoneLinkTemplate
(
data
.
milestone
));
$value
.
html
(
milestoneLinkNoneTemplate
);
return
$sidebarCollapsedValue
.
find
(
'
span
'
).
html
(
collapsedSidebarLabelTemplate
(
data
.
milestone
));
return
$sidebarCollapsedValue
.
find
(
'
span
'
).
text
(
'
No
'
);
}
else
{
}
$value
.
html
(
milestoneLinkNoneTemplate
);
});
return
$sidebarCollapsedValue
.
find
(
'
span
'
).
text
(
'
No
'
);
}
});
}
}
}
}
});
});
...
...
app/assets/javascripts/notes.js
View file @
8fa2932d
...
@@ -18,13 +18,14 @@ import 'vendor/jquery.atwho';
...
@@ -18,13 +18,14 @@ import 'vendor/jquery.atwho';
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
getLocationHash
}
from
'
./lib/utils/url_utility
'
;
import
{
getLocationHash
}
from
'
./lib/utils/url_utility
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
Flash
from
'
./flash
'
;
import
Flash
from
'
./flash
'
;
import
CommentTypeToggle
from
'
./comment_type_toggle
'
;
import
CommentTypeToggle
from
'
./comment_type_toggle
'
;
import
GLForm
from
'
./gl_form
'
;
import
GLForm
from
'
./gl_form
'
;
import
loadAwardsHandler
from
'
./awards_handler
'
;
import
loadAwardsHandler
from
'
./awards_handler
'
;
import
Autosave
from
'
./autosave
'
;
import
Autosave
from
'
./autosave
'
;
import
TaskList
from
'
./task_list
'
;
import
TaskList
from
'
./task_list
'
;
import
{
ajaxPost
,
isInViewport
,
getPagePath
,
scrollToElement
,
isMetaKey
}
from
'
./lib/utils/common_utils
'
;
import
{
isInViewport
,
getPagePath
,
scrollToElement
,
isMetaKey
}
from
'
./lib/utils/common_utils
'
;
import
imageDiffHelper
from
'
./image_diff/helpers/index
'
;
import
imageDiffHelper
from
'
./image_diff/helpers/index
'
;
import
{
localTimeAgo
}
from
'
./lib/utils/datetime_utility
'
;
import
{
localTimeAgo
}
from
'
./lib/utils/datetime_utility
'
;
...
@@ -1399,7 +1400,7 @@ export default class Notes {
...
@@ -1399,7 +1400,7 @@ export default class Notes {
* 2) Identify comment type; a) Main thread b) Discussion thread c) Discussion resolve
* 2) Identify comment type; a) Main thread b) Discussion thread c) Discussion resolve
* 3) Build temporary placeholder element (using `createPlaceholderNote`)
* 3) Build temporary placeholder element (using `createPlaceholderNote`)
* 4) Show placeholder note on UI
* 4) Show placeholder note on UI
* 5) Perform network request to submit the note using `a
jaxP
ost`
* 5) Perform network request to submit the note using `a
xios.p
ost`
* a) If request is successfully completed
* a) If request is successfully completed
* 1. Remove placeholder element
* 1. Remove placeholder element
* 2. Show submitted Note element
* 2. Show submitted Note element
...
@@ -1481,8 +1482,10 @@ export default class Notes {
...
@@ -1481,8 +1482,10 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */
/* eslint-disable promise/catch-or-return */
// Make request to submit comment on server
// Make request to submit comment on server
ajaxPost
(
formAction
,
formData
)
axios
.
post
(
formAction
,
formData
)
.
then
((
note
)
=>
{
.
then
((
res
)
=>
{
const
note
=
res
.
data
;
// Submission successful! remove placeholder
// Submission successful! remove placeholder
$notesContainer
.
find
(
`#
${
noteUniqueId
}
`
).
remove
();
$notesContainer
.
find
(
`#
${
noteUniqueId
}
`
).
remove
();
...
@@ -1555,7 +1558,7 @@ export default class Notes {
...
@@ -1555,7 +1558,7 @@ export default class Notes {
}
}
$form
.
trigger
(
'
ajax:success
'
,
[
note
]);
$form
.
trigger
(
'
ajax:success
'
,
[
note
]);
}).
fail
(()
=>
{
}).
catch
(()
=>
{
// Submission failed, remove placeholder note and show Flash error message
// Submission failed, remove placeholder note and show Flash error message
$notesContainer
.
find
(
`#
${
noteUniqueId
}
`
).
remove
();
$notesContainer
.
find
(
`#
${
noteUniqueId
}
`
).
remove
();
...
@@ -1594,7 +1597,7 @@ export default class Notes {
...
@@ -1594,7 +1597,7 @@ export default class Notes {
*
*
* 1) Get Form metadata
* 1) Get Form metadata
* 2) Update note element with new content
* 2) Update note element with new content
* 3) Perform network request to submit the updated note using `a
jaxP
ost`
* 3) Perform network request to submit the updated note using `a
xios.p
ost`
* a) If request is successfully completed
* a) If request is successfully completed
* 1. Show submitted Note element
* 1. Show submitted Note element
* b) If request failed
* b) If request failed
...
@@ -1625,12 +1628,12 @@ export default class Notes {
...
@@ -1625,12 +1628,12 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */
/* eslint-disable promise/catch-or-return */
// Make request to update comment on server
// Make request to update comment on server
a
jaxP
ost
(
formAction
,
formData
)
a
xios
.
p
ost
(
formAction
,
formData
)
.
then
((
note
)
=>
{
.
then
((
{
data
}
)
=>
{
// Submission successful! render final note element
// Submission successful! render final note element
this
.
updateNote
(
note
,
$editingNote
);
this
.
updateNote
(
data
,
$editingNote
);
})
})
.
fail
(()
=>
{
.
catch
(()
=>
{
// Submission failed, revert back to original note
// Submission failed, revert back to original note
$noteBodyText
.
html
(
_
.
escape
(
cachedNoteBodyText
));
$noteBodyText
.
html
(
_
.
escape
(
cachedNoteBodyText
));
$editingNote
.
removeClass
(
'
being-posted fade-in
'
);
$editingNote
.
removeClass
(
'
being-posted fade-in
'
);
...
...
spec/javascripts/issue_spec.js
View file @
8fa2932d
/* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
/* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
Issue
from
'
~/issue
'
;
import
Issue
from
'
~/issue
'
;
import
'
~/lib/utils/text_utility
'
;
import
'
~/lib/utils/text_utility
'
;
...
@@ -88,20 +90,24 @@ describe('Issue', function() {
...
@@ -88,20 +90,24 @@ describe('Issue', function() {
[
true
,
false
].
forEach
((
isIssueInitiallyOpen
)
=>
{
[
true
,
false
].
forEach
((
isIssueInitiallyOpen
)
=>
{
describe
(
`with
${
isIssueInitiallyOpen
?
'
open
'
:
'
closed
'
}
issue`
,
function
()
{
describe
(
`with
${
isIssueInitiallyOpen
?
'
open
'
:
'
closed
'
}
issue`
,
function
()
{
const
action
=
isIssueInitiallyOpen
?
'
close
'
:
'
reopen
'
;
const
action
=
isIssueInitiallyOpen
?
'
close
'
:
'
reopen
'
;
let
mock
;
function
ajaxSpy
(
req
)
{
function
mockCloseButtonResponseSuccess
(
url
,
response
)
{
if
(
req
.
url
===
this
.
$triggeredButton
.
attr
(
'
href
'
))
{
mock
.
onPut
(
url
).
reply
(()
=>
{
expect
(
req
.
type
).
toBe
(
'
PUT
'
);
expectNewBranchButtonState
(
true
,
false
);
expectNewBranchButtonState
(
true
,
false
);
return
this
.
issueStateDeferred
;
}
else
if
(
req
.
url
===
Issue
.
createMrDropdownWrap
.
dataset
.
canCreatePath
)
{
expect
(
req
.
type
).
toBe
(
'
GET
'
);
expectNewBranchButtonState
(
true
,
false
);
return
this
.
canCreateBranchDeferred
;
}
expect
(
req
.
url
).
toBe
(
'
unexpected
'
);
return
[
200
,
response
];
return
null
;
});
}
function
mockCloseButtonResponseError
(
url
)
{
mock
.
onPut
(
url
).
networkError
();
}
function
mockCanCreateBranch
(
canCreateBranch
)
{
mock
.
onGet
(
/
(
.*
)\/
can_create_branch$/
).
reply
(
200
,
{
can_create_branch
:
canCreateBranch
,
});
}
}
beforeEach
(
function
()
{
beforeEach
(
function
()
{
...
@@ -111,6 +117,11 @@ describe('Issue', function() {
...
@@ -111,6 +117,11 @@ describe('Issue', function() {
loadFixtures
(
'
issues/closed-issue.html.raw
'
);
loadFixtures
(
'
issues/closed-issue.html.raw
'
);
}
}
mock
=
new
MockAdapter
(
axios
);
mock
.
onGet
(
/
(
.*
)\/
related_branches$/
).
reply
(
200
,
{});
mock
.
onGet
(
/
(
.*
)\/
referenced_merge_requests$/
).
reply
(
200
,
{});
findElements
(
isIssueInitiallyOpen
);
findElements
(
isIssueInitiallyOpen
);
this
.
issue
=
new
Issue
();
this
.
issue
=
new
Issue
();
expectIssueState
(
isIssueInitiallyOpen
);
expectIssueState
(
isIssueInitiallyOpen
);
...
@@ -120,71 +131,89 @@ describe('Issue', function() {
...
@@ -120,71 +131,89 @@ describe('Issue', function() {
this
.
$projectIssuesCounter
=
$
(
'
.issue_counter
'
).
first
();
this
.
$projectIssuesCounter
=
$
(
'
.issue_counter
'
).
first
();
this
.
$projectIssuesCounter
.
text
(
'
1,001
'
);
this
.
$projectIssuesCounter
.
text
(
'
1,001
'
);
this
.
issueStateDeferred
=
new
jQuery
.
Deferred
();
spyOn
(
axios
,
'
get
'
).
and
.
callThrough
();
this
.
canCreateBranchDeferred
=
new
jQuery
.
Deferred
(
);
}
);
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callFake
(
ajaxSpy
.
bind
(
this
));
afterEach
(()
=>
{
mock
.
restore
();
$
(
'
div.flash-alert
'
).
remove
();
});
});
it
(
`
${
action
}
s the issue`
,
function
()
{
it
(
`
${
action
}
s the issue`
,
function
(
done
)
{
this
.
$triggeredButton
.
trigger
(
'
click
'
);
mockCloseButtonResponseSuccess
(
this
.
$triggeredButton
.
attr
(
'
href
'
),
{
this
.
issueStateDeferred
.
resolve
({
id
:
34
id
:
34
});
});
this
.
canCreateBranchDeferred
.
resolve
({
mockCanCreateBranch
(
!
isIssueInitiallyOpen
);
can_create_branch
:
!
isIssueInitiallyOpen
});
expectIssueState
(
!
isIssueInitiallyOpen
);
this
.
$triggeredButton
.
trigger
(
'
click
'
);
expect
(
this
.
$triggeredButton
.
get
(
0
).
getAttribute
(
'
disabled
'
)).
toBeNull
();
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
isIssueInitiallyOpen
?
'
1,000
'
:
'
1,002
'
);
setTimeout
(()
=>
{
expectNewBranchButtonState
(
false
,
!
isIssueInitiallyOpen
);
expectIssueState
(
!
isIssueInitiallyOpen
);
expect
(
this
.
$triggeredButton
.
get
(
0
).
getAttribute
(
'
disabled
'
)).
toBeNull
();
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
isIssueInitiallyOpen
?
'
1,000
'
:
'
1,002
'
);
expectNewBranchButtonState
(
false
,
!
isIssueInitiallyOpen
);
done
();
});
});
});
it
(
`fails to
${
action
}
the issue if saved:false`
,
function
()
{
it
(
`fails to
${
action
}
the issue if saved:false`
,
function
(
done
)
{
this
.
$triggeredButton
.
trigger
(
'
click
'
);
mockCloseButtonResponseSuccess
(
this
.
$triggeredButton
.
attr
(
'
href
'
),
{
this
.
issueStateDeferred
.
resolve
({
saved
:
false
saved
:
false
});
});
this
.
canCreateBranchDeferred
.
resolve
({
mockCanCreateBranch
(
isIssueInitiallyOpen
);
can_create_branch
:
isIssueInitiallyOpen
});
expectIssueState
(
isIssueInitiallyOpen
);
this
.
$triggeredButton
.
trigger
(
'
click
'
);
expect
(
this
.
$triggeredButton
.
get
(
0
).
getAttribute
(
'
disabled
'
)).
toBeNull
();
expectErrorMessage
();
setTimeout
(()
=>
{
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
'
1,001
'
);
expectIssueState
(
isIssueInitiallyOpen
);
expectNewBranchButtonState
(
false
,
isIssueInitiallyOpen
);
expect
(
this
.
$triggeredButton
.
get
(
0
).
getAttribute
(
'
disabled
'
)).
toBeNull
();
expectErrorMessage
();
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
'
1,001
'
);
expectNewBranchButtonState
(
false
,
isIssueInitiallyOpen
);
done
();
});
});
});
it
(
`fails to
${
action
}
the issue if HTTP error occurs`
,
function
()
{
it
(
`fails to
${
action
}
the issue if HTTP error occurs`
,
function
(
done
)
{
mockCloseButtonResponseError
(
this
.
$triggeredButton
.
attr
(
'
href
'
));
mockCanCreateBranch
(
isIssueInitiallyOpen
);
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
issueStateDeferred
.
reject
();
this
.
canCreateBranchDeferred
.
resolve
({
can_create_branch
:
isIssueInitiallyOpen
});
expectIssueState
(
isIssueInitiallyOpen
);
setTimeout
(()
=>
{
expect
(
this
.
$triggeredButton
.
get
(
0
).
getAttribute
(
'
disabled
'
)).
toBeNull
();
expectIssueState
(
isIssueInitiallyOpen
);
expectErrorMessage
();
expect
(
this
.
$triggeredButton
.
get
(
0
).
getAttribute
(
'
disabled
'
)).
toBeNull
();
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
'
1,001
'
);
expectErrorMessage
();
expectNewBranchButtonState
(
false
,
isIssueInitiallyOpen
);
expect
(
this
.
$projectIssuesCounter
.
text
()).
toBe
(
'
1,001
'
);
expectNewBranchButtonState
(
false
,
isIssueInitiallyOpen
);
done
();
});
});
});
it
(
'
disables the new branch button if Ajax call fails
'
,
function
()
{
it
(
'
disables the new branch button if Ajax call fails
'
,
function
()
{
mockCloseButtonResponseError
(
this
.
$triggeredButton
.
attr
(
'
href
'
));
mock
.
onGet
(
/
(
.*
)\/
can_create_branch$/
).
networkError
();
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
issueStateDeferred
.
reject
();
this
.
canCreateBranchDeferred
.
reject
();
expectNewBranchButtonState
(
false
,
false
);
expectNewBranchButtonState
(
false
,
false
);
});
});
it
(
'
does not trigger Ajax call if new branch button is missing
'
,
function
()
{
it
(
'
does not trigger Ajax call if new branch button is missing
'
,
function
(
done
)
{
mockCloseButtonResponseError
(
this
.
$triggeredButton
.
attr
(
'
href
'
));
Issue
.
$btnNewBranch
=
$
();
Issue
.
$btnNewBranch
=
$
();
this
.
canCreateBranchDeferred
=
null
;
this
.
canCreateBranchDeferred
=
null
;
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
$triggeredButton
.
trigger
(
'
click
'
);
this
.
issueStateDeferred
.
reject
();
setTimeout
(()
=>
{
expect
(
axios
.
get
).
not
.
toHaveBeenCalled
();
done
();
});
});
});
});
});
});
});
...
...
spec/javascripts/job_spec.js
View file @
8fa2932d
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
numberToHumanSize
}
from
'
~/lib/utils/number_utils
'
;
import
{
numberToHumanSize
}
from
'
~/lib/utils/number_utils
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
'
~/lib/utils/datetime_utility
'
;
import
'
~/lib/utils/datetime_utility
'
;
...
@@ -6,11 +8,29 @@ import '~/breakpoints';
...
@@ -6,11 +8,29 @@ import '~/breakpoints';
describe
(
'
Job
'
,
()
=>
{
describe
(
'
Job
'
,
()
=>
{
const
JOB_URL
=
`
${
gl
.
TEST_HOST
}
/frontend-fixtures/builds-project/-/jobs/1`
;
const
JOB_URL
=
`
${
gl
.
TEST_HOST
}
/frontend-fixtures/builds-project/-/jobs/1`
;
let
mock
;
let
response
;
function
waitForPromise
()
{
return
new
Promise
(
resolve
=>
requestAnimationFrame
(
resolve
));
}
preloadFixtures
(
'
builds/build-with-artifacts.html.raw
'
);
preloadFixtures
(
'
builds/build-with-artifacts.html.raw
'
);
beforeEach
(()
=>
{
beforeEach
(()
=>
{
loadFixtures
(
'
builds/build-with-artifacts.html.raw
'
);
loadFixtures
(
'
builds/build-with-artifacts.html.raw
'
);
spyOn
(
urlUtils
,
'
visitUrl
'
);
mock
=
new
MockAdapter
(
axios
);
mock
.
onGet
(
new
RegExp
(
`
${
JOB_URL
}
/trace.json?(.*)`
)).
reply
(()
=>
[
200
,
response
]);
});
afterEach
(()
=>
{
mock
.
restore
();
response
=
{};
});
});
describe
(
'
class constructor
'
,
()
=>
{
describe
(
'
class constructor
'
,
()
=>
{
...
@@ -55,161 +75,159 @@ describe('Job', () => {
...
@@ -55,161 +75,159 @@ describe('Job', () => {
});
});
describe
(
'
running build
'
,
()
=>
{
describe
(
'
running build
'
,
()
=>
{
it
(
'
updates the build trace on an interval
'
,
function
()
{
it
(
'
updates the build trace on an interval
'
,
function
(
done
)
{
const
deferred1
=
$
.
Deferred
();
response
=
{
const
deferred2
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValues
(
deferred1
.
promise
(),
deferred2
.
promise
());
spyOn
(
urlUtils
,
'
visitUrl
'
);
deferred1
.
resolve
({
html
:
'
<span>Update<span>
'
,
html
:
'
<span>Update<span>
'
,
status
:
'
running
'
,
status
:
'
running
'
,
state
:
'
newstate
'
,
state
:
'
newstate
'
,
append
:
true
,
append
:
true
,
complete
:
false
,
complete
:
false
,
});
};
deferred2
.
resolve
({
html
:
'
<span>More</span>
'
,
status
:
'
running
'
,
state
:
'
finalstate
'
,
append
:
true
,
complete
:
true
,
});
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
waitForPromise
()
expect
(
this
.
job
.
state
).
toBe
(
'
newstate
'
);
.
then
(()
=>
{
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
jasmine
.
clock
().
tick
(
4001
);
expect
(
this
.
job
.
state
).
toBe
(
'
newstate
'
);
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/UpdateMore/
);
response
=
{
expect
(
this
.
job
.
state
).
toBe
(
'
finalstate
'
);
html
:
'
<span>More</span>
'
,
status
:
'
running
'
,
state
:
'
finalstate
'
,
append
:
true
,
complete
:
true
,
};
})
.
then
(()
=>
jasmine
.
clock
().
tick
(
4001
))
.
then
(
waitForPromise
)
.
then
(()
=>
{
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/UpdateMore/
);
expect
(
this
.
job
.
state
).
toBe
(
'
finalstate
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
it
(
'
replaces the entire build trace
'
,
()
=>
{
it
(
'
replaces the entire build trace
'
,
(
done
)
=>
{
const
deferred1
=
$
.
Deferred
();
response
=
{
const
deferred2
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValues
(
deferred1
.
promise
(),
deferred2
.
promise
());
spyOn
(
urlUtils
,
'
visitUrl
'
);
deferred1
.
resolve
({
html
:
'
<span>Update<span>
'
,
html
:
'
<span>Update<span>
'
,
status
:
'
running
'
,
status
:
'
running
'
,
append
:
false
,
append
:
false
,
complete
:
false
,
complete
:
false
,
});
};
deferred2
.
resolve
({
html
:
'
<span>Different</span>
'
,
status
:
'
running
'
,
append
:
false
,
});
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
waitForPromise
()
.
then
(()
=>
{
jasmine
.
clock
().
tick
(
4001
);
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
not
.
toMatch
(
/Update/
);
response
=
{
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Different/
);
html
:
'
<span>Different</span>
'
,
status
:
'
running
'
,
append
:
false
,
};
})
.
then
(()
=>
jasmine
.
clock
().
tick
(
4001
))
.
then
(
waitForPromise
)
.
then
(()
=>
{
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
not
.
toMatch
(
/Update/
);
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Different/
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
});
});
describe
(
'
truncated information
'
,
()
=>
{
describe
(
'
truncated information
'
,
()
=>
{
describe
(
'
when size is less than total
'
,
()
=>
{
describe
(
'
when size is less than total
'
,
()
=>
{
it
(
'
shows information about truncated log
'
,
()
=>
{
it
(
'
shows information about truncated log
'
,
(
done
)
=>
{
spyOn
(
urlUtils
,
'
visitUrl
'
);
response
=
{
const
deferred
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
status
:
'
success
'
,
append
:
false
,
append
:
false
,
size
:
50
,
size
:
50
,
total
:
100
,
total
:
100
,
}
)
;
};
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
not
.
toContain
(
'
hidden
'
);
waitForPromise
()
.
then
(()
=>
{
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
not
.
toContain
(
'
hidden
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
it
(
'
shows the size in KiB
'
,
()
=>
{
it
(
'
shows the size in KiB
'
,
(
done
)
=>
{
const
size
=
50
;
const
size
=
50
;
spyOn
(
urlUtils
,
'
visitUrl
'
);
const
deferred
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
response
=
{
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
status
:
'
success
'
,
append
:
false
,
append
:
false
,
size
,
size
,
total
:
100
,
total
:
100
,
}
)
;
};
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
expect
(
waitForPromise
()
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
.
then
(()
=>
{
).
toEqual
(
`
${
numberToHumanSize
(
size
)}
`
);
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
numberToHumanSize
(
size
)}
`
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
it
(
'
shows incremented size
'
,
()
=>
{
it
(
'
shows incremented size
'
,
(
done
)
=>
{
const
deferred1
=
$
.
Deferred
();
response
=
{
const
deferred2
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValues
(
deferred1
.
promise
(),
deferred2
.
promise
());
spyOn
(
urlUtils
,
'
visitUrl
'
);
deferred1
.
resolve
({
html
:
'
<span>Update</span>
'
,
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
status
:
'
success
'
,
append
:
false
,
append
:
false
,
size
:
50
,
size
:
50
,
total
:
100
,
total
:
100
,
}
)
;
};
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
expect
(
waitForPromise
()
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
.
then
(()
=>
{
).
toEqual
(
`
${
numberToHumanSize
(
50
)}
`
);
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
jasmine
.
clock
().
tick
(
4001
);
).
toEqual
(
`
${
numberToHumanSize
(
50
)}
`
);
deferred2
.
resolve
({
response
=
{
html
:
'
<span>Update</span>
'
,
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
status
:
'
success
'
,
append
:
true
,
append
:
true
,
size
:
10
,
size
:
10
,
total
:
100
,
total
:
100
,
});
};
})
expect
(
.
then
(()
=>
jasmine
.
clock
().
tick
(
4001
))
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
.
then
(
waitForPromise
)
).
toEqual
(
`
${
numberToHumanSize
(
60
)}
`
);
.
then
(()
=>
{
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
numberToHumanSize
(
60
)}
`
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
it
(
'
renders the raw link
'
,
()
=>
{
it
(
'
renders the raw link
'
,
()
=>
{
const
deferred
=
$
.
Deferred
();
response
=
{
spyOn
(
urlUtils
,
'
visitUrl
'
);
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
status
:
'
success
'
,
append
:
false
,
append
:
false
,
size
:
50
,
size
:
50
,
total
:
100
,
total
:
100
,
}
)
;
};
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
...
@@ -220,50 +238,50 @@ describe('Job', () => {
...
@@ -220,50 +238,50 @@ describe('Job', () => {
});
});
describe
(
'
when size is equal than total
'
,
()
=>
{
describe
(
'
when size is equal than total
'
,
()
=>
{
it
(
'
does not show the trunctated information
'
,
()
=>
{
it
(
'
does not show the trunctated information
'
,
(
done
)
=>
{
const
deferred
=
$
.
Deferred
();
response
=
{
spyOn
(
urlUtils
,
'
visitUrl
'
);
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
status
:
'
success
'
,
append
:
false
,
append
:
false
,
size
:
100
,
size
:
100
,
total
:
100
,
total
:
100
,
}
)
;
};
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
toContain
(
'
hidden
'
);
waitForPromise
()
.
then
(()
=>
{
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
toContain
(
'
hidden
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
});
});
});
});
describe
(
'
output trace
'
,
()
=>
{
describe
(
'
output trace
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
((
done
)
=>
{
const
deferred
=
$
.
Deferred
();
response
=
{
spyOn
(
urlUtils
,
'
visitUrl
'
);
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
status
:
'
success
'
,
append
:
false
,
append
:
false
,
size
:
50
,
size
:
50
,
total
:
100
,
total
:
100
,
}
)
;
};
this
.
job
=
new
Job
();
this
.
job
=
new
Job
();
waitForPromise
()
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
it
(
'
should render trace controls
'
,
()
=>
{
it
(
'
should render trace controls
'
,
()
=>
{
const
controllers
=
document
.
querySelector
(
'
.controllers
'
);
const
controllers
=
document
.
querySelector
(
'
.controllers
'
);
expect
(
controllers
.
querySelector
(
'
.js-raw-link-controller
'
)).
toBeDefined
();
expect
(
controllers
.
querySelector
(
'
.js-raw-link-controller
'
)).
not
.
toBeNull
();
expect
(
controllers
.
querySelector
(
'
.js-erase-link
'
)).
toBeDefined
();
expect
(
controllers
.
querySelector
(
'
.js-scroll-up
'
)).
not
.
toBeNull
();
expect
(
controllers
.
querySelector
(
'
.js-scroll-up
'
)).
toBeDefined
();
expect
(
controllers
.
querySelector
(
'
.js-scroll-down
'
)).
not
.
toBeNull
();
expect
(
controllers
.
querySelector
(
'
.js-scroll-down
'
)).
toBeDefined
();
});
});
it
(
'
should render received output
'
,
()
=>
{
it
(
'
should render received output
'
,
()
=>
{
...
@@ -276,13 +294,13 @@ describe('Job', () => {
...
@@ -276,13 +294,13 @@ describe('Job', () => {
describe
(
'
getBuildTrace
'
,
()
=>
{
describe
(
'
getBuildTrace
'
,
()
=>
{
it
(
'
should request build trace with state parameter
'
,
(
done
)
=>
{
it
(
'
should request build trace with state parameter
'
,
(
done
)
=>
{
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callThrough
();
spyOn
(
axios
,
'
get
'
).
and
.
callThrough
();
// eslint-disable-next-line no-new
// eslint-disable-next-line no-new
new
Job
();
new
Job
();
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
jQuery
.
ajax
).
toHaveBeenCalledWith
(
expect
(
axios
.
get
).
toHaveBeenCalledWith
(
{
url
:
`
${
JOB_URL
}
/trace.json`
,
data
:
{
state
:
''
}
},
`
${
JOB_URL
}
/trace.json`
,
{
params
:
{
state
:
''
}
},
);
);
done
();
done
();
},
0
);
},
0
);
...
...
spec/javascripts/labels_issue_sidebar_spec.js
View file @
8fa2932d
/* eslint-disable no-new */
/* eslint-disable no-new */
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
IssuableContext
from
'
~/issuable_context
'
;
import
IssuableContext
from
'
~/issuable_context
'
;
import
LabelsSelect
from
'
~/labels_select
'
;
import
LabelsSelect
from
'
~/labels_select
'
;
...
@@ -10,35 +12,44 @@ import '~/users_select';
...
@@ -10,35 +12,44 @@ import '~/users_select';
(()
=>
{
(()
=>
{
let
saveLabelCount
=
0
;
let
saveLabelCount
=
0
;
let
mock
;
describe
(
'
Issue dropdown sidebar
'
,
()
=>
{
describe
(
'
Issue dropdown sidebar
'
,
()
=>
{
preloadFixtures
(
'
static/issue_sidebar_label.html.raw
'
);
preloadFixtures
(
'
static/issue_sidebar_label.html.raw
'
);
beforeEach
(()
=>
{
beforeEach
(()
=>
{
loadFixtures
(
'
static/issue_sidebar_label.html.raw
'
);
loadFixtures
(
'
static/issue_sidebar_label.html.raw
'
);
mock
=
new
MockAdapter
(
axios
);
new
IssuableContext
(
'
{"id":1,"name":"Administrator","username":"root"}
'
);
new
IssuableContext
(
'
{"id":1,"name":"Administrator","username":"root"}
'
);
new
LabelsSelect
();
new
LabelsSelect
();
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callFake
((
req
)
=>
{
mock
.
onGet
(
'
/root/test/labels.json
'
).
reply
(()
=>
{
const
d
=
$
.
Deferred
();
const
labels
=
Array
(
10
).
fill
().
map
((
_
,
i
)
=>
({
let
LABELS_DATA
=
[];
id
:
i
,
title
:
`test
${
i
}
`
,
color
:
'
#5CB85C
'
,
}));
if
(
req
.
url
===
'
/root/test/labels.json
'
)
{
return
[
200
,
labels
];
for
(
let
i
=
0
;
i
<
10
;
i
+=
1
)
{
});
LABELS_DATA
.
push
({
id
:
i
,
title
:
`test
${
i
}
`
,
color
:
'
#5CB85C
'
});
}
mock
.
onPut
(
'
/root/test/issues/2.json
'
).
reply
(()
=>
{
}
else
if
(
req
.
url
===
'
/root/test/issues/2.json
'
)
{
const
labels
=
Array
(
saveLabelCount
).
fill
().
map
((
_
,
i
)
=>
({
const
tmp
=
[];
id
:
i
,
for
(
let
i
=
0
;
i
<
saveLabelCount
;
i
+=
1
)
{
title
:
`test
${
i
}
`
,
tmp
.
push
({
id
:
i
,
title
:
`test
${
i
}
`
,
color
:
'
#5CB85C
'
});
color
:
'
#5CB85C
'
,
}
}));
LABELS_DATA
=
{
labels
:
tmp
};
}
d
.
resolve
(
LABELS_DATA
);
return
[
200
,
{
labels
}];
return
d
.
promise
();
});
});
});
});
afterEach
(()
=>
{
mock
.
restore
();
});
it
(
'
changes collapsed tooltip when changing labels when less than 5
'
,
(
done
)
=>
{
it
(
'
changes collapsed tooltip when changing labels when less than 5
'
,
(
done
)
=>
{
saveLabelCount
=
5
;
saveLabelCount
=
5
;
$
(
'
.edit-link
'
).
get
(
0
).
click
();
$
(
'
.edit-link
'
).
get
(
0
).
click
();
...
...
spec/javascripts/lib/utils/ajax_cache_spec.js
View file @
8fa2932d
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
describe
(
'
AjaxCache
'
,
()
=>
{
describe
(
'
AjaxCache
'
,
()
=>
{
...
@@ -87,66 +89,53 @@ describe('AjaxCache', () => {
...
@@ -87,66 +89,53 @@ describe('AjaxCache', () => {
});
});
describe
(
'
retrieve
'
,
()
=>
{
describe
(
'
retrieve
'
,
()
=>
{
let
ajaxSpy
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callFake
(
url
=>
ajaxSpy
(
url
));
mock
=
new
MockAdapter
(
axios
);
spyOn
(
axios
,
'
get
'
).
and
.
callThrough
();
});
afterEach
(()
=>
{
mock
.
restore
();
});
});
it
(
'
stores and returns data from Ajax call if cache is empty
'
,
(
done
)
=>
{
it
(
'
stores and returns data from Ajax call if cache is empty
'
,
(
done
)
=>
{
ajaxSpy
=
(
url
)
=>
{
mock
.
onGet
(
dummyEndpoint
).
reply
(
200
,
dummyResponse
);
expect
(
url
).
toBe
(
dummyEndpoint
);
const
deferred
=
$
.
Deferred
();
deferred
.
resolve
(
dummyResponse
);
return
deferred
.
promise
();
};
AjaxCache
.
retrieve
(
dummyEndpoint
)
AjaxCache
.
retrieve
(
dummyEndpoint
)
.
then
((
data
)
=>
{
.
then
((
data
)
=>
{
expect
(
data
).
to
Be
(
dummyResponse
);
expect
(
data
).
to
Equal
(
dummyResponse
);
expect
(
AjaxCache
.
internalStorage
[
dummyEndpoint
]).
to
Be
(
dummyResponse
);
expect
(
AjaxCache
.
internalStorage
[
dummyEndpoint
]).
to
Equal
(
dummyResponse
);
})
})
.
then
(
done
)
.
then
(
done
)
.
catch
(
fail
);
.
catch
(
fail
);
});
});
it
(
'
makes no Ajax call if request is pending
'
,
()
=>
{
it
(
'
makes no Ajax call if request is pending
'
,
(
done
)
=>
{
const
responseDeferred
=
$
.
Deferred
();
mock
.
onGet
(
dummyEndpoint
).
reply
(
200
,
dummyResponse
);
ajaxSpy
=
(
url
)
=>
{
expect
(
url
).
toBe
(
dummyEndpoint
);
// neither reject nor resolve to keep request pending
return
responseDeferred
.
promise
();
};
const
unexpectedResponse
=
data
=>
fail
(
`Did not expect response:
${
data
}
`
);
AjaxCache
.
retrieve
(
dummyEndpoint
)
AjaxCache
.
retrieve
(
dummyEndpoint
)
.
then
(
unexpectedRespons
e
)
.
then
(
don
e
)
.
catch
(
fail
);
.
catch
(
fail
);
AjaxCache
.
retrieve
(
dummyEndpoint
)
AjaxCache
.
retrieve
(
dummyEndpoint
)
.
then
(
unexpectedRespons
e
)
.
then
(
don
e
)
.
catch
(
fail
);
.
catch
(
fail
);
expect
(
$
.
ajax
.
calls
.
count
()).
toBe
(
1
);
expect
(
axios
.
get
.
calls
.
count
()).
toBe
(
1
);
});
});
it
(
'
returns undefined if Ajax call fails and cache is empty
'
,
(
done
)
=>
{
it
(
'
returns undefined if Ajax call fails and cache is empty
'
,
(
done
)
=>
{
const
dummyStatusText
=
'
exploded
'
;
const
errorMessage
=
'
Network Error
'
;
const
dummyErrorMessage
=
'
server exploded
'
;
mock
.
onGet
(
dummyEndpoint
).
networkError
();
ajaxSpy
=
(
url
)
=>
{
expect
(
url
).
toBe
(
dummyEndpoint
);
const
deferred
=
$
.
Deferred
();
deferred
.
reject
(
null
,
dummyStatusText
,
dummyErrorMessage
);
return
deferred
.
promise
();
};
AjaxCache
.
retrieve
(
dummyEndpoint
)
AjaxCache
.
retrieve
(
dummyEndpoint
)
.
then
(
data
=>
fail
(
`Received unexpected data:
${
JSON
.
stringify
(
data
)}
`
))
.
then
(
data
=>
fail
(
`Received unexpected data:
${
JSON
.
stringify
(
data
)}
`
))
.
catch
((
error
)
=>
{
.
catch
((
error
)
=>
{
expect
(
error
.
message
).
toBe
(
`
${
dummyEndpoint
}
:
${
dummyE
rrorMessage
}
`
);
expect
(
error
.
message
).
toBe
(
`
${
dummyEndpoint
}
:
${
e
rrorMessage
}
`
);
expect
(
error
.
textStatus
).
toBe
(
dummyStatusText
);
expect
(
error
.
textStatus
).
toBe
(
errorMessage
);
done
();
done
();
})
})
.
catch
(
fail
);
.
catch
(
fail
);
...
@@ -154,7 +143,9 @@ describe('AjaxCache', () => {
...
@@ -154,7 +143,9 @@ describe('AjaxCache', () => {
it
(
'
makes no Ajax call if matching data exists
'
,
(
done
)
=>
{
it
(
'
makes no Ajax call if matching data exists
'
,
(
done
)
=>
{
AjaxCache
.
internalStorage
[
dummyEndpoint
]
=
dummyResponse
;
AjaxCache
.
internalStorage
[
dummyEndpoint
]
=
dummyResponse
;
ajaxSpy
=
()
=>
fail
(
new
Error
(
'
expected no Ajax call!
'
));
mock
.
onGet
(
dummyEndpoint
).
reply
(()
=>
{
fail
(
new
Error
(
'
expected no Ajax call!
'
));
});
AjaxCache
.
retrieve
(
dummyEndpoint
)
AjaxCache
.
retrieve
(
dummyEndpoint
)
.
then
((
data
)
=>
{
.
then
((
data
)
=>
{
...
@@ -171,12 +162,7 @@ describe('AjaxCache', () => {
...
@@ -171,12 +162,7 @@ describe('AjaxCache', () => {
AjaxCache
.
internalStorage
[
dummyEndpoint
]
=
oldDummyResponse
;
AjaxCache
.
internalStorage
[
dummyEndpoint
]
=
oldDummyResponse
;
ajaxSpy
=
(
url
)
=>
{
mock
.
onGet
(
dummyEndpoint
).
reply
(
200
,
dummyResponse
);
expect
(
url
).
toBe
(
dummyEndpoint
);
const
deferred
=
$
.
Deferred
();
deferred
.
resolve
(
dummyResponse
);
return
deferred
.
promise
();
};
// Call without forceRetrieve param
// Call without forceRetrieve param
AjaxCache
.
retrieve
(
dummyEndpoint
)
AjaxCache
.
retrieve
(
dummyEndpoint
)
...
@@ -189,7 +175,7 @@ describe('AjaxCache', () => {
...
@@ -189,7 +175,7 @@ describe('AjaxCache', () => {
// Call with forceRetrieve param
// Call with forceRetrieve param
AjaxCache
.
retrieve
(
dummyEndpoint
,
true
)
AjaxCache
.
retrieve
(
dummyEndpoint
,
true
)
.
then
((
data
)
=>
{
.
then
((
data
)
=>
{
expect
(
data
).
to
Be
(
dummyResponse
);
expect
(
data
).
to
Equal
(
dummyResponse
);
})
})
.
then
(
done
)
.
then
(
done
)
.
catch
(
fail
);
.
catch
(
fail
);
...
...
spec/javascripts/lib/utils/common_utils_spec.js
View file @
8fa2932d
/* eslint-disable promise/catch-or-return */
/* eslint-disable promise/catch-or-return */
import
*
as
commonUtils
from
'
~/lib/utils/common_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
*
as
commonUtils
from
'
~/lib/utils/common_utils
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
describe
(
'
common_utils
'
,
()
=>
{
describe
(
'
common_utils
'
,
()
=>
{
...
@@ -460,17 +459,6 @@ describe('common_utils', () => {
...
@@ -460,17 +459,6 @@ describe('common_utils', () => {
});
});
});
});
describe
(
'
ajaxPost
'
,
()
=>
{
it
(
'
should perform `$.ajax` call and do `POST` request
'
,
()
=>
{
const
requestURL
=
'
/some/random/api
'
;
const
data
=
{
keyname
:
'
value
'
};
const
ajaxSpy
=
spyOn
(
$
,
'
ajax
'
).
and
.
callFake
(()
=>
{});
commonUtils
.
ajaxPost
(
requestURL
,
data
);
expect
(
ajaxSpy
.
calls
.
allArgs
()[
0
][
0
].
type
).
toEqual
(
'
POST
'
);
});
});
describe
(
'
spriteIcon
'
,
()
=>
{
describe
(
'
spriteIcon
'
,
()
=>
{
let
beforeGon
;
let
beforeGon
;
...
...
spec/javascripts/merge_request_tabs_spec.js
View file @
8fa2932d
/* eslint-disable no-var, comma-dangle, object-shorthand */
/* eslint-disable no-var, comma-dangle, object-shorthand */
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
MergeRequestTabs
from
'
~/merge_request_tabs
'
;
import
MergeRequestTabs
from
'
~/merge_request_tabs
'
;
import
'
~/commit/pipelines/pipelines_bundle
'
;
import
'
~/commit/pipelines/pipelines_bundle
'
;
...
@@ -46,7 +47,7 @@ import 'vendor/jquery.scrollTo';
...
@@ -46,7 +47,7 @@ import 'vendor/jquery.scrollTo';
describe
(
'
activateTab
'
,
function
()
{
describe
(
'
activateTab
'
,
function
()
{
beforeEach
(
function
()
{
beforeEach
(
function
()
{
spyOn
(
$
,
'
ajax
'
).
and
.
callFake
(
function
()
{}
);
spyOn
(
axios
,
'
get
'
).
and
.
returnValue
(
Promise
.
resolve
({
data
:
{}
})
);
loadFixtures
(
'
merge_requests/merge_request_with_task_list.html.raw
'
);
loadFixtures
(
'
merge_requests/merge_request_with_task_list.html.raw
'
);
this
.
subject
=
this
.
class
.
activateTab
;
this
.
subject
=
this
.
class
.
activateTab
;
});
});
...
@@ -148,7 +149,7 @@ import 'vendor/jquery.scrollTo';
...
@@ -148,7 +149,7 @@ import 'vendor/jquery.scrollTo';
describe
(
'
setCurrentAction
'
,
function
()
{
describe
(
'
setCurrentAction
'
,
function
()
{
beforeEach
(
function
()
{
beforeEach
(
function
()
{
spyOn
(
$
,
'
ajax
'
).
and
.
callFake
(
function
()
{}
);
spyOn
(
axios
,
'
get
'
).
and
.
returnValue
(
Promise
.
resolve
({
data
:
{}
})
);
this
.
subject
=
this
.
class
.
setCurrentAction
;
this
.
subject
=
this
.
class
.
setCurrentAction
;
});
});
...
@@ -214,13 +215,21 @@ import 'vendor/jquery.scrollTo';
...
@@ -214,13 +215,21 @@ import 'vendor/jquery.scrollTo';
});
});
describe
(
'
tabShown
'
,
()
=>
{
describe
(
'
tabShown
'
,
()
=>
{
let
mock
;
beforeEach
(
function
()
{
beforeEach
(
function
()
{
spyOn
(
$
,
'
ajax
'
).
and
.
callFake
(
function
(
options
)
{
mock
=
new
MockAdapter
(
axios
);
options
.
success
({
html
:
''
});
mock
.
onGet
(
/
(
.*
)\/
diffs
\.
json/
).
reply
(
200
,
{
data
:
{
html
:
''
},
});
});
loadFixtures
(
'
merge_requests/merge_request_with_task_list.html.raw
'
);
loadFixtures
(
'
merge_requests/merge_request_with_task_list.html.raw
'
);
});
});
afterEach
(()
=>
{
mock
.
restore
();
});
describe
(
'
with "Side-by-side"/parallel diff view
'
,
()
=>
{
describe
(
'
with "Side-by-side"/parallel diff view
'
,
()
=>
{
beforeEach
(
function
()
{
beforeEach
(
function
()
{
this
.
class
.
diffViewType
=
()
=>
'
parallel
'
;
this
.
class
.
diffViewType
=
()
=>
'
parallel
'
;
...
@@ -292,16 +301,20 @@ import 'vendor/jquery.scrollTo';
...
@@ -292,16 +301,20 @@ import 'vendor/jquery.scrollTo';
it
(
'
triggers Ajax request to JSON endpoint
'
,
function
(
done
)
{
it
(
'
triggers Ajax request to JSON endpoint
'
,
function
(
done
)
{
const
url
=
'
/foo/bar/merge_requests/1/diffs
'
;
const
url
=
'
/foo/bar/merge_requests/1/diffs
'
;
spyOn
(
this
.
class
,
'
ajaxGet
'
).
and
.
callFake
((
options
)
=>
{
expect
(
options
.
url
).
toEqual
(
`
${
url
}
.json`
);
spyOn
(
axios
,
'
get
'
).
and
.
callFake
((
reqUrl
)
=>
{
expect
(
reqUrl
).
toBe
(
`
${
url
}
.json`
);
done
();
done
();
return
Promise
.
resolve
({
data
:
{}
});
});
});
this
.
class
.
loadDiff
(
url
);
this
.
class
.
loadDiff
(
url
);
});
});
it
(
'
triggers scroll event when diff already loaded
'
,
function
(
done
)
{
it
(
'
triggers scroll event when diff already loaded
'
,
function
(
done
)
{
spyOn
(
this
.
class
,
'
ajaxGet
'
).
and
.
callFake
(()
=>
done
.
fail
()
);
spyOn
(
axios
,
'
get
'
).
and
.
callFake
(
done
.
fail
);
spyOn
(
document
,
'
dispatchEvent
'
);
spyOn
(
document
,
'
dispatchEvent
'
);
this
.
class
.
diffsLoaded
=
true
;
this
.
class
.
diffsLoaded
=
true
;
...
@@ -316,6 +329,7 @@ import 'vendor/jquery.scrollTo';
...
@@ -316,6 +329,7 @@ import 'vendor/jquery.scrollTo';
describe
(
'
with inline diff
'
,
()
=>
{
describe
(
'
with inline diff
'
,
()
=>
{
let
noteId
;
let
noteId
;
let
noteLineNumId
;
let
noteLineNumId
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
const
diffsResponse
=
getJSONFixture
(
inlineChangesTabJsonFixture
);
const
diffsResponse
=
getJSONFixture
(
inlineChangesTabJsonFixture
);
...
@@ -330,29 +344,40 @@ import 'vendor/jquery.scrollTo';
...
@@ -330,29 +344,40 @@ import 'vendor/jquery.scrollTo';
.
attr
(
'
href
'
)
.
attr
(
'
href
'
)
.
replace
(
'
#
'
,
''
);
.
replace
(
'
#
'
,
''
);
spyOn
(
$
,
'
ajax
'
).
and
.
callFake
(
function
(
options
)
{
mock
=
new
MockAdapter
(
axios
);
options
.
success
(
diffsResponse
);
mock
.
onGet
(
/
(
.*
)\/
diffs
\.
json/
).
reply
(
200
,
diffsResponse
);
});
});
afterEach
(()
=>
{
mock
.
restore
();
});
});
describe
(
'
with note fragment hash
'
,
()
=>
{
describe
(
'
with note fragment hash
'
,
()
=>
{
it
(
'
should expand and scroll to linked fragment hash #note_xxx
'
,
function
()
{
it
(
'
should expand and scroll to linked fragment hash #note_xxx
'
,
function
(
done
)
{
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
noteId
);
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
noteId
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
noteId
.
length
).
toBeGreaterThan
(
0
);
setTimeout
(()
=>
{
expect
(
Notes
.
instance
.
toggleDiffNote
).
toHaveBeenCalledWith
({
expect
(
noteId
.
length
).
toBeGreaterThan
(
0
);
target
:
jasmine
.
any
(
Object
),
expect
(
Notes
.
instance
.
toggleDiffNote
).
toHaveBeenCalledWith
({
lineType
:
'
old
'
,
target
:
jasmine
.
any
(
Object
),
forceShow
:
true
,
lineType
:
'
old
'
,
forceShow
:
true
,
});
done
();
});
});
});
});
it
(
'
should gracefully ignore non-existant fragment hash
'
,
function
()
{
it
(
'
should gracefully ignore non-existant fragment hash
'
,
function
(
done
)
{
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
'
note_something-that-does-not-exist
'
);
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
'
note_something-that-does-not-exist
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
setTimeout
(()
=>
{
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
done
();
});
});
});
});
});
...
@@ -370,6 +395,7 @@ import 'vendor/jquery.scrollTo';
...
@@ -370,6 +395,7 @@ import 'vendor/jquery.scrollTo';
describe
(
'
with parallel diff
'
,
()
=>
{
describe
(
'
with parallel diff
'
,
()
=>
{
let
noteId
;
let
noteId
;
let
noteLineNumId
;
let
noteLineNumId
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
const
diffsResponse
=
getJSONFixture
(
parallelChangesTabJsonFixture
);
const
diffsResponse
=
getJSONFixture
(
parallelChangesTabJsonFixture
);
...
@@ -384,30 +410,40 @@ import 'vendor/jquery.scrollTo';
...
@@ -384,30 +410,40 @@ import 'vendor/jquery.scrollTo';
.
attr
(
'
href
'
)
.
attr
(
'
href
'
)
.
replace
(
'
#
'
,
''
);
.
replace
(
'
#
'
,
''
);
spyOn
(
$
,
'
ajax
'
).
and
.
callFake
(
function
(
options
)
{
mock
=
new
MockAdapter
(
axios
);
options
.
success
(
diffsResponse
);
mock
.
onGet
(
/
(
.*
)\/
diffs
\.
json/
).
reply
(
200
,
diffsResponse
);
});
});
afterEach
(()
=>
{
mock
.
restore
();
});
});
describe
(
'
with note fragment hash
'
,
()
=>
{
describe
(
'
with note fragment hash
'
,
()
=>
{
it
(
'
should expand and scroll to linked fragment hash #note_xxx
'
,
function
()
{
it
(
'
should expand and scroll to linked fragment hash #note_xxx
'
,
function
(
done
)
{
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
noteId
);
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
noteId
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
noteId
.
length
).
toBeGreaterThan
(
0
);
setTimeout
(()
=>
{
expect
(
Notes
.
instance
.
toggleDiffNote
).
toHaveBeenCalledWith
({
expect
(
noteId
.
length
).
toBeGreaterThan
(
0
);
target
:
jasmine
.
any
(
Object
),
expect
(
Notes
.
instance
.
toggleDiffNote
).
toHaveBeenCalledWith
({
lineType
:
'
new
'
,
target
:
jasmine
.
any
(
Object
),
forceShow
:
true
,
lineType
:
'
new
'
,
forceShow
:
true
,
});
done
();
});
});
});
});
it
(
'
should gracefully ignore non-existant fragment hash
'
,
function
()
{
it
(
'
should gracefully ignore non-existant fragment hash
'
,
function
(
done
)
{
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
'
note_something-that-does-not-exist
'
);
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
'
note_something-that-does-not-exist
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
setTimeout
(()
=>
{
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
done
();
});
});
});
});
});
...
...
spec/javascripts/notes_spec.js
View file @
8fa2932d
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
import
_
from
'
underscore
'
;
import
_
from
'
underscore
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
'
autosize
'
;
import
'
autosize
'
;
import
'
~/gl_form
'
;
import
'
~/gl_form
'
;
import
'
~/lib/utils/text_utility
'
;
import
'
~/lib/utils/text_utility
'
;
import
'
~/render_gfm
'
;
import
'
~/render_gfm
'
;
import
Notes
from
'
~/notes
'
;
import
Notes
from
'
~/notes
'
;
import
timeoutPromise
from
'
./helpers/set_timeout_promise_helper
'
;
(
function
()
{
(
function
()
{
window
.
gon
||
(
window
.
gon
=
{});
window
.
gon
||
(
window
.
gon
=
{});
...
@@ -119,6 +122,7 @@ import Notes from '~/notes';
...
@@ -119,6 +122,7 @@ import Notes from '~/notes';
let
noteEntity
;
let
noteEntity
;
let
$form
;
let
$form
;
let
$notesContainer
;
let
$notesContainer
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
this
.
notes
=
new
Notes
(
''
,
[]);
this
.
notes
=
new
Notes
(
''
,
[]);
...
@@ -136,24 +140,32 @@ import Notes from '~/notes';
...
@@ -136,24 +140,32 @@ import Notes from '~/notes';
$form
=
$
(
'
form.js-main-target-form
'
);
$form
=
$
(
'
form.js-main-target-form
'
);
$notesContainer
=
$
(
'
ul.main-notes-list
'
);
$notesContainer
=
$
(
'
ul.main-notes-list
'
);
$form
.
find
(
'
textarea.js-note-text
'
).
val
(
sampleComment
);
$form
.
find
(
'
textarea.js-note-text
'
).
val
(
sampleComment
);
mock
=
new
MockAdapter
(
axios
);
mock
.
onPost
(
/
(
.*
)\/
notes$/
).
reply
(
200
,
noteEntity
);
});
});
it
(
'
updates note and resets edit form
'
,
()
=>
{
afterEach
(()
=>
{
const
deferred
=
$
.
Deferred
();
mock
.
restore
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
});
it
(
'
updates note and resets edit form
'
,
(
done
)
=>
{
spyOn
(
this
.
notes
,
'
revertNoteEditForm
'
);
spyOn
(
this
.
notes
,
'
revertNoteEditForm
'
);
spyOn
(
this
.
notes
,
'
setupNewNote
'
);
spyOn
(
this
.
notes
,
'
setupNewNote
'
);
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
deferred
.
resolve
(
noteEntity
);
const
$targetNote
=
$notesContainer
.
find
(
`#note_
${
noteEntity
.
id
}
`
);
setTimeout
(()
=>
{
const
updatedNote
=
Object
.
assign
({},
noteEntity
);
const
$targetNote
=
$notesContainer
.
find
(
`#note_
${
noteEntity
.
id
}
`
);
updatedNote
.
note
=
'
bar
'
;
const
updatedNote
=
Object
.
assign
({},
noteEntity
);
this
.
notes
.
updateNote
(
updatedNote
,
$targetNote
);
updatedNote
.
note
=
'
bar
'
;
this
.
notes
.
updateNote
(
updatedNote
,
$targetNote
);
expect
(
this
.
notes
.
revertNoteEditForm
).
toHaveBeenCalledWith
(
$targetNote
);
expect
(
this
.
notes
.
setupNewNote
).
toHaveBeenCalled
();
expect
(
this
.
notes
.
revertNoteEditForm
).
toHaveBeenCalledWith
(
$targetNote
);
done
(
);
expect
(
this
.
notes
.
setupNewNote
).
toHaveBeenCalled
(
);
}
);
});
});
});
});
...
@@ -479,8 +491,19 @@ import Notes from '~/notes';
...
@@ -479,8 +491,19 @@ import Notes from '~/notes';
};
};
let
$form
;
let
$form
;
let
$notesContainer
;
let
$notesContainer
;
let
mock
;
function
mockNotesPost
()
{
mock
.
onPost
(
/
(
.*
)\/
notes$/
).
reply
(
200
,
note
);
}
function
mockNotesPostError
()
{
mock
.
onPost
(
/
(
.*
)\/
notes$/
).
networkError
();
}
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
this
.
notes
=
new
Notes
(
''
,
[]);
this
.
notes
=
new
Notes
(
''
,
[]);
window
.
gon
.
current_username
=
'
root
'
;
window
.
gon
.
current_username
=
'
root
'
;
window
.
gon
.
current_user_fullname
=
'
Administrator
'
;
window
.
gon
.
current_user_fullname
=
'
Administrator
'
;
...
@@ -489,63 +512,92 @@ import Notes from '~/notes';
...
@@ -489,63 +512,92 @@ import Notes from '~/notes';
$form
.
find
(
'
textarea.js-note-text
'
).
val
(
sampleComment
);
$form
.
find
(
'
textarea.js-note-text
'
).
val
(
sampleComment
);
});
});
afterEach
(()
=>
{
mock
.
restore
();
});
it
(
'
should show placeholder note while new comment is being posted
'
,
()
=>
{
it
(
'
should show placeholder note while new comment is being posted
'
,
()
=>
{
mockNotesPost
();
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
expect
(
$notesContainer
.
find
(
'
.note.being-posted
'
).
length
>
0
).
toEqual
(
true
);
expect
(
$notesContainer
.
find
(
'
.note.being-posted
'
).
length
>
0
).
toEqual
(
true
);
});
});
it
(
'
should remove placeholder note when new comment is done posting
'
,
()
=>
{
it
(
'
should remove placeholder note when new comment is done posting
'
,
(
done
)
=>
{
const
deferred
=
$
.
Deferred
();
mockNotesPost
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
deferred
.
resolve
(
note
);
setTimeout
(()
=>
{
expect
(
$notesContainer
.
find
(
'
.note.being-posted
'
).
length
).
toEqual
(
0
);
expect
(
$notesContainer
.
find
(
'
.note.being-posted
'
).
length
).
toEqual
(
0
);
done
();
});
});
});
it
(
'
should show actual note element when new comment is done posting
'
,
()
=>
{
it
(
'
should show actual note element when new comment is done posting
'
,
(
done
)
=>
{
const
deferred
=
$
.
Deferred
();
mockNotesPost
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
deferred
.
resolve
(
note
);
setTimeout
(()
=>
{
expect
(
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
).
length
>
0
).
toEqual
(
true
);
expect
(
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
).
length
>
0
).
toEqual
(
true
);
done
();
});
});
});
it
(
'
should reset Form when new comment is done posting
'
,
()
=>
{
it
(
'
should reset Form when new comment is done posting
'
,
(
done
)
=>
{
const
deferred
=
$
.
Deferred
();
mockNotesPost
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
deferred
.
resolve
(
note
);
setTimeout
(()
=>
{
expect
(
$form
.
find
(
'
textarea.js-note-text
'
).
val
()).
toEqual
(
''
);
expect
(
$form
.
find
(
'
textarea.js-note-text
'
).
val
()).
toEqual
(
''
);
done
();
});
});
});
it
(
'
should show flash error message when new comment failed to be posted
'
,
()
=>
{
it
(
'
should show flash error message when new comment failed to be posted
'
,
(
done
)
=>
{
const
deferred
=
$
.
Deferred
();
mockNotesPostError
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
deferred
.
reject
();
setTimeout
(()
=>
{
expect
(
$notesContainer
.
parent
().
find
(
'
.flash-container .flash-text
'
).
is
(
'
:visible
'
)).
toEqual
(
true
);
expect
(
$notesContainer
.
parent
().
find
(
'
.flash-container .flash-text
'
).
is
(
'
:visible
'
)).
toEqual
(
true
);
done
();
});
});
});
it
(
'
should show flash error message when comment failed to be updated
'
,
()
=>
{
it
(
'
should show flash error message when comment failed to be updated
'
,
(
done
)
=>
{
const
deferred
=
$
.
Deferred
();
mockNotesPost
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
deferred
.
resolve
(
note
);
timeoutPromise
()
const
$noteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
);
.
then
(()
=>
{
$noteEl
.
find
(
'
.js-note-edit
'
).
click
(
);
const
$noteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
);
$noteEl
.
find
(
'
textarea.js-note-text
'
).
val
(
updatedComment
);
$noteEl
.
find
(
'
.js-note-edit
'
).
click
(
);
$noteEl
.
find
(
'
.js-comment-save-button
'
).
click
(
);
$noteEl
.
find
(
'
textarea.js-note-text
'
).
val
(
updatedComment
);
deferred
.
reject
();
mock
.
restore
();
const
$updatedNoteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
);
expect
(
$updatedNoteEl
.
hasClass
(
'
.being-posted
'
)).
toEqual
(
false
);
// Remove being-posted visuals
mockNotesPostError
();
expect
(
$updatedNoteEl
.
find
(
'
.note-text
'
).
text
().
trim
()).
toEqual
(
sampleComment
);
// See if comment reverted back to original
expect
(
$
(
'
.flash-container
'
).
is
(
'
:visible
'
)).
toEqual
(
true
);
// Flash error message shown
$noteEl
.
find
(
'
.js-comment-save-button
'
).
click
();
})
.
then
(
timeoutPromise
)
.
then
(()
=>
{
const
$updatedNoteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
);
expect
(
$updatedNoteEl
.
hasClass
(
'
.being-posted
'
)).
toEqual
(
false
);
// Remove being-posted visuals
expect
(
$updatedNoteEl
.
find
(
'
.note-text
'
).
text
().
trim
()).
toEqual
(
sampleComment
);
// See if comment reverted back to original
expect
(
$
(
'
.flash-container
'
).
is
(
'
:visible
'
)).
toEqual
(
true
);
// Flash error message shown
done
();
})
.
catch
(
done
.
fail
);
});
});
});
});
...
@@ -563,8 +615,12 @@ import Notes from '~/notes';
...
@@ -563,8 +615,12 @@ import Notes from '~/notes';
};
};
let
$form
;
let
$form
;
let
$notesContainer
;
let
$notesContainer
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
mock
.
onPost
(
/
(
.*
)\/
notes$/
).
reply
(
200
,
note
);
this
.
notes
=
new
Notes
(
''
,
[]);
this
.
notes
=
new
Notes
(
''
,
[]);
window
.
gon
.
current_username
=
'
root
'
;
window
.
gon
.
current_username
=
'
root
'
;
window
.
gon
.
current_user_fullname
=
'
Administrator
'
;
window
.
gon
.
current_user_fullname
=
'
Administrator
'
;
...
@@ -582,15 +638,20 @@ import Notes from '~/notes';
...
@@ -582,15 +638,20 @@ import Notes from '~/notes';
$form
.
find
(
'
textarea.js-note-text
'
).
val
(
sampleComment
);
$form
.
find
(
'
textarea.js-note-text
'
).
val
(
sampleComment
);
});
});
it
(
'
should remove slash command placeholder when comment with slash commands is done posting
'
,
()
=>
{
afterEach
(()
=>
{
const
deferred
=
$
.
Deferred
();
mock
.
restore
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
});
it
(
'
should remove slash command placeholder when comment with slash commands is done posting
'
,
(
done
)
=>
{
spyOn
(
gl
.
awardsHandler
,
'
addAwardToEmojiBar
'
).
and
.
callThrough
();
spyOn
(
gl
.
awardsHandler
,
'
addAwardToEmojiBar
'
).
and
.
callThrough
();
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
expect
(
$notesContainer
.
find
(
'
.system-note.being-posted
'
).
length
).
toEqual
(
1
);
// Placeholder shown
expect
(
$notesContainer
.
find
(
'
.system-note.being-posted
'
).
length
).
toEqual
(
1
);
// Placeholder shown
deferred
.
resolve
(
note
);
expect
(
$notesContainer
.
find
(
'
.system-note.being-posted
'
).
length
).
toEqual
(
0
);
// Placeholder removed
setTimeout
(()
=>
{
expect
(
$notesContainer
.
find
(
'
.system-note.being-posted
'
).
length
).
toEqual
(
0
);
// Placeholder removed
done
();
});
});
});
});
});
...
@@ -607,8 +668,12 @@ import Notes from '~/notes';
...
@@ -607,8 +668,12 @@ import Notes from '~/notes';
};
};
let
$form
;
let
$form
;
let
$notesContainer
;
let
$notesContainer
;
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
mock
.
onPost
(
/
(
.*
)\/
notes$/
).
reply
(
200
,
note
);
this
.
notes
=
new
Notes
(
''
,
[]);
this
.
notes
=
new
Notes
(
''
,
[]);
window
.
gon
.
current_username
=
'
root
'
;
window
.
gon
.
current_username
=
'
root
'
;
window
.
gon
.
current_user_fullname
=
'
Administrator
'
;
window
.
gon
.
current_user_fullname
=
'
Administrator
'
;
...
@@ -617,19 +682,24 @@ import Notes from '~/notes';
...
@@ -617,19 +682,24 @@ import Notes from '~/notes';
$form
.
find
(
'
textarea.js-note-text
'
).
html
(
sampleComment
);
$form
.
find
(
'
textarea.js-note-text
'
).
html
(
sampleComment
);
});
});
it
(
'
should not render a script tag
'
,
()
=>
{
afterEach
(()
=>
{
const
deferred
=
$
.
Deferred
();
mock
.
restore
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
});
it
(
'
should not render a script tag
'
,
(
done
)
=>
{
$
(
'
.js-comment-button
'
).
click
();
$
(
'
.js-comment-button
'
).
click
();
deferred
.
resolve
(
note
);
setTimeout
(()
=>
{
const
$noteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
);
const
$noteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
);
$noteEl
.
find
(
'
.js-note-edit
'
).
click
();
$noteEl
.
find
(
'
.js-note-edit
'
).
click
();
$noteEl
.
find
(
'
textarea.js-note-text
'
).
html
(
updatedComment
);
$noteEl
.
find
(
'
textarea.js-note-text
'
).
html
(
updatedComment
);
$noteEl
.
find
(
'
.js-comment-save-button
'
).
click
();
$noteEl
.
find
(
'
.js-comment-save-button
'
).
click
();
const
$updatedNoteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
).
find
(
'
.js-task-list-container
'
);
expect
(
$updatedNoteEl
.
find
(
'
.note-text
'
).
text
().
trim
()).
toEqual
(
''
);
const
$updatedNoteEl
=
$notesContainer
.
find
(
`#note_
${
note
.
id
}
`
).
find
(
'
.js-task-list-container
'
);
done
(
);
expect
(
$updatedNoteEl
.
find
(
'
.note-text
'
).
text
().
trim
()).
toEqual
(
''
);
}
);
});
});
});
});
...
...
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