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
c8431dcb
Commit
c8431dcb
authored
Apr 21, 2021
by
Sarah Groff Hennigh-Palermo
Committed by
Andrew Fontaine
Apr 21, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pipeline Graph: Update graph state selection
parent
a63b410d
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
333 additions
and
162 deletions
+333
-162
app/assets/javascripts/pipelines/components/graph/graph_component.vue
...avascripts/pipelines/components/graph/graph_component.vue
+9
-4
app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue
...ts/pipelines/components/graph/graph_component_wrapper.vue
+7
-0
app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue
...cripts/pipelines/components/graph/graph_view_selector.vue
+95
-40
app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
...ts/pipelines/components/graph/linked_pipelines_column.vue
+5
-0
app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue
...scripts/pipelines/components/graph_shared/links_layer.vue
+4
-44
locale/gitlab.pot
locale/gitlab.pot
+9
-12
spec/frontend/pipelines/graph/graph_component_spec.js
spec/frontend/pipelines/graph/graph_component_spec.js
+1
-0
spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
.../frontend/pipelines/graph/graph_component_wrapper_spec.js
+52
-4
spec/frontend/pipelines/graph/graph_view_selector_spec.js
spec/frontend/pipelines/graph/graph_view_selector_spec.js
+124
-0
spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
.../frontend/pipelines/graph/linked_pipelines_column_spec.js
+1
-0
spec/frontend/pipelines/graph_shared/links_layer_spec.js
spec/frontend/pipelines/graph_shared/links_layer_spec.js
+26
-58
No files found.
app/assets/javascripts/pipelines/components/graph/graph_component.vue
View file @
c8431dcb
...
...
@@ -25,6 +25,10 @@ export default {
type
:
Object
,
required
:
true
,
},
showLinks
:
{
type
:
Boolean
,
required
:
true
,
},
viewType
:
{
type
:
String
,
required
:
true
,
...
...
@@ -91,8 +95,8 @@ export default {
collectMetrics
:
true
,
};
},
sho
uldHide
Links
()
{
return
this
.
isStageView
;
sho
wJob
Links
()
{
return
!
this
.
isStageView
&&
this
.
showLinks
;
},
shouldShowStageName
()
{
return
!
this
.
isStageView
;
...
...
@@ -188,6 +192,7 @@ export default {
:config-paths=
"configPaths"
:linked-pipelines=
"upstreamPipelines"
:column-title=
"__('Upstream')"
:show-links=
"showJobLinks"
:type=
"$options.pipelineTypeConstants.UPSTREAM"
:view-type=
"viewType"
@
error=
"onError"
...
...
@@ -202,9 +207,8 @@ export default {
:container-measurements=
"measurements"
:highlighted-job=
"hoveredJobName"
:metrics-config=
"metricsConfig"
:
never-show-links=
"shouldHide
Links"
:
show-links=
"showJob
Links"
:view-type=
"viewType"
default-link-color=
"gl-stroke-transparent"
@
error=
"onError"
@
highlightedJobsChange=
"updateHighlightedJobs"
>
...
...
@@ -234,6 +238,7 @@ export default {
:config-paths=
"configPaths"
:linked-pipelines=
"downstreamPipelines"
:column-title=
"__('Downstream')"
:show-links=
"showJobLinks"
:type=
"$options.pipelineTypeConstants.DOWNSTREAM"
:view-type=
"viewType"
@
downstreamHovered=
"setSourceJob"
...
...
app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue
View file @
c8431dcb
...
...
@@ -48,6 +48,7 @@ export default {
pipeline
:
null
,
pipelineLayers
:
null
,
showAlert
:
false
,
showLinks
:
false
,
};
},
errorTexts
:
{
...
...
@@ -182,6 +183,9 @@ export default {
}
},
/* eslint-enable @gitlab/require-i18n-strings */
updateShowLinksState
(
val
)
{
this
.
showLinks
=
val
;
},
updateViewType
(
type
)
{
this
.
currentViewType
=
type
;
},
...
...
@@ -202,7 +206,9 @@ export default {
<graph-view-selector
v-if=
"showGraphViewSelector"
:type=
"currentViewType"
:show-links=
"showLinks"
@
updateViewType=
"updateViewType"
@
updateShowLinksState=
"updateShowLinksState"
/>
</local-storage-sync>
<gl-loading-icon
v-if=
"showLoadingIcon"
class=
"gl-mx-auto gl-my-4"
size=
"lg"
/>
...
...
@@ -211,6 +217,7 @@ export default {
:config-paths=
"configPaths"
:pipeline=
"pipeline"
:pipeline-layers=
"getPipelineLayers()"
:show-links=
"showLinks"
:view-type=
"currentViewType"
@
error=
"reportFailure"
@
refreshPipelineGraph=
"refreshPipelineGraph"
...
...
app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue
View file @
c8431dcb
<
script
>
import
{
Gl
Dropdown
,
GlDropdownItem
,
GlIcon
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
Gl
LoadingIcon
,
GlSegmentedControl
,
GlToggle
}
from
'
@gitlab/ui
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
STAGE_VIEW
,
LAYER_VIEW
}
from
'
./constants
'
;
export
default
{
name
:
'
GraphViewSelector
'
,
components
:
{
GlDropdown
,
GlDropdownItem
,
GlIcon
,
GlSprintf
,
GlLoadingIcon
,
GlSegmentedControl
,
GlToggle
,
},
props
:
{
showLinks
:
{
type
:
Boolean
,
required
:
true
,
},
type
:
{
type
:
String
,
required
:
true
,
...
...
@@ -19,67 +22,119 @@ export default {
},
data
()
{
return
{
currentViewType
:
STAGE_VIEW
,
currentViewType
:
this
.
type
,
showLinksActive
:
false
,
isToggleLoading
:
false
,
isSwitcherLoading
:
false
,
};
},
i18n
:
{
labelText
:
__
(
'
Order jobs by
'
),
viewLabelText
:
__
(
'
Group jobs by
'
),
linksLabelText
:
__
(
'
Show dependencies
'
),
},
views
:
{
[
STAGE_VIEW
]:
{
type
:
STAGE_VIEW
,
text
:
{
primary
:
__
(
'
Stage
'
),
secondary
:
__
(
'
View the jobs grouped into stages
'
),
},
},
[
LAYER_VIEW
]:
{
type
:
LAYER_VIEW
,
text
:
{
primary
:
__
(
'
%{codeStart}needs:%{codeEnd} relationships
'
),
secondary
:
__
(
'
View what jobs are needed for a job to run
'
),
primary
:
__
(
'
Job dependencies
'
),
},
},
},
computed
:
{
currentDropdownText
()
{
return
this
.
$options
.
views
[
this
.
type
].
text
.
primary
;
showLinksToggle
()
{
return
this
.
currentViewType
===
LAYER_VIEW
;
},
viewTypesList
()
{
return
Object
.
keys
(
this
.
$options
.
views
).
map
((
key
)
=>
{
return
{
value
:
key
,
text
:
this
.
$options
.
views
[
key
].
text
.
primary
,
};
});
},
},
watch
:
{
/*
How does this reset the loading? As we note in the methods comment below,
the loader is set to on before the update work is undertaken (in the parent).
Once the work is complete, one of these values will change, since that's the
point of the work. When that happens, the related value will update and we are done.
The bonus for this approach is that it works the same whichever "direction"
the work goes in.
*/
showLinks
()
{
this
.
isToggleLoading
=
false
;
},
type
()
{
this
.
isSwitcherLoading
=
false
;
},
},
methods
:
{
itemClick
(
type
)
{
this
.
$emit
(
'
updateViewType
'
,
type
);
/*
In both toggle methods, we use setTimeout so that the loading indicator displays,
then the work is done to update the DOM. The process is:
→ user clicks
→ call stack: set loading to true
→ render: the loading icon appears on the screen
→ callback queue: now do the work to calculate the new view / links
(note: this work is done in the parent after the event is emitted)
setTimeout is how we move the work to the callback queue.
We can't use nextTick because that is called before the render loop.
See https://www.hesselinkwebdesign.nl/2019/nexttick-vs-settimeout-in-vue/ for more details.
*/
toggleView
(
type
)
{
this
.
isSwitcherLoading
=
true
;
setTimeout
(()
=>
{
this
.
$emit
(
'
updateViewType
'
,
type
);
});
},
toggleShowLinksActive
(
val
)
{
this
.
isToggleLoading
=
true
;
setTimeout
(()
=>
{
this
.
$emit
(
'
updateShowLinksState
'
,
val
);
});
},
},
};
</
script
>
<
template
>
<div
class=
"gl-display-flex gl-align-items-center gl-my-4"
>
<span>
{{
$options
.
i18n
.
labelText
}}
</span>
<gl-dropdown
data-testid=
"pipeline-view-selector"
class=
"gl-ml-4"
>
<template
#button-content
>
<gl-sprintf
:message=
"currentDropdownText"
>
<template
#code
="
{ content }">
<code>
{{
content
}}
</code>
</
template
>
</gl-sprintf>
<gl-icon
class=
"gl-px-2"
name=
"angle-down"
:size=
"16"
/>
</template>
<gl-dropdown-item
v-for=
"view in $options.views"
:key=
"view.type"
:secondary-text=
"view.text.secondary"
@
click=
"itemClick(view.type)"
>
<b>
<gl-sprintf
:message=
"view.text.primary"
>
<
template
#code=
"{ content }"
>
<code>
{{
content
}}
</code>
</
template
>
</gl-sprintf>
</b>
</gl-dropdown-item>
</gl-dropdown>
<div
class=
"gl-relative gl-display-flex gl-align-items-center gl-w-max-content gl-my-4"
>
<gl-loading-icon
v-if=
"isSwitcherLoading"
data-testid=
"switcher-loading-state"
class=
"gl-absolute gl-w-full gl-bg-white gl-opacity-5 gl-z-index-2"
size=
"lg"
/>
<span
class=
"gl-font-weight-bold"
>
{{
$options
.
i18n
.
viewLabelText
}}
</span>
<gl-segmented-control
v-model=
"currentViewType"
:options=
"viewTypesList"
:disabled=
"isSwitcherLoading"
data-testid=
"pipeline-view-selector"
class=
"gl-mx-4"
@
input=
"toggleView"
/>
<div
v-if=
"showLinksToggle"
>
<gl-toggle
v-model=
"showLinksActive"
data-testid=
"show-links-toggle"
class=
"gl-mx-4"
:label=
"$options.i18n.linksLabelText"
:is-loading=
"isToggleLoading"
label-position=
"left"
@
change=
"toggleShowLinksActive"
/>
</div>
</div>
</
template
>
app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
View file @
c8431dcb
...
...
@@ -32,6 +32,10 @@ export default {
type
:
Array
,
required
:
true
,
},
showLinks
:
{
type
:
Boolean
,
required
:
true
,
},
type
:
{
type
:
String
,
required
:
true
,
...
...
@@ -217,6 +221,7 @@ export default {
:config-paths=
"configPaths"
:pipeline=
"currentPipeline"
:pipeline-layers=
"getPipelineLayers(pipeline.id)"
:show-links=
"showLinks"
:is-linked-pipeline=
"true"
:view-type=
"viewType"
/>
...
...
app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue
View file @
c8431dcb
<
script
>
import
{
GlAlert
}
from
'
@gitlab/ui
'
;
import
{
isEmpty
}
from
'
lodash
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
...
...
@@ -19,10 +18,8 @@ import LinksInner from './links_inner.vue';
export
default
{
name
:
'
LinksLayer
'
,
components
:
{
GlAlert
,
LinksInner
,
},
MAX_GROUPS
:
200
,
props
:
{
containerMeasurements
:
{
type
:
Object
,
...
...
@@ -37,10 +34,10 @@ export default {
required
:
false
,
default
:
()
=>
({}),
},
neverS
howLinks
:
{
s
howLinks
:
{
type
:
Boolean
,
required
:
false
,
default
:
fals
e
,
default
:
tru
e
,
},
},
data
()
{
...
...
@@ -67,29 +64,8 @@ export default {
shouldCollectMetrics
()
{
return
this
.
metricsConfig
.
collectMetrics
&&
this
.
metricsConfig
.
path
;
},
showAlert
()
{
/*
This is a hard override that allows us to turn off the links without
needing to remove the component entirely for iteration or based on graph type.
*/
if
(
this
.
neverShowLinks
)
{
return
false
;
}
return
!
this
.
containerZero
&&
!
this
.
showLinkedLayers
&&
!
this
.
alertDismissed
;
},
showLinkedLayers
()
{
/*
This is a hard override that allows us to turn off the links without
needing to remove the component entirely for iteration or based on graph type.
*/
if
(
this
.
neverShowLinks
)
{
return
false
;
}
return
(
!
this
.
containerZero
&&
(
this
.
showLinksOverride
||
this
.
numGroups
<
this
.
$options
.
MAX_GROUPS
)
);
return
this
.
showLinks
&&
!
this
.
containerZero
;
},
},
errorCaptured
(
err
,
_vm
,
info
)
{
...
...
@@ -103,7 +79,7 @@ export default {
is closed and functionality is enabled by default.
*/
if
(
this
.
neverS
howLinks
&&
!
isEmpty
(
this
.
pipelineData
))
{
if
(
!
this
.
s
howLinks
&&
!
isEmpty
(
this
.
pipelineData
))
{
window
.
requestAnimationFrame
(()
=>
{
this
.
prepareLinkData
();
});
...
...
@@ -151,13 +127,6 @@ export default {
reportPerformance
(
this
.
metricsConfig
.
path
,
data
);
});
},
dismissAlert
()
{
this
.
alertDismissed
=
true
;
},
overrideShowLinks
()
{
this
.
dismissAlert
();
this
.
showLinksOverride
=
true
;
},
prepareLinkData
()
{
this
.
beginPerfMeasure
();
let
numLinks
;
...
...
@@ -185,15 +154,6 @@ export default {
<slot></slot>
</links-inner>
<div
v-else
>
<gl-alert
v-if=
"showAlert"
class=
"gl-ml-4 gl-mb-4"
:primary-button-text=
"$options.i18n.showLinksAnyways"
@
primaryAction=
"overrideShowLinks"
@
dismiss=
"dismissAlert"
>
{{
$options
.
i18n
.
tooManyJobs
}}
</gl-alert>
<div
class=
"gl-display-flex gl-relative"
>
<slot></slot>
</div>
...
...
locale/gitlab.pot
View file @
c8431dcb
...
...
@@ -416,9 +416,6 @@ msgstr ""
msgid "%{board_target} not found"
msgstr ""
msgid "%{codeStart}needs:%{codeEnd} relationships"
msgstr ""
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
...
...
@@ -15217,6 +15214,9 @@ msgstr ""
msgid "Group is required when cluster_type is :group"
msgstr ""
msgid "Group jobs by"
msgstr ""
msgid "Group maintainers can register group runners in the %{link}"
msgstr ""
...
...
@@ -18199,6 +18199,9 @@ msgstr ""
msgid "Job artifacts"
msgstr ""
msgid "Job dependencies"
msgstr ""
msgid "Job has been erased"
msgstr ""
...
...
@@ -22502,9 +22505,6 @@ msgstr ""
msgid "Or you can choose one of the suggested colors below"
msgstr ""
msgid "Order jobs by"
msgstr ""
msgid "Orphaned member"
msgstr ""
...
...
@@ -29048,6 +29048,9 @@ msgstr ""
msgid "Show complete raw log"
msgstr ""
msgid "Show dependencies"
msgstr ""
msgid "Show details"
msgstr ""
...
...
@@ -34816,9 +34819,6 @@ msgstr ""
msgid "View the documentation"
msgstr ""
msgid "View the jobs grouped into stages"
msgstr ""
msgid "View the latest successful deployment to this environment"
msgstr ""
...
...
@@ -34831,9 +34831,6 @@ msgstr ""
msgid "View users statistics"
msgstr ""
msgid "View what jobs are needed for a job to run"
msgstr ""
msgid "Viewed"
msgstr ""
...
...
spec/frontend/pipelines/graph/graph_component_spec.js
View file @
c8431dcb
...
...
@@ -22,6 +22,7 @@ describe('graph component', () => {
const
defaultProps
=
{
pipeline
:
generateResponse
(
mockPipelineResponse
,
'
root/fungi-xoxo
'
),
showLinks
:
false
,
viewType
:
STAGE_VIEW
,
configPaths
:
{
metricsPath
:
''
,
...
...
spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
View file @
c8431dcb
...
...
@@ -15,6 +15,7 @@ import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import
PipelineGraphWrapper
from
'
~/pipelines/components/graph/graph_component_wrapper.vue
'
;
import
GraphViewSelector
from
'
~/pipelines/components/graph/graph_view_selector.vue
'
;
import
StageColumnComponent
from
'
~/pipelines/components/graph/stage_column_component.vue
'
;
import
LinksLayer
from
'
~/pipelines/components/graph_shared/links_layer.vue
'
;
import
*
as
parsingUtils
from
'
~/pipelines/components/parsing_utils
'
;
import
{
mockPipelineResponse
}
from
'
./mock_data
'
;
...
...
@@ -31,7 +32,9 @@ describe('Pipeline graph wrapper', () => {
let
wrapper
;
const
getAlert
=
()
=>
wrapper
.
find
(
GlAlert
);
const
getDependenciesToggle
=
()
=>
wrapper
.
find
(
'
[data-testid="show-links-toggle"]
'
);
const
getLoadingIcon
=
()
=>
wrapper
.
find
(
GlLoadingIcon
);
const
getLinksLayer
=
()
=>
wrapper
.
findComponent
(
LinksLayer
);
const
getGraph
=
()
=>
wrapper
.
find
(
PipelineGraph
);
const
getStageColumnTitle
=
()
=>
wrapper
.
find
(
'
[data-testid="stage-column-title"]
'
);
const
getAllStageColumnGroupsInColumn
=
()
=>
...
...
@@ -59,6 +62,7 @@ describe('Pipeline graph wrapper', () => {
};
const
createComponentWithApollo
=
({
data
=
{},
getPipelineDetailsHandler
=
jest
.
fn
().
mockResolvedValue
(
mockPipelineResponse
),
mountFn
=
shallowMount
,
provide
=
{},
...
...
@@ -66,7 +70,7 @@ describe('Pipeline graph wrapper', () => {
const
requestHandlers
=
[[
getPipelineDetails
,
getPipelineDetailsHandler
]];
const
apolloProvider
=
createMockApollo
(
requestHandlers
);
createComponent
({
apolloProvider
,
provide
,
mountFn
});
createComponent
({
apolloProvider
,
data
,
provide
,
mountFn
});
};
afterEach
(()
=>
{
...
...
@@ -74,6 +78,15 @@ describe('Pipeline graph wrapper', () => {
wrapper
=
null
;
});
beforeAll
(()
=>
{
jest
.
useFakeTimers
();
});
afterAll
(()
=>
{
jest
.
runOnlyPendingTimers
();
jest
.
useRealTimers
();
});
describe
(
'
when data is loading
'
,
()
=>
{
it
(
'
displays the loading icon
'
,
()
=>
{
createComponentWithApollo
();
...
...
@@ -282,6 +295,36 @@ describe('Pipeline graph wrapper', () => {
});
});
describe
(
'
when pipelineGraphLayersView feature flag is on and layers view is selected
'
,
()
=>
{
beforeEach
(
async
()
=>
{
createComponentWithApollo
({
provide
:
{
glFeatures
:
{
pipelineGraphLayersView
:
true
,
},
},
data
:
{
currentViewType
:
LAYER_VIEW
,
},
mountFn
:
mount
,
});
jest
.
runOnlyPendingTimers
();
await
wrapper
.
vm
.
$nextTick
();
});
it
(
'
sets showLinks to true
'
,
async
()
=>
{
/* This spec uses .props for performance reasons. */
expect
(
getLinksLayer
().
exists
()).
toBe
(
true
);
expect
(
getLinksLayer
().
props
(
'
showLinks
'
)).
toBe
(
false
);
expect
(
getViewSelector
().
props
(
'
type
'
)).
toBe
(
LAYER_VIEW
);
await
getDependenciesToggle
().
trigger
(
'
click
'
);
jest
.
runOnlyPendingTimers
();
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
findComponent
(
LinksLayer
).
props
(
'
showLinks
'
)).
toBe
(
true
);
});
});
describe
(
'
when feature flag is on and local storage is set
'
,
()
=>
{
beforeEach
(
async
()
=>
{
localStorage
.
setItem
(
VIEW_TYPE_KEY
,
LAYER_VIEW
);
...
...
@@ -299,10 +342,15 @@ describe('Pipeline graph wrapper', () => {
await
wrapper
.
vm
.
$nextTick
();
});
afterEach
(()
=>
{
localStorage
.
clear
();
});
it
(
'
reads the view type from localStorage when available
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
[data-testid="pipeline-view-selector"] code
'
).
text
()).
toContain
(
'
needs:
'
,
);
const
viewSelectorNeedsSegment
=
wrapper
.
findAll
(
'
[data-testid="pipeline-view-selector"] > label
'
)
.
at
(
1
);
expect
(
viewSelectorNeedsSegment
.
classes
()).
toContain
(
'
active
'
);
});
});
...
...
spec/frontend/pipelines/graph/graph_view_selector_spec.js
0 → 100644
View file @
c8431dcb
import
{
GlLoadingIcon
,
GlSegmentedControl
}
from
'
@gitlab/ui
'
;
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
LAYER_VIEW
,
STAGE_VIEW
}
from
'
~/pipelines/components/graph/constants
'
;
import
GraphViewSelector
from
'
~/pipelines/components/graph/graph_view_selector.vue
'
;
describe
(
'
the graph view selector component
'
,
()
=>
{
let
wrapper
;
const
findDependenciesToggle
=
()
=>
wrapper
.
find
(
'
[data-testid="show-links-toggle"]
'
);
const
findViewTypeSelector
=
()
=>
wrapper
.
findComponent
(
GlSegmentedControl
);
const
findStageViewLabel
=
()
=>
findViewTypeSelector
().
findAll
(
'
label
'
).
at
(
0
);
const
findLayersViewLabel
=
()
=>
findViewTypeSelector
().
findAll
(
'
label
'
).
at
(
1
);
const
findSwitcherLoader
=
()
=>
wrapper
.
find
(
'
[data-testid="switcher-loading-state"]
'
);
const
findToggleLoader
=
()
=>
findDependenciesToggle
().
find
(
GlLoadingIcon
);
const
defaultProps
=
{
showLinks
:
false
,
type
:
STAGE_VIEW
,
};
const
defaultData
=
{
showLinksActive
:
false
,
isToggleLoading
:
false
,
isSwitcherLoading
:
false
,
};
const
createComponent
=
({
data
=
{},
mountFn
=
shallowMount
,
props
=
{}
}
=
{})
=>
{
wrapper
=
mountFn
(
GraphViewSelector
,
{
propsData
:
{
...
defaultProps
,
...
props
,
},
data
()
{
return
{
...
defaultData
,
...
data
,
};
},
});
};
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
when showing stage view
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
mountFn
:
mount
});
});
it
(
'
shows the Stage view label as active in the selector
'
,
()
=>
{
expect
(
findStageViewLabel
().
classes
()).
toContain
(
'
active
'
);
});
it
(
'
does not show the Job dependencies (links) toggle
'
,
()
=>
{
expect
(
findDependenciesToggle
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
when showing Job dependencies view
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
mountFn
:
mount
,
props
:
{
type
:
LAYER_VIEW
,
},
});
});
it
(
'
shows the Job dependencies view label as active in the selector
'
,
()
=>
{
expect
(
findLayersViewLabel
().
classes
()).
toContain
(
'
active
'
);
});
it
(
'
shows the Job dependencies (links) toggle
'
,
()
=>
{
expect
(
findDependenciesToggle
().
exists
()).
toBe
(
true
);
});
});
describe
(
'
events
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
useFakeTimers
();
createComponent
({
mountFn
:
mount
,
props
:
{
type
:
LAYER_VIEW
,
},
});
});
it
(
'
shows loading state and emits updateViewType when view type toggled
'
,
async
()
=>
{
expect
(
wrapper
.
emitted
().
updateViewType
).
toBeUndefined
();
expect
(
findSwitcherLoader
().
exists
()).
toBe
(
false
);
await
findStageViewLabel
().
trigger
(
'
click
'
);
/*
Loading happens before the event is emitted or timers are run.
Then we run the timer because the event is emitted in setInterval
which is what gives the loader a chace to show up.
*/
expect
(
findSwitcherLoader
().
exists
()).
toBe
(
true
);
jest
.
runOnlyPendingTimers
();
expect
(
wrapper
.
emitted
().
updateViewType
).
toHaveLength
(
1
);
expect
(
wrapper
.
emitted
().
updateViewType
).
toEqual
([[
STAGE_VIEW
]]);
});
it
(
'
shows loading state and emits updateShowLinks when show links toggle is clicked
'
,
async
()
=>
{
expect
(
wrapper
.
emitted
().
updateShowLinksState
).
toBeUndefined
();
expect
(
findToggleLoader
().
exists
()).
toBe
(
false
);
await
findDependenciesToggle
().
trigger
(
'
click
'
);
/*
Loading happens before the event is emitted or timers are run.
Then we run the timer because the event is emitted in setInterval
which is what gives the loader a chace to show up.
*/
expect
(
findToggleLoader
().
exists
()).
toBe
(
true
);
jest
.
runOnlyPendingTimers
();
expect
(
wrapper
.
emitted
().
updateShowLinksState
).
toHaveLength
(
1
);
expect
(
wrapper
.
emitted
().
updateShowLinksState
).
toEqual
([[
true
]]);
});
});
});
spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
View file @
c8431dcb
...
...
@@ -26,6 +26,7 @@ describe('Linked Pipelines Column', () => {
const
defaultProps
=
{
columnTitle
:
'
Downstream
'
,
linkedPipelines
:
processedPipeline
.
downstream
,
showLinks
:
false
,
type
:
DOWNSTREAM
,
viewType
:
STAGE_VIEW
,
configPaths
:
{
...
...
spec/frontend/pipelines/graph_shared/links_layer_spec.js
View file @
c8431dcb
import
{
GlAlert
}
from
'
@gitlab/ui
'
;
import
{
fireEvent
,
within
}
from
'
@testing-library/dom
'
;
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
LinksInner
from
'
~/pipelines/components/graph_shared/links_inner.vue
'
;
import
LinksLayer
from
'
~/pipelines/components/graph_shared/links_layer.vue
'
;
import
{
generateResponse
,
mockPipelineResponse
}
from
'
../graph/mock_data
'
;
...
...
@@ -8,25 +6,18 @@ import { generateResponse, mockPipelineResponse } from '../graph/mock_data';
describe
(
'
links layer component
'
,
()
=>
{
let
wrapper
;
const
withinComponent
=
()
=>
within
(
wrapper
.
element
);
const
findAlert
=
()
=>
wrapper
.
find
(
GlAlert
);
const
findShowAnyways
=
()
=>
withinComponent
().
getByText
(
wrapper
.
vm
.
$options
.
i18n
.
showLinksAnyways
);
const
findLinksInner
=
()
=>
wrapper
.
find
(
LinksInner
);
const
pipeline
=
generateResponse
(
mockPipelineResponse
,
'
root/fungi-xoxo
'
);
const
containerId
=
`pipeline-links-container-
${
pipeline
.
id
}
`
;
const
slotContent
=
"
<div>Ceci n'est pas un graphique</div>
"
;
const
tooManyStages
=
Array
(
101
)
.
fill
(
0
)
.
flatMap
(()
=>
pipeline
.
stages
);
const
defaultProps
=
{
containerId
,
containerMeasurements
:
{
width
:
400
,
height
:
400
},
pipelineId
:
pipeline
.
id
,
pipelineData
:
pipeline
.
stages
,
showLinks
:
false
,
};
const
createComponent
=
({
mountFn
=
shallowMount
,
props
=
{}
}
=
{})
=>
{
...
...
@@ -49,7 +40,7 @@ describe('links layer component', () => {
wrapper
=
null
;
});
describe
(
'
with
data under max stages
'
,
()
=>
{
describe
(
'
with
show links off
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
...
...
@@ -58,63 +49,40 @@ describe('links layer component', () => {
expect
(
wrapper
.
html
()).
toContain
(
slotContent
);
});
it
(
'
renders the
inner links component
'
,
()
=>
{
expect
(
findLinksInner
().
exists
()).
toBe
(
tru
e
);
it
(
'
does not render
inner links component
'
,
()
=>
{
expect
(
findLinksInner
().
exists
()).
toBe
(
fals
e
);
});
});
describe
(
'
with more than the max number of stages
'
,
()
=>
{
describe
(
'
rendering
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
pipelineData
:
tooManyStages
}
});
});
it
(
'
renders the default slot
'
,
()
=>
{
expect
(
wrapper
.
html
()).
toContain
(
slotContent
);
});
it
(
'
renders the alert component
'
,
()
=>
{
expect
(
findAlert
().
exists
()).
toBe
(
true
);
});
it
(
'
does not render the inner links component
'
,
()
=>
{
expect
(
findLinksInner
().
exists
()).
toBe
(
false
);
describe
(
'
with show links on
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
showLinks
:
true
,
},
});
});
describe
(
'
with width or height measurement at 0
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
containerMeasurements
:
{
width
:
0
,
height
:
100
}
}
});
});
it
(
'
renders the default slot
'
,
()
=>
{
expect
(
wrapper
.
html
()).
toContain
(
slotContent
);
});
it
(
'
does not render the alert component
'
,
()
=>
{
expect
(
findAlert
().
exists
()).
toBe
(
false
);
});
it
(
'
renders the default slot
'
,
()
=>
{
expect
(
wrapper
.
html
()).
toContain
(
slotContent
);
});
it
(
'
does not render the inner links component
'
,
()
=>
{
expect
(
findLinksInner
().
exists
()).
toBe
(
false
);
});
it
(
'
renders the inner links component
'
,
()
=>
{
expect
(
findLinksInner
().
exists
()).
toBe
(
true
);
});
});
describe
(
'
interactions
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
mountFn
:
mount
,
props
:
{
pipelineData
:
tooManyStages
}
});
});
describe
(
'
with width or height measurement at 0
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
containerMeasurements
:
{
width
:
0
,
height
:
100
}
}
});
});
it
(
'
renders the disable button
'
,
()
=>
{
expect
(
findShowAnyways
()).
not
.
toBe
(
null
);
});
it
(
'
renders the default slot
'
,
()
=>
{
expect
(
wrapper
.
html
()).
toContain
(
slotContent
);
});
it
(
'
shows links when override is clicked
'
,
async
()
=>
{
expect
(
findLinksInner
().
exists
()).
toBe
(
false
);
fireEvent
(
findShowAnyways
(),
new
MouseEvent
(
'
click
'
,
{
bubbles
:
true
}));
await
wrapper
.
vm
.
$nextTick
();
expect
(
findLinksInner
().
exists
()).
toBe
(
true
);
});
it
(
'
does not render the inner links component
'
,
()
=>
{
expect
(
findLinksInner
().
exists
()).
toBe
(
false
);
});
});
});
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