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
0
Merge Requests
0
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
Léo-Paul Géneau
gitlab-ce
Commits
e69732e2
Commit
e69732e2
authored
May 04, 2017
by
Filipa Lacerda
Committed by
Phil Hughes
May 04, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pipeline table mini graph dropdown remains open when table is refreshed
parent
dcdced81
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
309 additions
and
99 deletions
+309
-99
app/assets/javascripts/commit/pipelines/pipelines_table.js
app/assets/javascripts/commit/pipelines/pipelines_table.js
+10
-1
app/assets/javascripts/pipelines/components/stage.vue
app/assets/javascripts/pipelines/components/stage.vue
+173
-0
app/assets/javascripts/pipelines/pipelines.js
app/assets/javascripts/pipelines/pipelines.js
+10
-1
app/assets/javascripts/vue_shared/components/pipelines_table.js
...sets/javascripts/vue_shared/components/pipelines_table.js
+9
-2
app/assets/javascripts/vue_shared/components/pipelines_table_row.js
.../javascripts/vue_shared/components/pipelines_table_row.js
+11
-2
app/assets/stylesheets/pages/pipelines.scss
app/assets/stylesheets/pages/pipelines.scss
+22
-28
app/views/shared/_mini_pipeline_graph.html.haml
app/views/shared/_mini_pipeline_graph.html.haml
+4
-4
changelogs/unreleased/31558-job-dropdown.yml
changelogs/unreleased/31558-job-dropdown.yml
+4
-0
spec/javascripts/fixtures/mini_dropdown_graph.html.haml
spec/javascripts/fixtures/mini_dropdown_graph.html.haml
+3
-3
spec/javascripts/pipelines/stage_spec.js
spec/javascripts/pipelines/stage_spec.js
+63
-58
No files found.
app/assets/javascripts/commit/pipelines/pipelines_table.js
View file @
e69732e2
...
@@ -46,6 +46,7 @@ export default Vue.component('pipelines-table', {
...
@@ -46,6 +46,7 @@ export default Vue.component('pipelines-table', {
isLoading
:
false
,
isLoading
:
false
,
hasError
:
false
,
hasError
:
false
,
isMakingRequest
:
false
,
isMakingRequest
:
false
,
updateGraphDropdown
:
false
,
};
};
},
},
...
@@ -130,15 +131,21 @@ export default Vue.component('pipelines-table', {
...
@@ -130,15 +131,21 @@ export default Vue.component('pipelines-table', {
const
pipelines
=
response
.
pipelines
||
response
;
const
pipelines
=
response
.
pipelines
||
response
;
this
.
store
.
storePipelines
(
pipelines
);
this
.
store
.
storePipelines
(
pipelines
);
this
.
isLoading
=
false
;
this
.
isLoading
=
false
;
this
.
updateGraphDropdown
=
true
;
},
},
errorCallback
()
{
errorCallback
()
{
this
.
hasError
=
true
;
this
.
hasError
=
true
;
this
.
isLoading
=
false
;
this
.
isLoading
=
false
;
this
.
updateGraphDropdown
=
false
;
},
},
setIsMakingRequest
(
isMakingRequest
)
{
setIsMakingRequest
(
isMakingRequest
)
{
this
.
isMakingRequest
=
isMakingRequest
;
this
.
isMakingRequest
=
isMakingRequest
;
if
(
isMakingRequest
)
{
this
.
updateGraphDropdown
=
false
;
}
},
},
},
},
...
@@ -163,7 +170,9 @@ export default Vue.component('pipelines-table', {
...
@@ -163,7 +170,9 @@ export default Vue.component('pipelines-table', {
v-if="shouldRenderTable">
v-if="shouldRenderTable">
<pipelines-table-component
<pipelines-table-component
:pipelines="state.pipelines"
:pipelines="state.pipelines"
:service="service" />
:service="service"
:update-graph-dropdown="updateGraphDropdown"
/>
</div>
</div>
</div>
</div>
`
,
`
,
...
...
app/assets/javascripts/pipelines/components/stage.
js
→
app/assets/javascripts/pipelines/components/stage.
vue
View file @
e69732e2
<
script
>
/**
* Renders each stage of the pipeline mini graph.
*
* Given the provided endpoint will make a request to
* fetch the dropdown data when the stage is clicked.
*
* Request is made inside this component to make it reusable between:
* 1. Pipelines main table
* 2. Pipelines table in commit and Merge request views
* 3. Merge request widget
* 4. Commit widget
*/
/* global Flash */
/* global Flash */
import
StatusIconEntityMap
from
'
../../ci_status_icons
'
;
import
StatusIconEntityMap
from
'
../../ci_status_icons
'
;
...
@@ -7,36 +22,55 @@ export default {
...
@@ -7,36 +22,55 @@ export default {
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
updateDropdown
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
},
data
()
{
data
()
{
return
{
return
{
builds
:
''
,
isLoading
:
false
,
spinner
:
'
<span class="fa fa-spinner fa-spin"></span>
'
,
dropdownContent
:
''
,
endpoint
:
this
.
stage
.
dropdown_path
,
};
};
},
},
updated
()
{
updated
()
{
if
(
this
.
builds
)
{
if
(
this
.
dropdownContent
.
length
>
0
)
{
this
.
stopDropdownClickPropagation
();
this
.
stopDropdownClickPropagation
();
}
}
},
},
methods
:
{
watch
:
{
fetchBuilds
(
e
)
{
updateDropdown
()
{
const
ariaExpanded
=
e
.
currentTarget
.
attributes
[
'
aria-expanded
'
];
if
(
this
.
updateDropdown
&&
this
.
isDropdownOpen
()
&&
!
this
.
isLoading
)
{
this
.
fetchJobs
();
}
},
},
if
(
ariaExpanded
&&
(
ariaExpanded
.
textContent
===
'
true
'
))
return
null
;
methods
:
{
onClickStage
()
{
if
(
!
this
.
isDropdownOpen
())
{
this
.
isLoading
=
true
;
this
.
fetchJobs
();
}
},
return
this
.
$http
.
get
(
this
.
stage
.
dropdown_path
)
fetchJobs
()
{
this
.
$http
.
get
(
this
.
endpoint
)
.
then
((
response
)
=>
{
.
then
((
response
)
=>
{
this
.
builds
=
JSON
.
parse
(
response
.
body
).
html
;
this
.
dropdownContent
=
response
.
json
().
html
;
this
.
isLoading
=
false
;
})
})
.
catch
(()
=>
{
.
catch
(()
=>
{
// If dropdown is opened we'll close it.
this
.
closeDropdown
();
if
(
this
.
$el
.
classList
.
contains
(
'
open
'
))
{
this
.
isLoading
=
false
;
$
(
this
.
$refs
.
dropdown
).
dropdown
(
'
toggle
'
);
}
const
flash
=
new
Flash
(
'
Something went wrong on our end.
'
);
const
flash
=
new
Flash
(
'
Something went wrong on our end.
'
);
return
flash
;
return
flash
;
...
@@ -57,59 +91,83 @@ export default {
...
@@ -57,59 +91,83 @@ export default {
e
.
stopPropagation
();
e
.
stopPropagation
();
});
});
},
},
closeDropdown
()
{
if
(
this
.
isDropdownOpen
())
{
$
(
this
.
$refs
.
dropdown
).
dropdown
(
'
toggle
'
);
}
},
},
computed
:
{
buildsOrSpinner
()
{
isDropdownOpen
()
{
return
this
.
builds
?
this
.
builds
:
this
.
spinner
;
return
this
.
$el
.
classList
.
contains
(
'
open
'
);
},
dropdownClass
()
{
if
(
this
.
builds
)
return
'
js-builds-dropdown-container
'
;
return
'
js-builds-dropdown-loading builds-dropdown-loading
'
;
},
},
buildStatus
()
{
return
`Build:
${
this
.
stage
.
status
.
label
}
`
;
},
},
tooltip
()
{
return
`has-tooltip ci-status-icon ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
computed
:
{
dropdownClass
()
{
return
this
.
dropdownContent
.
length
>
0
?
'
js-builds-dropdown-container
'
:
'
js-builds-dropdown-loading
'
;
},
},
triggerButtonClass
()
{
triggerButtonClass
()
{
return
`
mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button
ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
return
`ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
},
},
svgHTML
()
{
svgIcon
()
{
return
StatusIconEntityMap
[
this
.
stage
.
status
.
icon
];
return
StatusIconEntityMap
[
this
.
stage
.
status
.
icon
];
},
},
},
},
template
:
`
};
<div>
</
script
>
<
template
>
<div
class=
"dropdown"
>
<button
<button
@click="fetchBuilds($event)"
:class=
"triggerButtonClass"
:class=
"triggerButtonClass"
@
click=
"onClickStage"
class=
"mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button"
:title=
"stage.title"
:title=
"stage.title"
data-placement=
"top"
data-placement=
"top"
data-toggle=
"dropdown"
data-toggle=
"dropdown"
type=
"button"
type=
"button"
:aria-label="stage.title"
id=
"stageDropdown"
ref="dropdown">
aria-haspopup=
"true"
aria-expanded=
"false"
>
<span
<span
v-html="svgHTML"
v-html=
"svgIcon"
aria-hidden="true">
aria-hidden=
"true"
:aria-label=
"stage.title"
>
</span>
</span>
<i
<i
class=
"fa fa-caret-down"
class=
"fa fa-caret-down"
aria-hidden="true" />
aria-hidden=
"true"
>
</i>
</button>
</button>
<ul
<ul
ref="dropdown-content"
class=
"dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container"
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
aria-labelledby=
"stageDropdown"
>
<div
class="arrow-up"
<li
aria-hidden="true"></div>
<div
:class=
"dropdownClass"
:class=
"dropdownClass"
class="js-builds-dropdown-list scrollable-menu"
class=
"js-builds-dropdown-list scrollable-menu"
>
v-html="buildsOrSpinner">
<div
class=
"text-center"
v-if=
"isLoading"
>
<i
class=
"fa fa-spin fa-spinner"
aria-hidden=
"true"
aria-label=
"Loading"
>
</i>
</div>
</div>
<ul
v-else
v-html=
"dropdownContent"
>
</ul>
</li>
</ul>
</ul>
</div>
</div>
`
,
</script>
};
app/assets/javascripts/pipelines/pipelines.js
View file @
e69732e2
...
@@ -49,6 +49,7 @@ export default {
...
@@ -49,6 +49,7 @@ export default {
isLoading
:
false
,
isLoading
:
false
,
hasError
:
false
,
hasError
:
false
,
isMakingRequest
:
false
,
isMakingRequest
:
false
,
updateGraphDropdown
:
false
,
};
};
},
},
...
@@ -198,15 +199,21 @@ export default {
...
@@ -198,15 +199,21 @@ export default {
this
.
store
.
storePagination
(
response
.
headers
);
this
.
store
.
storePagination
(
response
.
headers
);
this
.
isLoading
=
false
;
this
.
isLoading
=
false
;
this
.
updateGraphDropdown
=
true
;
},
},
errorCallback
()
{
errorCallback
()
{
this
.
hasError
=
true
;
this
.
hasError
=
true
;
this
.
isLoading
=
false
;
this
.
isLoading
=
false
;
this
.
updateGraphDropdown
=
false
;
},
},
setIsMakingRequest
(
isMakingRequest
)
{
setIsMakingRequest
(
isMakingRequest
)
{
this
.
isMakingRequest
=
isMakingRequest
;
this
.
isMakingRequest
=
isMakingRequest
;
if
(
isMakingRequest
)
{
this
.
updateGraphDropdown
=
false
;
}
},
},
},
},
...
@@ -263,7 +270,9 @@ export default {
...
@@ -263,7 +270,9 @@ export default {
<pipelines-table-component
<pipelines-table-component
:pipelines="state.pipelines"
:pipelines="state.pipelines"
:service="service"/>
:service="service"
:update-graph-dropdown="updateGraphDropdown"
/>
</div>
</div>
<gl-pagination
<gl-pagination
...
...
app/assets/javascripts/vue_shared/components/pipelines_table.js
View file @
e69732e2
...
@@ -10,13 +10,18 @@ export default {
...
@@ -10,13 +10,18 @@ export default {
pipelines
:
{
pipelines
:
{
type
:
Array
,
type
:
Array
,
required
:
true
,
required
:
true
,
default
:
()
=>
([]),
},
},
service
:
{
service
:
{
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
updateGraphDropdown
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
},
components
:
{
components
:
{
...
@@ -40,7 +45,9 @@ export default {
...
@@ -40,7 +45,9 @@ export default {
v-bind:model="model">
v-bind:model="model">
<tr is="pipelines-table-row-component"
<tr is="pipelines-table-row-component"
:pipeline="model"
:pipeline="model"
:service="service"></tr>
:service="service"
:update-graph-dropdown="updateGraphDropdown"
/>
</template>
</template>
</tbody>
</tbody>
</table>
</table>
...
...
app/assets/javascripts/vue_shared/components/pipelines_table_row.js
View file @
e69732e2
...
@@ -3,7 +3,7 @@ import AsyncButtonComponent from '../../pipelines/components/async_button.vue';
...
@@ -3,7 +3,7 @@ import AsyncButtonComponent from '../../pipelines/components/async_button.vue';
import
PipelinesActionsComponent
from
'
../../pipelines/components/pipelines_actions
'
;
import
PipelinesActionsComponent
from
'
../../pipelines/components/pipelines_actions
'
;
import
PipelinesArtifactsComponent
from
'
../../pipelines/components/pipelines_artifacts
'
;
import
PipelinesArtifactsComponent
from
'
../../pipelines/components/pipelines_artifacts
'
;
import
PipelinesStatusComponent
from
'
../../pipelines/components/status
'
;
import
PipelinesStatusComponent
from
'
../../pipelines/components/status
'
;
import
PipelinesStageComponent
from
'
../../pipelines/components/stage
'
;
import
PipelinesStageComponent
from
'
../../pipelines/components/stage
.vue
'
;
import
PipelinesUrlComponent
from
'
../../pipelines/components/pipeline_url
'
;
import
PipelinesUrlComponent
from
'
../../pipelines/components/pipeline_url
'
;
import
PipelinesTimeagoComponent
from
'
../../pipelines/components/time_ago
'
;
import
PipelinesTimeagoComponent
from
'
../../pipelines/components/time_ago
'
;
import
CommitComponent
from
'
./commit
'
;
import
CommitComponent
from
'
./commit
'
;
...
@@ -24,6 +24,12 @@ export default {
...
@@ -24,6 +24,12 @@ export default {
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
updateGraphDropdown
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
},
components
:
{
components
:
{
...
@@ -213,7 +219,10 @@ export default {
...
@@ -213,7 +219,10 @@ export default {
<div class="stage-container dropdown js-mini-pipeline-graph"
<div class="stage-container dropdown js-mini-pipeline-graph"
v-if="pipeline.details.stages.length > 0"
v-if="pipeline.details.stages.length > 0"
v-for="stage in pipeline.details.stages">
v-for="stage in pipeline.details.stages">
<dropdown-stage :stage="stage"/>
<dropdown-stage
:stage="stage"
:update-dropdown="updateGraphDropdown"/>
</div>
</div>
</td>
</td>
...
...
app/assets/stylesheets/pages/pipelines.scss
View file @
e69732e2
...
@@ -781,16 +781,11 @@
...
@@ -781,16 +781,11 @@
}
}
.scrollable-menu
{
.scrollable-menu
{
padding
:
0
;
max-height
:
245px
;
max-height
:
245px
;
overflow
:
auto
;
overflow
:
auto
;
}
}
// Loading icon
.builds-dropdown-loading
{
margin
:
0
auto
;
width
:
20px
;
}
// Action icon on the right
// Action icon on the right
a
.ci-action-icon-wrapper
{
a
.ci-action-icon-wrapper
{
color
:
$action-icon-color
;
color
:
$action-icon-color
;
...
@@ -893,7 +888,7 @@
...
@@ -893,7 +888,7 @@
* Top arrow in the dropdown in the mini pipeline graph
* Top arrow in the dropdown in the mini pipeline graph
*/
*/
.mini-pipeline-graph-dropdown-menu
{
.mini-pipeline-graph-dropdown-menu
{
.arrow-up
{
&
:
:
before
,
&
:
:
before
,
&::
after
{
&::
after
{
content
:
''
;
content
:
''
;
...
@@ -917,7 +912,6 @@
...
@@ -917,7 +912,6 @@
margin-top
:
1px
;
margin-top
:
1px
;
border-bottom-color
:
$white-light
;
border-bottom-color
:
$white-light
;
}
}
}
}
}
/**
/**
...
...
app/views/shared/_mini_pipeline_graph.html.haml
View file @
e69732e2
...
@@ -11,8 +11,8 @@
...
@@ -11,8 +11,8 @@
=
icon
(
'caret-down'
)
=
icon
(
'caret-down'
)
%ul
.dropdown-menu.mini-pipeline-graph-dropdown-menu.js-builds-dropdown-container
%ul
.dropdown-menu.mini-pipeline-graph-dropdown-menu.js-builds-dropdown-container
.arrow-up
%li
.js-builds-dropdown-list.scrollable-menu
.js-builds-dropdown-list.scrollable-menu
.js-builds-dropdown-loading.builds-dropdown-loading.hidden
%li
.js-builds-dropdown-loading.hidden
%span
.fa.fa-spinner.fa-spin
.text-center
%i
.fa.fa-spinner.fa-spin
{
'aria-hidden'
:
'true'
,
'aria-label'
:
'Loading'
}
changelogs/unreleased/31558-job-dropdown.yml
0 → 100644
View file @
e69732e2
---
title
:
Job dropdown of pipeline mini graph updates in realtime when its opened
merge_request
:
author
:
spec/javascripts/fixtures/mini_dropdown_graph.html.haml
View file @
e69732e2
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
Dropdown
Dropdown
%ul
.dropdown-menu.mini-pipeline-graph-dropdown-menu.js-builds-dropdown-container
%ul
.dropdown-menu.mini-pipeline-graph-dropdown-menu.js-builds-dropdown-container
.js-builds-dropdown-list.scrollable-menu
%li
.js-builds-dropdown-list.scrollable-menu
.js-builds-dropdown-loading.
builds-dropdown-loading.hidden
%li
.js-
builds-dropdown-loading.hidden
%span
.fa.fa-spinner
.fa-spin
%span
.fa.fa-spinner
spec/javascripts/pipelines/stage_spec.js
View file @
e69732e2
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
{
SUCCESS_SVG
}
from
'
~/ci_status_icons
'
;
import
stage
from
'
~/pipelines/components/stage.vue
'
;
import
Stage
from
'
~/pipelines/components/stage
'
;
function
minify
(
string
)
{
describe
(
'
Pipelines stage component
'
,
()
=>
{
return
string
.
replace
(
/
\s
/g
,
''
);
let
StageComponent
;
}
let
component
;
describe
(
'
Pipelines Stage
'
,
()
=>
{
describe
(
'
data
'
,
()
=>
{
let
stageReturnValue
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
stageReturnValue
=
Stage
.
data
();
StageComponent
=
Vue
.
extend
(
stage
);
});
it
(
'
should return object with .builds and .spinner
'
,
()
=>
{
component
=
new
StageComponent
({
expect
(
stageReturnValue
).
toEqual
({
propsData
:
{
builds
:
''
,
stage
:
{
spinner
:
'
<span class="fa fa-spinner fa-spin"></span>
'
,
status
:
{
});
group
:
'
success
'
,
icon
:
'
icon_status_success
'
,
title
:
'
success
'
,
},
dropdown_path
:
'
foo
'
,
},
updateDropdown
:
false
,
},
}).
$mount
();
});
});
it
(
'
should render a dropdown with the status icon
'
,
()
=>
{
expect
(
component
.
$el
.
getAttribute
(
'
class
'
)).
toEqual
(
'
dropdown
'
);
expect
(
component
.
$el
.
querySelector
(
'
svg
'
)).
toBeDefined
();
expect
(
component
.
$el
.
querySelector
(
'
button
'
).
getAttribute
(
'
data-toggle
'
)).
toEqual
(
'
dropdown
'
);
});
});
describe
(
'
computed
'
,
()
=>
{
describe
(
'
with successfull request
'
,
()
=>
{
describe
(
'
svgHTML
'
,
function
()
{
const
interceptor
=
(
request
,
next
)
=>
{
let
stage
;
next
(
request
.
respondWith
(
JSON
.
stringify
({
html
:
'
foo
'
}),
{
let
svgHTML
;
status
:
200
,
}));
};
beforeEach
(()
=>
{
beforeEach
(()
=>
{
stage
=
{
stage
:
{
status
:
{
icon
:
'
icon_status_success
'
}
}
};
Vue
.
http
.
interceptors
.
push
(
interceptor
);
svgHTML
=
Stage
.
computed
.
svgHTML
.
call
(
stage
);
});
});
it
(
"
should return the correct icon for the stage's status
"
,
()
=>
{
afterEach
(()
=>
{
expect
(
svgHTML
).
toBe
(
SUCCESS_SVG
);
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
interceptor
,
);
});
});
it
(
'
should render the received data
'
,
(
done
)
=>
{
component
.
$el
.
querySelector
(
'
button
'
).
click
();
setTimeout
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-builds-dropdown-container ul
'
).
textContent
.
trim
(),
).
toEqual
(
'
foo
'
);
done
();
},
0
);
});
});
});
});
describe
(
'
when mounted
'
,
()
=>
{
describe
(
'
when request fails
'
,
()
=>
{
let
StageComponent
;
const
interceptor
=
(
request
,
next
)
=>
{
let
renderedComponent
;
next
(
request
.
respondWith
(
JSON
.
stringify
({}),
{
let
stage
;
status
:
500
,
}));
};
beforeEach
(()
=>
{
beforeEach
(()
=>
{
stage
=
{
status
:
{
icon
:
'
icon_status_success
'
}
};
Vue
.
http
.
interceptors
.
push
(
interceptor
);
StageComponent
=
Vue
.
extend
(
Stage
);
renderedComponent
=
new
StageComponent
({
propsData
:
{
stage
,
},
}).
$mount
();
});
});
it
(
'
should render the correct status svg
'
,
()
=>
{
afterEach
(()
=>
{
const
minifiedComponent
=
minify
(
renderedComponent
.
$el
.
outerHTML
);
Vue
.
http
.
interceptors
=
_
.
without
(
const
expectedSVG
=
minify
(
SUCCESS_SVG
);
Vue
.
http
.
interceptors
,
interceptor
,
);
expect
(
minifiedComponent
).
toContain
(
expectedSVG
);
});
});
});
describe
(
'
when request fails
'
,
()
=>
{
it
(
'
should close the dropdown
'
,
()
=>
{
it
(
'
closes dropdown
'
,
()
=>
{
component
.
$el
.
click
();
spyOn
(
$
,
'
ajax
'
).
and
.
callFake
(
options
=>
options
.
error
());
const
StageComponent
=
Vue
.
extend
(
Stage
);
const
component
=
new
StageComponent
({
propsData
:
{
stage
:
{
status
:
{
icon
:
'
foo
'
}
}
},
}).
$mount
();
expect
(
setTimeout
(()
=>
{
component
.
$el
.
classList
.
contains
(
'
open
'
),
expect
(
component
.
$el
.
classList
.
contains
(
'
open
'
)).
toEqual
(
false
);
).
toEqual
(
false
);
},
0
);
});
});
});
});
});
});
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