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
e71d8d94
Commit
e71d8d94
authored
Jul 06, 2017
by
Filipa Lacerda
Committed by
Phil Hughes
Jul 06, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve state management for deploy boards with realtime data
parent
d5628865
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
244 additions
and
327 deletions
+244
-327
app/assets/javascripts/environments/components/deploy_board_component.vue
...cripts/environments/components/deploy_board_component.vue
+62
-135
app/assets/javascripts/environments/components/environment.vue
...ssets/javascripts/environments/components/environment.vue
+40
-21
app/assets/javascripts/environments/components/environment_item.vue
.../javascripts/environments/components/environment_item.vue
+8
-9
app/assets/javascripts/environments/components/environments_table.vue
...avascripts/environments/components/environments_table.vue
+4
-30
app/assets/javascripts/environments/stores/environments_store.js
...ets/javascripts/environments/stores/environments_store.js
+22
-12
changelogs/unreleased-ee/2677-deploy-boards.yml
changelogs/unreleased-ee/2677-deploy-boards.yml
+4
-0
spec/javascripts/environments/deploy_board_component_spec.js
spec/javascripts/environments/deploy_board_component_spec.js
+28
-99
spec/javascripts/environments/environment_table_spec.js
spec/javascripts/environments/environment_table_spec.js
+6
-16
spec/javascripts/environments/environments_store_spec.js
spec/javascripts/environments/environments_store_spec.js
+70
-5
No files found.
app/assets/javascripts/environments/components/deploy_board_component.vue
View file @
e71d8d94
<
script
>
/* eslint-disable no-new, no-undef */
/* global Flash */
/**
* Renders a deploy board.
*
* A deploy board is composed by:
* - Information area with percentage of completion.
* - Instances with status.
* - Button Actions.
* [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png)
*
* The data of each deploy board needs to be fetched when we render the component.
*
* The endpoint response can sometimes be 204, in those cases we need to retry the request.
* This should be done using backoff pooling and we should make no more than 3 request
* for each deploy board.
* After the third request we need to show a message saying we can't fetch the data.
* Please refer to this [comment](https://gitlab.com/gitlab-org/gitlab-ee/issues/1589#note_23630610)
* for more information
*/
import
Visibility
from
'
visibilityjs
'
;
import
deployBoardSvg
from
'
empty_states/icons/_deploy_board.svg
'
;
import
instanceComponent
from
'
./deploy_board_instance_component.vue
'
;
import
Poll
from
'
../../lib/utils/poll
'
;
import
'
../../flash
'
;
export
default
{
components
:
{
instanceComponent
,
},
props
:
{
store
:
{
type
:
Object
,
required
:
true
,
},
service
:
{
type
:
Object
,
required
:
true
,
/**
* Renders a deploy board.
*
* A deploy board is composed by:
* - Information area with percentage of completion.
* - Instances with status.
* - Button Actions.
* [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png)
*/
import
deployBoardSvg
from
'
empty_states/icons/_deploy_board.svg
'
;
import
instanceComponent
from
'
./deploy_board_instance_component.vue
'
;
import
loadingIcon
from
'
../../vue_shared/components/loading_icon.vue
'
;
export
default
{
components
:
{
instanceComponent
,
loadingIcon
,
},
deployBoardData
:
{
type
:
Object
,
required
:
true
,
props
:
{
deployBoardData
:
{
type
:
Object
,
required
:
true
,
},
isLoading
:
{
type
:
Boolean
,
required
:
true
,
},
hasError
:
{
type
:
Boolean
,
required
:
true
,
},
},
environmentID
:
{
type
:
Number
,
required
:
true
,
data
()
{
return
{
deployBoardSvg
,
};
},
endpoint
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
isLoading
:
false
,
hasError
:
false
,
deployBoardSvg
,
};
},
created
()
{
const
poll
=
new
Poll
({
resource
:
this
.
service
,
method
:
'
getDeployBoard
'
,
data
:
this
.
endpoint
,
successCallback
:
this
.
successCallback
,
errorCallback
:
this
.
errorCallback
,
});
if
(
!
Visibility
.
hidden
())
{
this
.
isLoading
=
true
;
poll
.
makeRequest
();
}
Visibility
.
change
(()
=>
{
if
(
!
Visibility
.
hidden
())
{
poll
.
restart
();
}
else
{
poll
.
stop
();
}
});
},
methods
:
{
successCallback
(
response
)
{
const
data
=
response
.
json
();
this
.
store
.
storeDeployBoard
(
this
.
environmentID
,
data
);
this
.
isLoading
=
false
;
},
errorCallback
()
{
this
.
isLoading
=
false
;
// eslint-disable-next-line no-new
new
Flash
(
'
An error occurred while fetching the deploy board.
'
);
},
},
computed
:
{
canRenderDeployBoard
()
{
return
!
this
.
isLoading
&&
!
this
.
hasError
&&
this
.
deployBoardData
.
valid
;
},
canRenderEmptyState
()
{
return
!
this
.
isLoading
&&
!
this
.
hasError
&&
!
this
.
deployBoardData
.
valid
;
},
canRenderErrorState
()
{
return
!
this
.
isLoading
&&
this
.
hasError
;
},
instanceTitle
()
{
let
title
;
if
(
this
.
deployBoardData
.
instances
.
length
===
1
)
{
title
=
'
Instance
'
;
}
else
{
title
=
'
Instances
'
;
}
return
title
;
},
projectName
()
{
return
'
<projectname>
'
;
computed
:
{
canRenderDeployBoard
()
{
return
!
this
.
isLoading
&&
!
this
.
hasError
&&
this
.
deployBoardData
.
valid
;
},
canRenderEmptyState
()
{
return
!
this
.
isLoading
&&
!
this
.
hasError
&&
!
this
.
deployBoardData
.
valid
;
},
canRenderErrorState
()
{
return
!
this
.
isLoading
&&
this
.
hasError
;
},
instanceTitle
()
{
let
title
;
if
(
this
.
deployBoardData
.
instances
.
length
===
1
)
{
title
=
'
Instance
'
;
}
else
{
title
=
'
Instances
'
;
}
return
title
;
},
projectName
()
{
return
'
<projectname>
'
;
},
},
},
};
};
</
script
>
<
template
>
<div
class=
"js-deploy-board deploy-board"
>
<div
v-if=
"isLoading"
>
<i
class=
"fa fa-spinner fa-spin"
aria-hidden=
"true"
/>
<loading-icon
/>
</div>
<div
v-if=
"canRenderDeployBoard"
>
...
...
@@ -161,7 +87,8 @@ export default {
<instance-component
:status=
"instance.status"
:tooltip-text=
"instance.tooltip"
:stable=
"instance.stable"
/>
:stable=
"instance.stable"
/>
</
template
>
</div>
</section>
...
...
app/assets/javascripts/environments/components/environment.vue
View file @
e71d8d94
...
...
@@ -33,7 +33,6 @@ export default {
state
:
store
.
state
,
visibility
:
'
available
'
,
isLoading
:
false
,
isLoadingFolderContent
:
false
,
cssContainerClass
:
environmentsData
.
cssClass
,
endpoint
:
environmentsData
.
environmentsDataEndpoint
,
canCreateDeployment
:
environmentsData
.
canCreateDeployment
,
...
...
@@ -97,9 +96,6 @@ export default {
errorCallback
:
this
.
errorCallback
,
notificationCallback
:
(
isMakingRequest
)
=>
{
this
.
isMakingRequest
=
isMakingRequest
;
// We need to verify if any folder is open to also fecth it
this
.
openFolders
=
this
.
store
.
getOpenFolders
();
},
});
...
...
@@ -118,11 +114,13 @@ export default {
eventHub
.
$on
(
'
toggleFolder
'
,
this
.
toggleFolder
);
eventHub
.
$on
(
'
postAction
'
,
this
.
postAction
);
eventHub
.
$on
(
'
toggleDeployBoard
'
,
this
.
toggleDeployBoard
);
},
beforeDestroy
()
{
eventHub
.
$off
(
'
toggleFolder
'
);
eventHub
.
$off
(
'
postAction
'
);
eventHub
.
$off
(
'
toggleDeployBoard
'
);
},
methods
:
{
...
...
@@ -134,14 +132,18 @@ export default {
* @return {Object}
*/
toggleDeployBoard
(
model
)
{
return
this
.
store
.
toggleDeployBoard
(
model
.
id
);
this
.
store
.
toggleDeployBoard
(
model
.
id
);
if
(
!
model
.
isDeployboardVisible
)
{
this
.
fetchDeployBoard
(
model
,
true
);
}
},
toggleFolder
(
folder
,
folderUrl
)
{
this
.
store
.
toggleFolder
(
folder
);
if
(
!
folder
.
isOpen
)
{
this
.
fetchChildEnvironments
(
folder
,
folderUrl
);
this
.
fetchChildEnvironments
(
folder
,
folderUrl
,
true
);
}
},
...
...
@@ -169,19 +171,17 @@ export default {
.
catch
(
this
.
errorCallback
);
},
fetchChildEnvironments
(
folder
,
folderUrl
)
{
this
.
isLoadingFolderContent
=
true
;
fetchChildEnvironments
(
folder
,
folderUrl
,
showLoader
=
false
)
{
this
.
store
.
updateEnvironmentProp
(
folder
,
'
isLoadingFolderContent
'
,
showLoader
)
;
this
.
service
.
getFolderContent
(
folderUrl
)
.
then
(
resp
=>
resp
.
json
())
.
then
((
response
)
=>
{
this
.
store
.
setfolderContent
(
folder
,
response
.
environments
);
this
.
isLoadingFolderContent
=
false
;
})
.
then
(
response
=>
this
.
store
.
setfolderContent
(
folder
,
response
.
environments
))
.
then
(()
=>
this
.
store
.
updateEnvironmentProp
(
folder
,
'
isLoadingFolderContent
'
,
false
))
.
catch
(()
=>
{
this
.
isLoadingFolderContent
=
false
;
// eslint-disable-next-line no-new
new
Flash
(
'
An error occurred while fetching the environments.
'
);
this
.
store
.
updateEnvironmentProp
(
folder
,
'
isLoadingFolderContent
'
,
false
);
});
},
...
...
@@ -198,16 +198,21 @@ export default {
successCallback
(
resp
)
{
this
.
saveData
(
resp
);
// If folders are open while polling we need to open them again
if
(
this
.
openFolders
.
length
)
{
this
.
openFolders
.
map
((
folder
)
=>
{
// We need to verify if any folder is open to also update it
const
openFolders
=
this
.
store
.
getOpenFolders
();
if
(
openFolders
.
length
)
{
openFolders
.
forEach
((
folder
)
=>
{
// TODO - Move this to the backend
const
folderUrl
=
`
${
window
.
location
.
pathname
}
/folders/
${
folder
.
folderName
}
`
;
this
.
store
.
updateFolder
(
folder
,
'
isOpen
'
,
true
);
return
this
.
fetchChildEnvironments
(
folder
,
folderUrl
);
});
}
const
openDeployBoards
=
this
.
store
.
getOpenDeployBoards
();
if
(
openDeployBoards
.
length
)
{
openDeployBoards
.
forEach
(
env
=>
this
.
fetchDeployBoard
(
env
));
}
},
errorCallback
()
{
...
...
@@ -215,6 +220,23 @@ export default {
// eslint-disable-next-line no-new
new
Flash
(
'
An error occurred while fetching the environments.
'
);
},
fetchDeployBoard
(
environment
,
showLoader
=
false
)
{
this
.
store
.
updateEnvironmentProp
(
environment
,
'
isLoadingDeployBoard
'
,
showLoader
);
this
.
service
.
getDeployBoard
(
environment
.
rollout_status_path
)
.
then
(
resp
=>
resp
.
json
())
.
then
((
data
)
=>
{
this
.
store
.
storeDeployBoard
(
environment
.
id
,
data
);
this
.
store
.
updateEnvironmentProp
(
environment
,
'
isLoadingDeployBoard
'
,
false
);
})
.
catch
(()
=>
{
this
.
store
.
updateEnvironmentProp
(
environment
,
'
isLoadingDeployBoard
'
,
false
);
this
.
store
.
updateEnvironmentProp
(
environment
,
'
hasErrorDeployBoard
'
,
true
);
// eslint-disable-next-line no-new
new
Flash
(
'
An error occurred while fetching the deploy board.
'
);
});
},
},
};
</
script
>
...
...
@@ -289,10 +311,7 @@ export default {
:environments=
"state.environments"
:can-create-deployment=
"canCreateDeploymentParsed"
:can-read-environment=
"canReadEnvironmentParsed"
:toggleDeployBoard=
"toggleDeployBoard"
:store=
"store"
:service=
"service"
:is-loading-folder-content=
"isLoadingFolderContent"
/>
/>
</div>
<table-pagination
v-if=
"state.paginationInformation && state.paginationInformation.totalPages > 1"
...
...
app/assets/javascripts/environments/components/environment_item.vue
View file @
e71d8d94
...
...
@@ -44,12 +44,6 @@ export default {
required
:
false
,
default
:
false
,
},
toggleDeployBoard
:
{
type
:
Function
,
required
:
false
,
},
},
computed
:
{
...
...
@@ -426,6 +420,9 @@ export default {
onClickFolder
()
{
eventHub
.
$emit
(
'
toggleFolder
'
,
this
.
model
,
this
.
folderUrl
);
},
toggleDeployBoard
()
{
eventHub
.
$emit
(
'
toggleDeployBoard
'
,
this
.
model
);
},
},
};
</
script
>
...
...
@@ -443,17 +440,19 @@ export default {
<span
class=
"deploy-board-icon"
v-if=
"model.hasDeployBoard"
@
click=
"toggleDeployBoard
(model)
"
>
@
click=
"toggleDeployBoard"
>
<i
v-show=
"!model.isDeployBoardVisible"
class=
"fa fa-caret-right"
aria-hidden=
"true"
/>
aria-hidden=
"true"
>
</i>
<i
v-show=
"model.isDeployBoardVisible"
class=
"fa fa-caret-down"
aria-hidden=
"true"
/>
aria-hidden=
"true"
>
</i>
</span>
<a
v-if=
"!model.isFolder"
...
...
app/assets/javascripts/environments/components/environments_table.vue
View file @
e71d8d94
...
...
@@ -31,29 +31,6 @@ export default {
required
:
false
,
default
:
false
,
},
isLoadingFolderContent
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
toggleDeployBoard
:
{
type
:
Function
,
required
:
false
,
default
:
()
=>
{},
},
store
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({}),
},
service
:
{
type
:
Object
,
required
:
true
,
},
},
methods
:
{
...
...
@@ -90,23 +67,20 @@ export default {
:model=
"model"
:can-create-deployment=
"canCreateDeployment"
:can-read-environment=
"canReadEnvironment"
:toggleDeployBoard=
"toggleDeployBoard"
/>
<div
v-if=
"model.hasDeployBoard && model.isDeployBoardVisible"
class=
"js-deploy-board-row"
>
<div
class=
"deploy-board-container"
>
<deploy-board
:store=
"store"
:service=
"service"
:environmentID=
"model.id"
:deployBoardData=
"model.deployBoardData"
:endpoint=
"model.rollout_status_path"
:deploy-board-data=
"model.deployBoardData"
:is-loading=
"model.isLoadingDeployBoard"
:has-error=
"model.hasErrorDeployBoard"
/>
</div>
</div>
<template
v-if=
"model.isFolder && model.isOpen && model.children && model.children.length > 0"
>
<div
v-if=
"isLoadingFolderContent"
>
<div
v-if=
"
model.
isLoadingFolderContent"
>
<loading-icon
size=
"2"
/>
</div>
...
...
app/assets/javascripts/environments/stores/environments_store.js
View file @
e71d8d94
...
...
@@ -43,14 +43,18 @@ export default class EnvironmentsStore {
*/
storeEnvironments
(
environments
=
[])
{
const
filteredEnvironments
=
environments
.
map
((
env
)
=>
{
const
oldEnvironmentState
=
this
.
state
.
environments
.
find
(
element
=>
element
.
id
===
env
.
latest
.
id
)
||
{};
let
filtered
=
{};
if
(
env
.
size
>
1
)
{
filtered
=
Object
.
assign
({},
env
,
{
isFolder
:
true
,
isLoadingFolderContent
:
oldEnvironmentState
.
isLoading
||
false
,
folderName
:
env
.
name
,
isOpen
:
false
,
children
:
[],
isOpen
:
oldEnvironmentState
.
isOpen
||
false
,
children
:
oldEnvironmentState
.
children
||
[],
});
}
...
...
@@ -64,8 +68,12 @@ export default class EnvironmentsStore {
if
(
filtered
.
size
===
1
&&
filtered
.
rollout_status_path
)
{
filtered
=
Object
.
assign
({},
filtered
,
{
hasDeployBoard
:
true
,
isDeployBoardVisible
:
true
,
deployBoardData
:
{},
isDeployBoardVisible
:
oldEnvironmentState
.
isDeployBoardVisible
===
false
?
oldEnvironmentState
.
isDeployBoardVisible
:
true
,
deployBoardData
:
oldEnvironmentState
.
deployBoardData
||
{},
isLoadingDeployBoard
:
oldEnvironmentState
.
isLoadingDeployBoard
||
false
,
hasErrorDeployBoard
:
oldEnvironmentState
.
hasErrorDeployBoard
||
false
,
});
}
return
filtered
;
...
...
@@ -169,7 +177,7 @@ export default class EnvironmentsStore {
* @return {Array}
*/
toggleFolder
(
folder
)
{
return
this
.
update
Folder
(
folder
,
'
isOpen
'
,
!
folder
.
isOpen
);
return
this
.
update
EnvironmentProp
(
folder
,
'
isOpen
'
,
!
folder
.
isOpen
);
}
/**
...
...
@@ -196,23 +204,23 @@ export default class EnvironmentsStore {
return
updated
;
});
return
this
.
update
Folder
(
folder
,
'
children
'
,
updatedEnvironments
);
return
this
.
update
EnvironmentProp
(
folder
,
'
children
'
,
updatedEnvironments
);
}
/**
* Given a
folder a prop and a new value updates the correct folder
.
* Given a
environment, a prop and a new value updates the correct environment
.
*
* @param {Object}
folder
* @param {Object}
environment
* @param {String} prop
* @param {String|Boolean|Object|Array} newValue
* @return {Array}
*/
update
Folder
(
folder
,
prop
,
newValue
)
{
update
EnvironmentProp
(
environment
,
prop
,
newValue
)
{
const
environments
=
this
.
state
.
environments
;
const
updatedEnvironments
=
environments
.
map
((
env
)
=>
{
const
updateEnv
=
Object
.
assign
({},
env
);
if
(
env
.
i
sFolder
&&
env
.
id
===
folder
.
id
)
{
if
(
env
.
i
d
===
environment
.
id
)
{
updateEnv
[
prop
]
=
newValue
;
}
...
...
@@ -220,8 +228,6 @@ export default class EnvironmentsStore {
});
this
.
state
.
environments
=
updatedEnvironments
;
return
updatedEnvironments
;
}
getOpenFolders
()
{
...
...
@@ -229,4 +235,8 @@ export default class EnvironmentsStore {
return
environments
.
filter
(
env
=>
env
.
isFolder
&&
env
.
isOpen
);
}
getOpenDeployBoards
()
{
return
this
.
state
.
environments
.
filter
(
env
=>
env
.
isDeployBoardVisible
);
}
}
changelogs/unreleased-ee/2677-deploy-boards.yml
0 → 100644
View file @
e71d8d94
---
title
:
Merge states to allow realtime with deploy boards
merge_request
:
author
:
spec/javascripts/environments/deploy_board_component_spec.js
View file @
e71d8d94
import
Vue
from
'
vue
'
;
import
DeployBoard
from
'
~/environments/components/deploy_board_component.vue
'
;
import
Service
from
'
~/environments/services/environments_service
'
;
import
{
deployBoardMockData
,
invalidDeployBoardMockData
}
from
'
./mock_data
'
;
describe
(
'
Deploy Board
'
,
()
=>
{
...
...
@@ -10,147 +9,77 @@ describe('Deploy Board', () => {
DeployBoardComponent
=
Vue
.
extend
(
DeployBoard
);
});
describe
(
'
successfull request
'
,
()
=>
{
const
deployBoardInterceptor
=
(
request
,
next
)
=>
{
next
(
request
.
respondWith
(
JSON
.
stringify
(
deployBoardMockData
),
{
status
:
200
,
}));
};
describe
(
'
with valid data
'
,
()
=>
{
let
component
;
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
deployBoardInterceptor
);
this
.
service
=
new
Service
(
'
environments
'
);
component
=
new
DeployBoardComponent
({
propsData
:
{
store
:
{},
service
:
this
.
service
,
deployBoardData
:
deployBoardMockData
,
environmentID
:
1
,
endpoint
:
'
endpoint
'
,
isLoading
:
false
,
hasError
:
false
,
},
}).
$mount
();
});
afterEach
(
()
=>
{
Vue
.
http
.
interceptors
=
_
.
withou
t
(
Vue
.
http
.
interceptors
,
deployBoardInterceptor
,
);
it
(
'
should render percentage with completion value provided
'
,
()
=>
{
expec
t
(
component
.
$el
.
querySelector
(
'
.deploy-board-information .percentage
'
).
textContent
,
)
.
toEqual
(
`
${
deployBoardMockData
.
completion
}
%`
)
;
});
it
(
'
should render percentage with completion value provided
'
,
(
done
)
=>
{
setTimeout
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.deploy-board-information .percentage
'
).
textContent
,
).
toEqual
(
`
${
deployBoardMockData
.
completion
}
%`
);
done
();
},
0
);
});
it
(
'
should render all instances
'
,
()
=>
{
const
instances
=
component
.
$el
.
querySelectorAll
(
'
.deploy-board-instances-container div
'
);
it
(
'
should render all instances
'
,
(
done
)
=>
{
setTimeout
(()
=>
{
const
instances
=
component
.
$el
.
querySelectorAll
(
'
.deploy-board-instances-container div
'
);
expect
(
instances
.
length
).
toEqual
(
deployBoardMockData
.
instances
.
length
);
expect
(
instances
.
length
).
toEqual
(
deployBoardMockData
.
instances
.
length
);
expect
(
instances
[
2
].
classList
.
contains
(
`deploy-board-instance-
${
deployBoardMockData
.
instances
[
2
].
status
}
`
),
).
toBe
(
true
);
done
();
},
0
);
expect
(
instances
[
2
].
classList
.
contains
(
`deploy-board-instance-
${
deployBoardMockData
.
instances
[
2
].
status
}
`
),
).
toBe
(
true
);
});
it
(
'
should render an abort and a rollback button with the provided url
'
,
(
done
)
=>
{
setTimeout
(()
=>
{
const
buttons
=
component
.
$el
.
querySelectorAll
(
'
.deploy-board-actions a
'
);
it
(
'
should render an abort and a rollback button with the provided url
'
,
()
=>
{
const
buttons
=
component
.
$el
.
querySelectorAll
(
'
.deploy-board-actions a
'
);
expect
(
buttons
[
0
].
getAttribute
(
'
href
'
)).
toEqual
(
deployBoardMockData
.
rollback_url
);
expect
(
buttons
[
1
].
getAttribute
(
'
href
'
)).
toEqual
(
deployBoardMockData
.
abort_url
);
done
();
},
0
);
expect
(
buttons
[
0
].
getAttribute
(
'
href
'
)).
toEqual
(
deployBoardMockData
.
rollback_url
);
expect
(
buttons
[
1
].
getAttribute
(
'
href
'
)).
toEqual
(
deployBoardMockData
.
abort_url
);
});
});
describe
(
'
successfull request without valid data
'
,
()
=>
{
const
deployBoardInterceptorInvalidData
=
(
request
,
next
)
=>
{
next
(
request
.
respondWith
(
JSON
.
stringify
(
invalidDeployBoardMockData
),
{
status
:
200
,
}));
};
describe
(
'
without valid data
'
,
()
=>
{
let
component
;
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
deployBoardInterceptorInvalidData
);
this
.
service
=
new
Service
(
'
environments
'
);
component
=
new
DeployBoardComponent
({
propsData
:
{
store
:
{},
service
:
new
Service
(
'
environments
'
),
deployBoardData
:
invalidDeployBoardMockData
,
environmentID
:
1
,
endpoint
:
'
endpoint
'
,
isLoading
:
false
,
hasError
:
false
,
},
}).
$mount
();
});
afterEach
(()
=>
{
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
deployBoardInterceptorInvalidData
,
);
});
it
(
'
should render the empty state
'
,
(
done
)
=>
{
setTimeout
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.deploy-board-empty-state-svg svg
'
)).
toBeDefined
();
expect
(
component
.
$el
.
querySelector
(
'
.deploy-board-empty-state-text .title
'
).
textContent
).
toContain
(
'
Kubernetes deployment not found
'
);
done
();
},
0
);
it
(
'
should render the empty state
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.deploy-board-empty-state-svg svg
'
)).
toBeDefined
();
expect
(
component
.
$el
.
querySelector
(
'
.deploy-board-empty-state-text .title
'
).
textContent
).
toContain
(
'
Kubernetes deployment not found
'
);
});
});
describe
(
'
unsuccessfull request
'
,
()
=>
{
const
deployBoardErrorInterceptor
=
(
request
,
next
)
=>
{
next
(
request
.
respondWith
(
JSON
.
stringify
({}),
{
status
:
500
,
}));
};
describe
(
'
with error
'
,
()
=>
{
let
component
;
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
deployBoardErrorInterceptor
);
this
.
service
=
new
Service
(
'
environments
'
);
component
=
new
DeployBoardComponent
({
propsData
:
{
store
:
{},
service
:
this
.
service
,
deployBoardData
:
{},
environmentID
:
1
,
endpoint
:
'
endpoint
'
,
isLoading
:
false
,
hasError
:
true
,
},
}).
$mount
();
});
afterEach
(()
=>
{
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
deployBoardErrorInterceptor
);
});
it
(
'
should render empty state
'
,
(
done
)
=>
{
setTimeout
(()
=>
{
expect
(
component
.
$el
.
children
.
length
).
toEqual
(
1
);
done
();
},
0
);
it
(
'
should render empty state
'
,
()
=>
{
expect
(
component
.
$el
.
children
.
length
).
toEqual
(
1
);
});
});
});
spec/javascripts/environments/environment_table_spec.js
View file @
e71d8d94
import
Vue
from
'
vue
'
;
import
environmentTableComp
from
'
~/environments/components/environments_table.vue
'
;
import
eventHub
from
'
~/environments/event_hub
'
;
import
{
deployBoardMockData
}
from
'
./mock_data
'
;
describe
(
'
Environment item
'
,
()
=>
{
...
...
@@ -24,9 +25,6 @@ describe('Environment item', () => {
environments
:
[
mockItem
],
canCreateDeployment
:
false
,
canReadEnvironment
:
true
,
toggleDeployBoard
:
()
=>
{},
store
:
{},
service
:
{},
},
}).
$mount
();
...
...
@@ -43,6 +41,8 @@ describe('Environment item', () => {
hasDeployBoard
:
true
,
deployBoardData
:
deployBoardMockData
,
isDeployBoardVisible
:
true
,
isLoadingDeployBoard
:
false
,
hasErrorDeployBoard
:
false
,
};
const
component
=
new
EnvironmentTable
({
...
...
@@ -51,11 +51,6 @@ describe('Environment item', () => {
environments
:
[
mockItem
],
canCreateDeployment
:
true
,
canReadEnvironment
:
true
,
toggleDeployBoard
:
()
=>
{},
store
:
{},
service
:
{
getDeployBoard
:
()
=>
Promise
.
resolve
(),
},
},
}).
$mount
();
...
...
@@ -85,7 +80,9 @@ describe('Environment item', () => {
isDeployBoardVisible
:
false
,
};
const
spy
=
jasmine
.
createSpy
(
'
spy
'
);
eventHub
.
$on
(
'
toggleDeployBoard
'
,
(
env
)
=>
{
expect
(
env
.
id
).
toEqual
(
mockItem
.
id
);
});
const
component
=
new
EnvironmentTable
({
el
:
document
.
querySelector
(
'
.test-dom-element
'
),
...
...
@@ -93,16 +90,9 @@ describe('Environment item', () => {
environments
:
[
mockItem
],
canCreateDeployment
:
true
,
canReadEnvironment
:
true
,
toggleDeployBoard
:
spy
,
store
:
{},
service
:
{
getDeployBoard
:
()
=>
Promise
.
resolve
(),
},
},
}).
$mount
();
component
.
$el
.
querySelector
(
'
.deploy-board-icon
'
).
click
();
expect
(
spy
).
toHaveBeenCalled
();
});
});
spec/javascripts/environments/environments_store_spec.js
View file @
e71d8d94
...
...
@@ -33,6 +33,8 @@ describe('Store', () => {
hasDeployBoard
:
true
,
isDeployBoardVisible
:
true
,
deployBoardData
:
{},
isLoadingDeployBoard
:
false
,
hasErrorDeployBoard
:
false
,
};
store
.
storeEnvironments
(
serverData
);
...
...
@@ -60,8 +62,10 @@ describe('Store', () => {
const
environment
=
{
name
:
'
foo
'
,
size
:
1
,
id
:
1
,
rollout_status_path
:
'
url
'
,
latest
:
{
id
:
1
,
rollout_status_path
:
'
url
'
,
},
};
store
.
storeEnvironments
([
environment
]);
...
...
@@ -74,7 +78,9 @@ describe('Store', () => {
const
environment
=
{
name
:
'
bar
'
,
size
:
3
,
id
:
2
,
latest
:
{
id
:
2
,
},
};
store
.
storeEnvironments
([
environment
]);
...
...
@@ -119,6 +125,16 @@ describe('Store', () => {
store
.
toggleFolder
(
store
.
state
.
environments
[
1
]);
expect
(
store
.
state
.
environments
[
1
].
isOpen
).
toEqual
(
false
);
});
it
(
'
should keep folder open when environments are updated
'
,
()
=>
{
store
.
storeEnvironments
(
serverData
);
store
.
toggleFolder
(
store
.
state
.
environments
[
1
]);
expect
(
store
.
state
.
environments
[
1
].
isOpen
).
toEqual
(
true
);
store
.
storeEnvironments
(
serverData
);
expect
(
store
.
state
.
environments
[
1
].
isOpen
).
toEqual
(
true
);
});
});
describe
(
'
setfolderContent
'
,
()
=>
{
...
...
@@ -130,6 +146,17 @@ describe('Store', () => {
expect
(
store
.
state
.
environments
[
1
].
children
.
length
).
toEqual
(
serverData
.
length
);
expect
(
store
.
state
.
environments
[
1
].
children
[
0
].
isChildren
).
toEqual
(
true
);
});
it
(
'
should keep folder content when environments are updated
'
,
()
=>
{
store
.
storeEnvironments
(
serverData
);
store
.
setfolderContent
(
store
.
state
.
environments
[
1
],
serverData
);
expect
(
store
.
state
.
environments
[
1
].
children
.
length
).
toEqual
(
serverData
.
length
);
// poll
store
.
storeEnvironments
(
serverData
);
expect
(
store
.
state
.
environments
[
1
].
children
.
length
).
toEqual
(
serverData
.
length
);
});
});
describe
(
'
store pagination
'
,
()
=>
{
...
...
@@ -162,7 +189,10 @@ describe('Store', () => {
const
environment
=
{
name
:
'
foo
'
,
size
:
1
,
id
:
1
,
latest
:
{
id
:
1
,
},
rollout_status_path
:
'
path
'
,
};
store
.
storeEnvironments
([
environment
]);
...
...
@@ -170,13 +200,30 @@ describe('Store', () => {
it
(
'
should toggle deploy board property for given environment id
'
,
()
=>
{
store
.
toggleDeployBoard
(
1
);
expect
(
store
.
state
.
environments
[
0
].
isDeployBoardVisible
).
toEqual
(
true
);
expect
(
store
.
state
.
environments
[
0
].
isDeployBoardVisible
).
toEqual
(
false
);
});
it
(
'
should store deploy board data for given environment id
'
,
()
=>
{
store
.
storeDeployBoard
(
1
,
deployBoardMockData
);
expect
(
store
.
state
.
environments
[
0
].
deployBoardData
).
toEqual
(
deployBoardMockData
);
});
it
(
'
should keep deploy board data when updating environments
'
,
()
=>
{
store
.
storeDeployBoard
(
1
,
deployBoardMockData
);
expect
(
store
.
state
.
environments
[
0
].
deployBoardData
).
toEqual
(
deployBoardMockData
);
const
environment
=
{
name
:
'
foo
'
,
size
:
1
,
latest
:
{
id
:
1
,
},
rollout_status_path
:
'
path
'
,
};
store
.
storeEnvironments
([
environment
]);
expect
(
store
.
state
.
environments
[
0
].
deployBoardData
).
toEqual
(
deployBoardMockData
);
});
});
describe
(
'
getOpenFolders
'
,
()
=>
{
...
...
@@ -187,4 +234,22 @@ describe('Store', () => {
expect
(
store
.
getOpenFolders
()[
0
]).
toEqual
(
store
.
state
.
environments
[
1
]);
});
});
describe
(
'
getOpenDeployBoards
'
,
()
=>
{
it
(
'
should return open deploy boards
'
,
()
=>
{
const
environment
=
{
name
:
'
foo
'
,
size
:
1
,
latest
:
{
id
:
1
,
},
rollout_status_path
:
'
path
'
,
};
store
.
storeEnvironments
([
environment
]);
expect
(
store
.
getOpenDeployBoards
().
length
).
toEqual
(
1
);
expect
(
store
.
getOpenDeployBoards
()[
0
].
id
).
toEqual
(
environment
.
latest
.
id
);
});
});
});
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