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
8d3d313c
Commit
8d3d313c
authored
May 25, 2021
by
Robert Hunt
Committed by
Natalia Tepluhina
May 25, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create new create/update modals to show the form
parent
d0429644
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
683 additions
and
75 deletions
+683
-75
ee/app/assets/javascripts/status_checks/components/actions.vue
...p/assets/javascripts/status_checks/components/actions.vue
+9
-1
ee/app/assets/javascripts/status_checks/components/form.vue
ee/app/assets/javascripts/status_checks/components/form.vue
+28
-30
ee/app/assets/javascripts/status_checks/components/modal_create.vue
...ets/javascripts/status_checks/components/modal_create.vue
+38
-0
ee/app/assets/javascripts/status_checks/components/modal_update.vue
...ets/javascripts/status_checks/components/modal_update.vue
+37
-0
ee/app/assets/javascripts/status_checks/components/shared_modal.vue
...ets/javascripts/status_checks/components/shared_modal.vue
+107
-0
ee/app/assets/javascripts/status_checks/components/status_checks.vue
...ts/javascripts/status_checks/components/status_checks.vue
+21
-8
ee/app/assets/javascripts/status_checks/constants.js
ee/app/assets/javascripts/status_checks/constants.js
+1
-1
ee/app/assets/javascripts/status_checks/utils.js
ee/app/assets/javascripts/status_checks/utils.js
+4
-0
ee/spec/frontend/status_checks/components/actions_spec.js
ee/spec/frontend/status_checks/components/actions_spec.js
+23
-5
ee/spec/frontend/status_checks/components/form_spec.js
ee/spec/frontend/status_checks/components/form_spec.js
+39
-19
ee/spec/frontend/status_checks/components/modal_create_spec.js
...ec/frontend/status_checks/components/modal_create_spec.js
+74
-0
ee/spec/frontend/status_checks/components/modal_update_spec.js
...ec/frontend/status_checks/components/modal_update_spec.js
+66
-0
ee/spec/frontend/status_checks/components/shared_modal_spec.js
...ec/frontend/status_checks/components/shared_modal_spec.js
+170
-0
ee/spec/frontend/status_checks/components/status_checks_spec.js
...c/frontend/status_checks/components/status_checks_spec.js
+50
-11
ee/spec/frontend/status_checks/utils_spec.js
ee/spec/frontend/status_checks/utils_spec.js
+13
-0
locale/gitlab.pot
locale/gitlab.pot
+3
-0
No files found.
ee/app/assets/javascripts/status_checks/components/actions.vue
View file @
8d3d313c
...
...
@@ -6,6 +6,12 @@ export default {
components
:
{
GlButton
,
},
props
:
{
statusCheck
:
{
type
:
Object
,
required
:
true
,
},
},
i18n
:
{
editButton
:
__
(
'
Edit
'
),
removeButton
:
__
(
'
Remove...
'
),
...
...
@@ -15,7 +21,9 @@ export default {
<
template
>
<div
class=
"gl-display-flex gl-justify-content-end"
>
<gl-button
data-testid=
"edit-btn"
>
{{
$options
.
i18n
.
editButton
}}
</gl-button>
<gl-button
data-testid=
"edit-btn"
@
click=
"$emit('open-update-modal', statusCheck)"
>
{{
$options
.
i18n
.
editButton
}}
</gl-button>
<gl-button
class=
"gl-ml-3"
data-testid=
"remove-btn"
>
{{
$options
.
i18n
.
removeButton
}}
</gl-button>
...
...
ee/app/assets/javascripts/status_checks/components/form.vue
View file @
8d3d313c
...
...
@@ -29,11 +29,6 @@ export default {
required
:
false
,
default
:
()
=>
[],
},
showValidation
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
statusCheck
:
{
type
:
Object
,
required
:
false
,
...
...
@@ -41,51 +36,36 @@ export default {
},
},
data
()
{
const
{
protectedBranches
,
name
,
externalUrl
:
url
}
=
this
.
statusCheck
;
const
{
protectedBranches
:
branches
,
name
,
externalUrl
:
url
}
=
this
.
statusCheck
;
return
{
branches
:
protectedBranches
,
branches
,
branchesToAdd
:
[],
branchesApiFailed
:
false
,
name
,
showValidation
:
false
,
url
,
};
},
computed
:
{
formData
()
{
const
{
branches
,
name
,
url
}
=
this
;
return
{
branches
:
branches
.
map
(({
id
})
=>
id
),
name
,
url
,
};
},
isValid
()
{
return
this
.
isValidBranches
&&
this
.
isValidName
&&
this
.
isValidUrl
;
},
isValidBranches
()
{
return
this
.
branches
.
every
((
branch
)
=>
isEqual
(
branch
,
ANY_BRANCH
)
||
isNumber
(
branch
?.
id
));
},
isValidName
()
{
return
Boolean
(
this
.
name
);
},
isValidUrl
()
{
return
Boolean
(
this
.
url
)
&&
isSafeURL
(
this
.
url
);
return
this
.
nameState
&&
this
.
urlState
&&
this
.
branchesState
;
},
branchesState
()
{
return
!
this
.
showValidation
||
this
.
isValidBranches
;
return
!
this
.
showValidation
||
this
.
checkBranchesValidity
(
this
.
branches
)
;
},
nameState
()
{
return
(
!
this
.
showValidation
||
(
this
.
isValidName
&&
!
this
.
serverValidationErrors
.
includes
(
NAME_TAKEN_SERVER_ERROR
))
(
this
.
checkNameValidity
(
this
.
name
)
&&
!
this
.
serverValidationErrors
.
includes
(
NAME_TAKEN_SERVER_ERROR
))
);
},
urlState
()
{
return
(
!
this
.
showValidation
||
(
this
.
isValidUrl
&&
!
this
.
serverValidationErrors
.
includes
(
URL_TAKEN_SERVER_ERROR
))
(
this
.
checkUrlValidity
(
this
.
url
)
&&
!
this
.
serverValidationErrors
.
includes
(
URL_TAKEN_SERVER_ERROR
))
);
},
invalidNameMessage
()
{
...
...
@@ -109,6 +89,15 @@ export default {
},
},
methods
:
{
submit
()
{
this
.
showValidation
=
true
;
if
(
this
.
isValid
)
{
const
{
branches
,
name
,
url
}
=
this
;
this
.
$emit
(
'
submit
'
,
{
branches
,
name
,
url
});
}
},
setBranchApiError
(
hasErrored
,
error
)
{
if
(
!
this
.
branchesApiFailed
&&
error
)
{
Sentry
.
captureException
(
error
);
...
...
@@ -116,6 +105,15 @@ export default {
this
.
branchesApiFailed
=
hasErrored
;
},
checkBranchesValidity
(
branches
)
{
return
branches
.
every
((
branch
)
=>
isEqual
(
branch
,
ANY_BRANCH
)
||
isNumber
(
branch
?.
id
));
},
checkNameValidity
(
name
)
{
return
Boolean
(
name
);
},
checkUrlValidity
(
url
)
{
return
Boolean
(
url
)
&&
isSafeURL
(
url
);
},
},
i18n
:
{
form
:
{
...
...
@@ -148,7 +146,7 @@ export default {
<gl-alert
v-if=
"branchesApiFailed"
class=
"gl-mb-5"
:dismissible=
"false"
variant=
"danger"
>
{{
$options
.
i18n
.
validations
.
branchesApiFailure
}}
</gl-alert>
<form
novalidate
>
<form
novalidate
@
submit.prevent.stop=
"submit"
>
<gl-form-group
:label=
"$options.i18n.form.nameLabel"
:description=
"$options.i18n.form.nameDescription"
...
...
ee/app/assets/javascripts/status_checks/components/modal_create.vue
0 → 100644
View file @
8d3d313c
<
script
>
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
mapActions
}
from
'
vuex
'
;
import
{
s__
}
from
'
~/locale
'
;
import
SharedModal
from
'
./shared_modal.vue
'
;
export
default
{
components
:
{
GlButton
,
SharedModal
,
},
methods
:
{
...
mapActions
([
'
postStatusCheck
'
]),
show
()
{
this
.
$refs
.
modal
.
show
();
},
},
modalId
:
'
status-checks-create-modal
'
,
i18n
:
{
addButton
:
s__
(
'
StatusCheck|Add status check
'
),
title
:
s__
(
'
StatusCheck|Add status check
'
),
},
};
</
script
>
<
template
>
<div>
<gl-button
category=
"secondary"
variant=
"confirm"
size=
"small"
@
click=
"show()"
>
{{
$options
.
i18n
.
addButton
}}
</gl-button>
<shared-modal
ref=
"modal"
:modal-id=
"$options.modalId"
:title=
"$options.i18n.title"
:action=
"postStatusCheck"
/>
</div>
</
template
>
ee/app/assets/javascripts/status_checks/components/modal_update.vue
0 → 100644
View file @
8d3d313c
<
script
>
import
{
mapActions
}
from
'
vuex
'
;
import
{
s__
}
from
'
~/locale
'
;
import
SharedModal
from
'
./shared_modal.vue
'
;
export
default
{
components
:
{
SharedModal
,
},
props
:
{
statusCheck
:
{
type
:
Object
,
required
:
true
,
},
},
methods
:
{
...
mapActions
([
'
putStatusCheck
'
]),
show
()
{
this
.
$refs
.
modal
.
show
();
},
},
modalId
:
'
status-checks-update-modal
'
,
i18n
:
{
title
:
s__
(
'
StatusCheck|Update status check
'
),
},
};
</
script
>
<
template
>
<shared-modal
ref=
"modal"
:modal-id=
"$options.modalId"
:title=
"$options.i18n.title"
:status-check=
"statusCheck"
:action=
"putStatusCheck"
/>
</
template
>
ee/app/assets/javascripts/status_checks/components/shared_modal.vue
0 → 100644
View file @
8d3d313c
<
script
>
import
{
GlModal
,
GlModalDirective
}
from
'
@gitlab/ui
'
;
import
{
mapState
}
from
'
vuex
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
modalPrimaryActionProps
}
from
'
../utils
'
;
import
StatusCheckForm
from
'
./form.vue
'
;
const
i18n
=
{
cancelButton
:
__
(
'
Cancel
'
)
};
export
default
{
components
:
{
GlModal
,
StatusCheckForm
,
},
directives
:
{
GlModal
:
GlModalDirective
,
},
props
:
{
action
:
{
type
:
Function
,
required
:
true
,
},
modalId
:
{
type
:
String
,
required
:
true
,
},
statusCheck
:
{
type
:
Object
,
required
:
false
,
default
:
undefined
,
},
title
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
serverValidationErrors
:
[],
submitting
:
false
,
};
},
computed
:
{
...
mapState
({
projectId
:
({
settings
})
=>
settings
.
projectId
,
}),
primaryActionProps
()
{
return
modalPrimaryActionProps
(
this
.
title
,
this
.
submitting
);
},
},
methods
:
{
async
submit
()
{
this
.
$refs
.
form
.
submit
();
},
async
handleFormSubmit
(
formData
)
{
this
.
submitting
=
true
;
const
{
branches
,
name
,
url
}
=
formData
;
try
{
await
this
.
action
({
externalUrl
:
url
,
id
:
this
.
statusCheck
?.
id
,
name
,
protectedBranchIds
:
branches
.
map
(({
id
})
=>
id
),
});
this
.
$refs
.
modal
.
hide
();
}
catch
(
failureResponse
)
{
this
.
serverValidationErrors
=
failureResponse
?.
response
?.
data
?.
message
||
[];
}
this
.
submitting
=
false
;
},
show
()
{
this
.
$refs
.
modal
.
show
();
},
resetModal
()
{
this
.
serverValidationErrors
=
[];
},
},
cancelActionProps
:
{
text
:
i18n
.
cancelButton
,
},
};
</
script
>
<
template
>
<gl-modal
ref=
"modal"
:modal-id=
"modalId"
:title=
"title"
:action-primary=
"primaryActionProps"
:action-cancel=
"$options.cancelActionProps"
size=
"sm"
@
ok.prevent=
"submit"
@
hidden=
"resetModal"
>
<status-check-form
ref=
"form"
:project-id=
"projectId"
:server-validation-errors=
"serverValidationErrors"
:status-check=
"statusCheck"
@
submit=
"handleFormSubmit"
/>
</gl-modal>
</
template
>
ee/app/assets/javascripts/status_checks/components/status_checks.vue
View file @
8d3d313c
<
script
>
import
{
Gl
Button
,
Gl
Table
}
from
'
@gitlab/ui
'
;
import
{
GlTable
}
from
'
@gitlab/ui
'
;
import
{
mapState
}
from
'
vuex
'
;
import
{
DEFAULT_TH_CLASSES
}
from
'
~/lib/utils/constants
'
;
import
{
thWidthClass
}
from
'
~/lib/utils/table_utility
'
;
import
{
__
,
s__
}
from
'
~/locale
'
;
import
{
EMPTY_STATUS_CHECK
}
from
'
../constants
'
;
import
Actions
from
'
./actions.vue
'
;
import
Branch
from
'
./branch.vue
'
;
import
ModalCreate
from
'
./modal_create.vue
'
;
import
ModalUpdate
from
'
./modal_update.vue
'
;
export
const
i18n
=
{
addButton
:
s__
(
'
StatusCheck|Add status check
'
),
apiHeader
:
__
(
'
API
'
),
branchHeader
:
__
(
'
Target branch
'
),
emptyTableText
:
s__
(
'
StatusCheck|No status checks are defined yet.
'
),
...
...
@@ -19,12 +21,24 @@ export default {
components
:
{
Actions
,
Branch
,
GlButton
,
GlTable
,
ModalCreate
,
ModalUpdate
,
},
data
()
{
return
{
statusCheckToUpdate
:
EMPTY_STATUS_CHECK
,
};
},
computed
:
{
...
mapState
([
'
statusChecks
'
]),
},
methods
:
{
openUpdateModal
(
statusCheck
)
{
this
.
statusCheckToUpdate
=
statusCheck
;
this
.
$refs
.
updateModal
.
show
();
},
},
fields
:
[
{
key
:
'
name
'
,
...
...
@@ -65,13 +79,12 @@ export default {
<template
#cell(protectedBranches)=
"
{ item }">
<branch
:branches=
"item.protectedBranches"
/>
</
template
>
<
template
#cell
(
actions
)
>
<actions
/>
<
template
#cell(actions)
=
"{ item }"
>
<actions
:status-check=
"item"
@
open-update-modal=
"openUpdateModal"
/>
</
template
>
</gl-table>
<gl-button
category=
"secondary"
variant=
"confirm"
size=
"small"
>
{{ $options.i18n.addButton }}
</gl-button>
<modal-create
/>
<modal-update
ref=
"updateModal"
:status-check=
"statusCheckToUpdate"
/>
</div>
</template>
ee/app/assets/javascripts/status_checks/constants.js
View file @
8d3d313c
...
...
@@ -9,7 +9,7 @@ export const ANY_BRANCH = {
export
const
EMPTY_STATUS_CHECK
=
{
name
:
''
,
protectedBranches
:
[],
u
rl
:
''
,
externalU
rl
:
''
,
};
export
const
URL_TAKEN_SERVER_ERROR
=
'
External url has already been taken
'
;
...
...
ee/app/assets/javascripts/status_checks/utils.js
0 → 100644
View file @
8d3d313c
export
const
modalPrimaryActionProps
=
(
text
,
loading
)
=>
({
text
,
attributes
:
[{
variant
:
'
confirm
'
,
loading
}],
});
ee/spec/frontend/status_checks/components/actions_spec.js
View file @
8d3d313c
...
...
@@ -2,17 +2,31 @@ import { GlButton } from '@gitlab/ui';
import
Actions
from
'
ee/status_checks/components/actions.vue
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
const
statusCheck
=
{
externalUrl
:
'
https://foo.com
'
,
id
:
1
,
name
:
'
Foo
'
,
protectedBranches
:
[],
};
describe
(
'
Status checks actions
'
,
()
=>
{
let
wrapper
;
const
createWrapper
=
()
=>
{
wrapper
=
shallowMountExtended
(
Actions
,
{
propsData
:
{
statusCheck
,
},
stubs
:
{
GlButton
,
},
});
};
beforeEach
(()
=>
{
createWrapper
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
...
...
@@ -20,15 +34,19 @@ describe('Status checks actions', () => {
const
findEditBtn
=
()
=>
wrapper
.
findByTestId
(
'
edit-btn
'
);
const
findRemoveBtn
=
()
=>
wrapper
.
findByTestId
(
'
remove-btn
'
);
it
(
'
renders the edit button
'
,
()
=>
{
createWrapper
();
describe
(
'
Edit button
'
,
()
=>
{
it
(
'
renders the edit button
'
,
()
=>
{
expect
(
findEditBtn
().
text
()).
toBe
(
'
Edit
'
);
});
it
(
'
sends the status check to the update event
'
,
()
=>
{
findEditBtn
().
trigger
(
'
click
'
);
expect
(
findEditBtn
().
text
()).
toBe
(
'
Edit
'
);
expect
(
wrapper
.
emitted
(
'
open-update-modal
'
)[
0
][
0
]).
toStrictEqual
(
statusCheck
);
});
});
it
(
'
renders the remove button
'
,
()
=>
{
createWrapper
();
expect
(
findRemoveBtn
().
text
()).
toBe
(
'
Remove...
'
);
});
});
ee/spec/frontend/status_checks/components/form_spec.js
View file @
8d3d313c
import
{
GlAlert
,
GlFormGroup
,
GlFormInput
}
from
'
@gitlab/ui
'
;
import
*
as
Sentry
from
'
@sentry/browser
'
;
import
{
nextTick
}
from
'
vue
'
;
import
BranchesSelect
from
'
ee/status_checks/components/branches_select.vue
'
;
import
Form
from
'
ee/status_checks/components/form.vue
'
;
import
{
NAME_TAKEN_SERVER_ERROR
,
URL_TAKEN_SERVER_ERROR
}
from
'
ee/status_checks/constants
'
;
...
...
@@ -11,7 +10,6 @@ import { TEST_PROTECTED_BRANCHES } from '../mock_data';
const
projectId
=
'
1
'
;
const
statusCheck
=
{
protectedBranches
:
TEST_PROTECTED_BRANCHES
,
branches
:
TEST_PROTECTED_BRANCHES
,
name
:
'
Foo
'
,
externalUrl
:
'
https://foo.com
'
,
};
...
...
@@ -19,10 +17,15 @@ const sentryError = new Error('Network error');
describe
(
'
Status checks form
'
,
()
=>
{
let
wrapper
;
const
submitHandler
=
jest
.
fn
();
const
createWrapper
=
(
props
=
{})
=>
{
wrapper
=
shallowMountExtended
(
Form
,
{
propsData
:
{
projectId
,
...
props
},
propsData
:
{
projectId
,
submitHandler
,
...
props
,
},
stubs
:
{
GlFormGroup
:
stubComponent
(
GlFormGroup
,
{
props
:
[
'
state
'
,
'
invalidFeedback
'
],
...
...
@@ -31,10 +34,12 @@ describe('Status checks form', () => {
props
:
[
'
state
'
,
'
disabled
'
,
'
value
'
],
template
:
`<input />`
,
}),
BranchesSelect
:
stubComponent
(
BranchesSelect
),
},
});
};
const
findForm
=
()
=>
wrapper
.
find
(
'
form
'
);
const
findNameInput
=
()
=>
wrapper
.
findByTestId
(
'
name
'
);
const
findNameValidation
=
()
=>
wrapper
.
findByTestId
(
'
name-group
'
);
const
findBranchesSelect
=
()
=>
wrapper
.
findComponent
(
BranchesSelect
);
...
...
@@ -61,7 +66,7 @@ describe('Status checks form', () => {
expect
(
inputsAreValid
()).
toBe
(
true
);
expect
(
findNameInput
().
props
(
'
value
'
)).
toBe
(
''
);
expect
(
findBranchesSelect
().
props
(
'
selectedBranches
'
)).
toStrictEqual
([]);
expect
(
findUrlInput
().
props
(
'
value
'
)).
toBe
(
undefined
);
expect
(
findUrlInput
().
props
(
'
value
'
)).
toBe
(
''
);
});
it
(
'
shows filled inputs when initial data is given
'
,
()
=>
{
...
...
@@ -69,15 +74,20 @@ describe('Status checks form', () => {
expect
(
inputsAreValid
()).
toBe
(
true
);
expect
(
findNameInput
().
props
(
'
value
'
)).
toBe
(
statusCheck
.
name
);
expect
(
findBranchesSelect
().
props
(
'
selectedBranches
'
)).
toStrictEqual
(
statusCheck
.
branches
);
expect
(
findBranchesSelect
().
props
(
'
selectedBranches
'
)).
toStrictEqual
(
statusCheck
.
protectedBranches
,
);
expect
(
findUrlInput
().
props
(
'
value
'
)).
toBe
(
statusCheck
.
externalUrl
);
});
});
describe
(
'
Validation
'
,
()
=>
{
it
(
'
shows the validation messages if showValidation is passed
'
,
()
=>
{
createWrapper
({
showValidation
:
true
,
branches
:
[
'
abc
'
]
});
it
(
'
shows the validation messages if invalid on submission
'
,
async
()
=>
{
createWrapper
({
branches
:
[
'
abc
'
]
});
await
findForm
().
trigger
(
'
submit
'
);
expect
(
wrapper
.
emitted
(
'
submit
'
)).
toBe
(
undefined
);
expect
(
inputsAreValid
()).
toBe
(
false
);
expect
(
findNameValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Please provide a name.
'
);
expect
(
findBranchesValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
...
...
@@ -86,22 +96,26 @@ describe('Status checks form', () => {
expect
(
findUrlValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Please provide a valid URL.
'
);
});
it
(
'
shows the invalid URL error if the URL is unsafe
'
,
()
=>
{
it
(
'
shows the invalid URL error if the URL is unsafe
'
,
async
()
=>
{
createWrapper
({
showValidation
:
true
,
statusCheck
:
{
...
statusCheck
,
externalUrl
:
'
ftp://foo.com
'
},
});
await
findForm
().
trigger
(
'
submit
'
);
expect
(
wrapper
.
emitted
(
'
submit
'
)).
toBe
(
undefined
);
expect
(
inputsAreValid
()).
toBe
(
false
);
expect
(
findUrlValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Please provide a valid URL.
'
);
});
it
(
'
shows the serverValidationErrors if given
'
,
()
=>
{
it
(
'
shows the serverValidationErrors if given
'
,
async
()
=>
{
createWrapper
({
showValidation
:
true
,
serverValidationErrors
:
[
NAME_TAKEN_SERVER_ERROR
,
URL_TAKEN_SERVER_ERROR
],
});
await
findForm
().
trigger
(
'
submit
'
);
expect
(
wrapper
.
emitted
(
'
submit
'
)).
toBe
(
undefined
);
expect
(
inputsAreValid
()).
toBe
(
false
);
expect
(
findNameValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Name is already taken.
'
);
expect
(
findUrlValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
...
...
@@ -109,9 +123,18 @@ describe('Status checks form', () => {
);
});
it
(
'
does not show any errors if the values are valid
'
,
()
=>
{
createWrapper
({
showValidation
:
true
,
statusCheck
});
it
(
'
does not show any errors if the values are valid
'
,
async
()
=>
{
createWrapper
({
statusCheck
});
await
findForm
().
trigger
(
'
submit
'
);
expect
(
wrapper
.
emitted
(
'
submit
'
)).
toContainEqual
([
{
branches
:
statusCheck
.
protectedBranches
,
name
:
statusCheck
.
name
,
url
:
statusCheck
.
externalUrl
,
},
]);
expect
(
inputsAreValid
()).
toBe
(
true
);
});
});
...
...
@@ -131,19 +154,16 @@ describe('Status checks form', () => {
it
(
'
shows the alert
'
,
async
()
=>
{
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
false
);
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
await
nextTick
();
await
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
true
);
});
it
(
'
hides the alert if the apiError is reset
'
,
async
()
=>
{
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
await
nextTick
();
await
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
true
);
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
false
);
await
nextTick
();
await
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
false
);
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
false
);
});
...
...
ee/spec/frontend/status_checks/components/modal_create_spec.js
0 → 100644
View file @
8d3d313c
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
ModalCreate
from
'
ee/status_checks/components/modal_create.vue
'
;
import
SharedModal
from
'
ee/status_checks/components/shared_modal.vue
'
;
Vue
.
use
(
Vuex
);
const
projectId
=
'
1
'
;
const
statusChecksPath
=
'
/api/v4/projects/1/external_approval_rules
'
;
const
modalId
=
'
status-checks-create-modal
'
;
const
title
=
'
Add status check
'
;
describe
(
'
Modal create
'
,
()
=>
{
let
wrapper
;
let
store
;
const
actions
=
{
postStatusCheck
:
jest
.
fn
(),
};
const
createWrapper
=
()
=>
{
store
=
new
Vuex
.
Store
({
actions
,
state
:
{
isLoading
:
false
,
settings
:
{
projectId
,
statusChecksPath
},
statusChecks
:
[],
},
});
wrapper
=
shallowMount
(
ModalCreate
,
{
store
,
stubs
:
{
GlButton
,
},
});
wrapper
.
vm
.
$refs
.
modal
.
show
=
jest
.
fn
();
};
beforeEach
(()
=>
{
createWrapper
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
const
findAddBtn
=
()
=>
wrapper
.
findComponent
(
GlButton
);
const
findModal
=
()
=>
wrapper
.
findComponent
(
SharedModal
);
describe
(
'
Add button
'
,
()
=>
{
it
(
'
renders
'
,
()
=>
{
expect
(
findAddBtn
().
text
()).
toBe
(
'
Add status check
'
);
});
it
(
'
opens the modal
'
,
()
=>
{
findAddBtn
().
trigger
(
'
click
'
);
expect
(
wrapper
.
vm
.
$refs
.
modal
.
show
).
toHaveBeenCalled
();
});
});
describe
(
'
Modal
'
,
()
=>
{
it
(
'
sets the modals props
'
,
()
=>
{
expect
(
findModal
().
props
()).
toStrictEqual
({
action
:
expect
.
any
(
Function
),
modalId
,
title
,
statusCheck
:
undefined
,
});
});
});
});
ee/spec/frontend/status_checks/components/modal_update_spec.js
0 → 100644
View file @
8d3d313c
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
ModalUpdate
from
'
ee/status_checks/components/modal_update.vue
'
;
import
SharedModal
from
'
ee/status_checks/components/shared_modal.vue
'
;
import
{
TEST_PROTECTED_BRANCHES
}
from
'
../mock_data
'
;
Vue
.
use
(
Vuex
);
const
projectId
=
'
1
'
;
const
statusChecksPath
=
'
/api/v4/projects/1/external_approval_rules
'
;
const
modalId
=
'
status-checks-update-modal
'
;
const
title
=
'
Update status check
'
;
const
statusCheck
=
{
externalUrl
:
'
https://foo.com
'
,
id
:
1
,
name
:
'
Foo
'
,
protectedBranches
:
TEST_PROTECTED_BRANCHES
,
};
describe
(
'
Modal update
'
,
()
=>
{
let
wrapper
;
let
store
;
const
actions
=
{
putStatusCheck
:
jest
.
fn
(),
};
const
createWrapper
=
()
=>
{
store
=
new
Vuex
.
Store
({
actions
,
state
:
{
isLoading
:
false
,
settings
:
{
projectId
,
statusChecksPath
},
statusChecks
:
[],
},
});
wrapper
=
shallowMount
(
ModalUpdate
,
{
propsData
:
{
statusCheck
,
},
store
,
});
};
beforeEach
(()
=>
{
createWrapper
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
const
findModal
=
()
=>
wrapper
.
findComponent
(
SharedModal
);
describe
(
'
Modal
'
,
()
=>
{
it
(
'
sets the modals props
'
,
()
=>
{
expect
(
findModal
().
props
()).
toStrictEqual
({
action
:
expect
.
any
(
Function
),
modalId
,
title
,
statusCheck
,
});
});
});
});
ee/spec/frontend/status_checks/components/shared_modal_spec.js
0 → 100644
View file @
8d3d313c
import
{
GlButton
,
GlModal
}
from
'
@gitlab/ui
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
Form
from
'
ee/status_checks/components/form.vue
'
;
import
SharedModal
from
'
ee/status_checks/components/shared_modal.vue
'
;
import
{
EMPTY_STATUS_CHECK
}
from
'
ee/status_checks/constants
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
TEST_PROTECTED_BRANCHES
}
from
'
../mock_data
'
;
Vue
.
use
(
Vuex
);
const
projectId
=
'
1
'
;
const
statusChecksPath
=
'
/api/v4/projects/1/external_approval_rules
'
;
const
modalId
=
'
modal-id
'
;
const
title
=
'
Modal title
'
;
const
statusCheck
=
{
externalUrl
:
'
https://foo.com
'
,
id
:
1
,
name
:
'
Foo
'
,
protectedBranches
:
TEST_PROTECTED_BRANCHES
,
};
const
formData
=
{
branches
:
statusCheck
.
protectedBranches
,
name
:
statusCheck
.
name
,
url
:
statusCheck
.
externalUrl
,
};
describe
(
'
Shared modal
'
,
()
=>
{
let
wrapper
;
let
store
;
const
glModalDirective
=
jest
.
fn
();
const
action
=
jest
.
fn
();
const
createWrapper
=
(
props
=
{})
=>
{
store
=
new
Vuex
.
Store
({
state
:
{
isLoading
:
false
,
settings
:
{
projectId
,
statusChecksPath
},
statusChecks
:
[],
},
});
wrapper
=
shallowMountExtended
(
SharedModal
,
{
directives
:
{
glModal
:
{
bind
(
el
,
{
modifiers
})
{
glModalDirective
(
modifiers
);
},
},
},
propsData
:
{
action
,
modalId
,
title
,
...
props
,
},
store
,
stubs
:
{
GlButton
:
stubComponent
(
GlButton
,
{
props
:
[
'
v-gl-modal
'
,
'
loading
'
],
}),
},
});
wrapper
.
vm
.
$refs
.
modal
.
hide
=
jest
.
fn
();
wrapper
.
vm
.
$refs
.
form
.
submit
=
jest
.
fn
();
};
afterEach
(()
=>
{
wrapper
.
destroy
();
});
const
findModal
=
()
=>
wrapper
.
findComponent
(
GlModal
);
const
findForm
=
()
=>
wrapper
.
findComponent
(
Form
);
describe
(
'
Modal
'
,
()
=>
{
describe
(
'
defaults
'
,
()
=>
{
beforeEach
(()
=>
{
createWrapper
();
});
it
(
'
sets the modals props
'
,
()
=>
{
expect
(
findModal
().
props
()).
toMatchObject
({
actionPrimary
:
{
text
:
title
,
attributes
:
[{
variant
:
'
confirm
'
,
loading
:
false
}]
},
actionCancel
:
{
text
:
'
Cancel
'
},
modalId
,
size
:
'
sm
'
,
title
,
});
});
});
describe
.
each
`
given | expected
${
undefined
}
|
${
EMPTY_STATUS_CHECK
}
${
statusCheck
}
|
${
statusCheck
}
`
(
'
when the $given status check is passed
'
,
({
given
,
expected
})
=>
{
beforeEach
(()
=>
{
createWrapper
({
statusCheck
:
given
});
});
it
(
'
shows the form with the correct props
'
,
()
=>
{
expect
(
findForm
().
props
()).
toMatchObject
({
projectId
,
serverValidationErrors
:
[],
statusCheck
:
expected
,
});
});
});
});
describe
(
'
Submission
'
,
()
=>
{
describe
.
each
`
given | expected
${
undefined
}
|
${
EMPTY_STATUS_CHECK
}
${
statusCheck
}
|
${
statusCheck
}
`
(
'
when the $given status check is passed
'
,
({
given
,
expected
})
=>
{
beforeEach
(()
=>
{
createWrapper
({
statusCheck
:
given
});
});
it
(
'
submits the values and hides the modal
'
,
async
()
=>
{
await
findModal
().
vm
.
$emit
(
'
ok
'
,
{
preventDefault
:
()
=>
null
});
await
findForm
().
vm
.
$emit
(
'
submit
'
,
formData
);
await
waitForPromises
();
expect
(
wrapper
.
vm
.
$refs
.
form
.
submit
).
toHaveBeenCalled
();
expect
(
action
).
toHaveBeenCalledWith
({
externalUrl
:
formData
.
url
,
id
:
expected
?.
id
,
name
:
formData
.
name
,
protectedBranchIds
:
formData
.
branches
.
map
(({
id
})
=>
id
),
});
expect
(
wrapper
.
vm
.
$refs
.
modal
.
hide
).
toHaveBeenCalled
();
});
it
(
'
submits the values, the API fails and does not hide the modal
'
,
async
()
=>
{
const
message
=
[
'
Name has already been taken
'
];
action
.
mockRejectedValueOnce
({
response
:
{
data
:
{
message
}
},
});
await
findModal
().
vm
.
$emit
(
'
ok
'
,
{
preventDefault
:
()
=>
null
});
await
findForm
().
vm
.
$emit
(
'
submit
'
,
formData
);
await
waitForPromises
();
expect
(
wrapper
.
vm
.
$refs
.
form
.
submit
).
toHaveBeenCalled
();
expect
(
action
).
toHaveBeenCalledWith
({
externalUrl
:
formData
.
url
,
id
:
expected
?.
id
,
name
:
formData
.
name
,
protectedBranchIds
:
formData
.
branches
.
map
(({
id
})
=>
id
),
});
expect
(
wrapper
.
vm
.
$refs
.
modal
.
hide
).
not
.
toHaveBeenCalled
();
expect
(
findForm
().
props
()).
toMatchObject
({
projectId
,
serverValidationErrors
:
message
,
statusCheck
:
expected
,
});
});
});
});
});
ee/spec/frontend/status_checks/components/status_checks_spec.js
View file @
8d3d313c
import
{
Gl
Button
,
Gl
Table
}
from
'
@gitlab/ui
'
;
import
{
GlTable
}
from
'
@gitlab/ui
'
;
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
Actions
from
'
ee/status_checks/components/actions.vue
'
;
import
Branch
from
'
ee/status_checks/components/branch.vue
'
;
import
ModalCreate
from
'
ee/status_checks/components/modal_create.vue
'
;
import
ModalUpdate
from
'
ee/status_checks/components/modal_update.vue
'
;
import
StatusChecks
,
{
i18n
}
from
'
ee/status_checks/components/status_checks.vue
'
;
import
createStore
from
'
ee/status_checks/store
'
;
import
{
SET_STATUS_CHECKS
}
from
'
ee/status_checks/store/mutation_types
'
;
Vue
.
use
(
Vuex
);
const
statusChecks
=
[
{
name
:
'
Foo
'
,
externalUrl
:
'
http://foo.com/api
'
,
protectedBranches
:
[]
},
{
name
:
'
Bar
'
,
externalUrl
:
'
http://bar.com/api
'
,
protectedBranches
:
[{
name
:
'
main
'
}]
},
];
describe
(
'
Status checks
'
,
()
=>
{
let
store
;
let
wrapper
;
...
...
@@ -17,13 +24,16 @@ describe('Status checks', () => {
const
createWrapper
=
(
mountFn
=
mount
)
=>
{
store
=
createStore
();
wrapper
=
mountFn
(
StatusChecks
,
{
store
});
wrapper
.
vm
.
$refs
.
updateModal
.
show
=
jest
.
fn
();
};
afterEach
(()
=>
{
wrapper
.
destroy
();
});
const
findAddButton
=
()
=>
wrapper
.
findComponent
(
GlButton
);
const
findCreateModal
=
()
=>
wrapper
.
findComponent
(
ModalCreate
);
const
findUpdateModal
=
()
=>
wrapper
.
findComponent
(
ModalUpdate
);
const
findTable
=
()
=>
wrapper
.
findComponent
(
GlTable
);
const
findHeaders
=
()
=>
findTable
().
find
(
'
thead
'
).
find
(
'
tr
'
).
findAll
(
'
th
'
);
const
findBranch
=
(
trIdx
)
=>
wrapper
.
findAllComponents
(
Branch
).
at
(
trIdx
);
...
...
@@ -45,19 +55,20 @@ describe('Status checks', () => {
expect
(
findCell
(
0
,
0
).
text
()).
toBe
(
i18n
.
emptyTableText
);
});
it
(
'
renders the add button
'
,
()
=>
{
it
(
'
creates the create modal
'
,
()
=>
{
createWrapper
(
shallowMount
);
expect
(
find
AddButton
().
text
()).
toBe
(
i18n
.
addButton
);
expect
(
find
CreateModal
().
exists
()).
toBe
(
true
);
});
});
describe
(
'
Filled table
'
,
()
=>
{
const
statusChecks
=
[
{
name
:
'
Foo
'
,
externalUrl
:
'
http://foo.com/api
'
,
protectedBranches
:
[]
},
{
name
:
'
Bar
'
,
externalUrl
:
'
http://bar.com/api
'
,
protectedBranches
:
[{
name
:
'
main
'
}]
},
];
it
(
'
creates the update modal
'
,
()
=>
{
createWrapper
(
shallowMount
);
expect
(
findUpdateModal
().
exists
()).
toBe
(
true
);
});
});
describe
(
'
Table
'
,
()
=>
{
beforeEach
(()
=>
{
createWrapper
();
store
.
commit
(
SET_STATUS_CHECKS
,
statusChecks
);
...
...
@@ -87,8 +98,36 @@ describe('Status checks', () => {
});
it
(
'
renders the actions
'
,
()
=>
{
expect
(
findActions
(
index
,
1
).
exists
()).
toBe
(
true
);
expect
(
findActions
(
index
,
1
).
props
(
'
statusCheck
'
)).
toStrictEqual
(
statusCheck
);
});
});
});
describe
(
'
Update modal filling
'
,
()
=>
{
beforeEach
(()
=>
{
createWrapper
();
store
.
commit
(
SET_STATUS_CHECKS
,
statusChecks
);
});
it
(
'
opens the update modal with the correct status check when an edit button is clicked
'
,
async
()
=>
{
const
statusCheck
=
findActions
(
0
,
1
).
props
(
'
statusCheck
'
);
await
findActions
(
0
,
1
).
vm
.
$emit
(
'
open-update-modal
'
,
statusCheck
);
expect
(
findUpdateModal
().
props
(
'
statusCheck
'
)).
toStrictEqual
(
statusCheck
);
expect
(
wrapper
.
vm
.
$refs
.
updateModal
.
show
).
toHaveBeenCalled
();
});
it
(
'
updates the status check prop for the update modal when another edit button is clicked
'
,
async
()
=>
{
const
statusCheck
=
findActions
(
1
,
1
).
props
(
'
statusCheck
'
);
await
findActions
(
0
,
1
).
vm
.
$emit
(
'
update-status-to-check
'
,
findActions
(
0
,
1
).
props
(
'
statusCheck
'
),
);
await
findActions
(
1
,
1
).
vm
.
$emit
(
'
open-update-modal
'
,
statusCheck
);
expect
(
findUpdateModal
().
props
(
'
statusCheck
'
)).
toStrictEqual
(
statusCheck
);
});
});
});
ee/spec/frontend/status_checks/utils_spec.js
0 → 100644
View file @
8d3d313c
import
*
as
Utils
from
'
ee/status_checks/utils
'
;
describe
(
'
modalPrimaryActionProps
'
,
()
=>
{
it
(
'
returns the props with the text and loading state
'
,
()
=>
{
const
text
=
'
Button text
'
;
const
loading
=
true
;
expect
(
Utils
.
modalPrimaryActionProps
(
text
,
loading
)).
toStrictEqual
({
text
,
attributes
:
[{
variant
:
'
confirm
'
,
loading
}],
});
});
});
locale/gitlab.pot
View file @
8d3d313c
...
...
@@ -31147,6 +31147,9 @@ msgstr ""
msgid "StatusCheck|Target branch"
msgstr ""
msgid "StatusCheck|Update status check"
msgstr ""
msgid "StatusCheck|You are about to remove the %{name} status check."
msgstr ""
...
...
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