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
79b6a429
Commit
79b6a429
authored
May 20, 2021
by
Robert Hunt
Committed by
Natalia Tepluhina
May 20, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create status checks form and branch selection
parent
7daf57fa
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
702 additions
and
0 deletions
+702
-0
ee/app/assets/javascripts/status_checks/components/branches_select.vue
.../javascripts/status_checks/components/branches_select.vue
+109
-0
ee/app/assets/javascripts/status_checks/components/form.vue
ee/app/assets/javascripts/status_checks/components/form.vue
+199
-0
ee/app/assets/javascripts/status_checks/constants.js
ee/app/assets/javascripts/status_checks/constants.js
+16
-0
ee/spec/frontend/status_checks/components/branches_select_spec.js
...frontend/status_checks/components/branches_select_spec.js
+184
-0
ee/spec/frontend/status_checks/components/form_spec.js
ee/spec/frontend/status_checks/components/form_spec.js
+157
-0
ee/spec/frontend/status_checks/mock_data.js
ee/spec/frontend/status_checks/mock_data.js
+7
-0
locale/gitlab.pot
locale/gitlab.pot
+30
-0
No files found.
ee/app/assets/javascripts/status_checks/components/branches_select.vue
0 → 100644
View file @
79b6a429
<
script
>
import
{
GlDropdown
,
GlDropdownItem
,
GlSearchBoxByType
}
from
'
@gitlab/ui
'
;
import
{
debounce
}
from
'
lodash
'
;
import
Api
from
'
ee/api
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
BRANCH_FETCH_DELAY
,
ANY_BRANCH
}
from
'
../constants
'
;
export
default
{
components
:
{
GlDropdown
,
GlDropdownItem
,
GlSearchBoxByType
,
},
props
:
{
projectId
:
{
type
:
String
,
required
:
true
,
},
selectedBranches
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
isInvalid
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
branches
:
[],
initialLoading
:
false
,
searching
:
false
,
searchTerm
:
''
,
selected
:
this
.
selectedBranches
[
0
]
||
ANY_BRANCH
,
};
},
mounted
()
{
this
.
initialLoading
=
true
;
this
.
fetchBranches
()
// Errors are handled by fetchBranches
.
catch
(()
=>
{})
.
finally
(()
=>
{
this
.
initialLoading
=
false
;
});
},
methods
:
{
fetchBranches
(
term
)
{
this
.
searching
=
true
;
const
excludeAnyBranch
=
term
&&
!
term
.
toLowerCase
().
includes
(
'
any
'
);
return
Api
.
projectProtectedBranches
(
this
.
projectId
,
term
)
.
then
((
branches
)
=>
{
this
.
$emit
(
'
apiError
'
,
false
);
this
.
branches
=
excludeAnyBranch
?
branches
:
[
ANY_BRANCH
,
...
branches
];
})
.
catch
((
error
)
=>
{
this
.
$emit
(
'
apiError
'
,
true
,
error
);
this
.
branches
=
excludeAnyBranch
?
[]
:
[
ANY_BRANCH
];
})
.
finally
(()
=>
{
this
.
searching
=
false
;
});
},
search
:
debounce
(
function
debouncedSearch
()
{
this
.
fetchBranches
(
this
.
searchTerm
);
},
BRANCH_FETCH_DELAY
),
isSelectedBranch
(
id
)
{
return
this
.
selected
.
id
===
id
;
},
onSelect
(
branch
)
{
this
.
selected
=
branch
;
this
.
$emit
(
'
input
'
,
branch
);
},
branchNameClass
(
id
)
{
return
{
monospace
:
id
!==
null
,
};
},
},
i18n
:
{
header
:
__
(
'
Select branch
'
),
},
};
</
script
>
<
template
>
<gl-dropdown
:class=
"
{ 'is-invalid': isInvalid }"
class="gl-w-full gl-dropdown-menu-full-width"
:text="selected.name"
:loading="initialLoading"
:header-text="$options.i18n.header"
>
<template
#header
>
<gl-search-box-by-type
v-model=
"searchTerm"
:is-loading=
"searching"
@
input=
"search"
/>
</
template
>
<gl-dropdown-item
v-for=
"branch in branches"
:key=
"branch.id"
:is-check-item=
"true"
:is-checked=
"isSelectedBranch(branch.id)"
@
click=
"onSelect(branch)"
>
<span
:class=
"branchNameClass(branch.id)"
>
{{ branch.name }}
</span>
</gl-dropdown-item>
</gl-dropdown>
</template>
ee/app/assets/javascripts/status_checks/components/form.vue
0 → 100644
View file @
79b6a429
<
script
>
import
{
GlAlert
,
GlFormGroup
,
GlFormInput
}
from
'
@gitlab/ui
'
;
import
*
as
Sentry
from
'
@sentry/browser
'
;
import
{
isEqual
,
isNumber
}
from
'
lodash
'
;
import
{
isSafeURL
}
from
'
~/lib/utils/url_utility
'
;
import
{
__
,
s__
}
from
'
~/locale
'
;
import
{
ANY_BRANCH
,
EMPTY_STATUS_CHECK
,
NAME_TAKEN_SERVER_ERROR
,
URL_TAKEN_SERVER_ERROR
,
}
from
'
../constants
'
;
import
BranchesSelect
from
'
./branches_select.vue
'
;
export
default
{
components
:
{
BranchesSelect
,
GlAlert
,
GlFormGroup
,
GlFormInput
,
},
props
:
{
projectId
:
{
type
:
String
,
required
:
true
,
},
serverValidationErrors
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
showValidation
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
statusCheck
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
EMPTY_STATUS_CHECK
,
},
},
data
()
{
const
{
protectedBranches
,
name
,
externalUrl
:
url
}
=
this
.
statusCheck
;
return
{
branches
:
protectedBranches
,
branchesToAdd
:
[],
branchesApiFailed
:
false
,
name
,
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
);
},
branchesState
()
{
return
!
this
.
showValidation
||
this
.
isValidBranches
;
},
nameState
()
{
return
(
!
this
.
showValidation
||
(
this
.
isValidName
&&
!
this
.
serverValidationErrors
.
includes
(
NAME_TAKEN_SERVER_ERROR
))
);
},
urlState
()
{
return
(
!
this
.
showValidation
||
(
this
.
isValidUrl
&&
!
this
.
serverValidationErrors
.
includes
(
URL_TAKEN_SERVER_ERROR
))
);
},
invalidNameMessage
()
{
if
(
this
.
serverValidationErrors
.
includes
(
NAME_TAKEN_SERVER_ERROR
))
{
return
this
.
$options
.
i18n
.
validations
.
nameTaken
;
}
return
this
.
$options
.
i18n
.
validations
.
nameMissing
;
},
invalidUrlMessage
()
{
if
(
this
.
serverValidationErrors
.
includes
(
URL_TAKEN_SERVER_ERROR
))
{
return
this
.
$options
.
i18n
.
validations
.
urlTaken
;
}
return
this
.
$options
.
i18n
.
validations
.
invalidUrl
;
},
},
watch
:
{
branchesToAdd
(
value
)
{
this
.
branches
=
value
?
[
value
]
:
[];
},
},
methods
:
{
setBranchApiError
(
hasErrored
,
error
)
{
if
(
!
this
.
branchesApiFailed
&&
error
)
{
Sentry
.
captureException
(
error
);
}
this
.
branchesApiFailed
=
hasErrored
;
},
},
i18n
:
{
form
:
{
addStatusChecks
:
s__
(
'
StatusCheck|API to check
'
),
statusChecks
:
s__
(
'
StatusCheck|Status to check
'
),
statusChecksDescription
:
s__
(
'
StatusCheck|Invoke an external API as part of the pipeline process.
'
,
),
nameLabel
:
s__
(
'
StatusCheck|Service name
'
),
nameDescription
:
s__
(
'
StatusCheck|Examples: QA, Security.
'
),
protectedBranchLabel
:
s__
(
'
StatusCheck|Target branch
'
),
protectedBranchDescription
:
s__
(
'
StatusCheck|Apply this status check to any branch or a specific protected branch.
'
,
),
},
validations
:
{
branchesRequired
:
__
(
'
Please select a valid target branch.
'
),
branchesApiFailure
:
__
(
'
Unable to fetch branches list, please close the form and try again
'
),
nameTaken
:
__
(
'
Name is already taken.
'
),
nameMissing
:
__
(
'
Please provide a name.
'
),
urlTaken
:
s__
(
'
StatusCheck|External API is already in use by another status check.
'
),
invalidUrl
:
__
(
'
Please provide a valid URL.
'
),
},
},
};
</
script
>
<
template
>
<div>
<gl-alert
v-if=
"branchesApiFailed"
class=
"gl-mb-5"
:dismissible=
"false"
variant=
"danger"
>
{{
$options
.
i18n
.
validations
.
branchesApiFailure
}}
</gl-alert>
<form
novalidate
>
<gl-form-group
:label=
"$options.i18n.form.nameLabel"
:description=
"$options.i18n.form.nameDescription"
:state=
"nameState"
:invalid-feedback=
"invalidNameMessage"
data-testid=
"name-group"
>
<gl-form-input
v-model=
"name"
:state=
"nameState"
data-qa-selector=
"rule_name_field"
data-testid=
"name"
/>
</gl-form-group>
<gl-form-group
:label=
"$options.i18n.form.addStatusChecks"
:description=
"$options.i18n.form.statusChecksDescription"
:state=
"urlState"
:invalid-feedback=
"invalidUrlMessage"
data-testid=
"url-group"
>
<gl-form-input
v-model=
"url"
:state=
"urlState"
type=
"url"
:placeholder=
"`https://api.gitlab.com/`"
data-qa-selector=
"external_url_field"
data-testid=
"url"
/>
</gl-form-group>
<gl-form-group
:label=
"$options.i18n.form.protectedBranchLabel"
:description=
"$options.i18n.form.protectedBranchDescription"
:state=
"branchesState"
:invalid-feedback=
"$options.i18n.validations.branchesRequired"
data-testid=
"branches-group"
>
<branches-select
v-model=
"branchesToAdd"
:project-id=
"projectId"
:is-invalid=
"!branchesState"
:selected-branches=
"branches"
@
apiError=
"setBranchApiError"
/>
</gl-form-group>
</form>
</div>
</
template
>
ee/app/assets/javascripts/status_checks/constants.js
0 → 100644
View file @
79b6a429
import
{
__
}
from
'
~/locale
'
;
export
const
BRANCH_FETCH_DELAY
=
250
;
export
const
ANY_BRANCH
=
{
id
:
null
,
name
:
__
(
'
Any branch
'
),
};
export
const
EMPTY_STATUS_CHECK
=
{
name
:
''
,
protectedBranches
:
[],
url
:
''
,
};
export
const
URL_TAKEN_SERVER_ERROR
=
'
External url has already been taken
'
;
export
const
NAME_TAKEN_SERVER_ERROR
=
'
Name has already been taken
'
;
ee/spec/frontend/status_checks/components/branches_select_spec.js
0 → 100644
View file @
79b6a429
import
{
GlDropdown
,
GlDropdownItem
,
GlSearchBoxByType
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
mount
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
Api
from
'
ee/api
'
;
import
BranchesSelect
from
'
ee/status_checks/components/branches_select.vue
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
TEST_DEFAULT_BRANCH
,
TEST_BRANCHES_SELECTIONS
,
TEST_PROJECT_ID
,
TEST_PROTECTED_BRANCHES
,
}
from
'
../mock_data
'
;
const
branchNames
=
()
=>
TEST_BRANCHES_SELECTIONS
.
map
((
branch
)
=>
branch
.
name
);
const
protectedBranchNames
=
()
=>
TEST_PROTECTED_BRANCHES
.
map
((
branch
)
=>
branch
.
name
);
const
error
=
new
Error
(
'
Something went wrong
'
);
describe
(
'
Branches Select
'
,
()
=>
{
let
wrapper
;
const
findDropdown
=
()
=>
wrapper
.
findComponent
(
GlDropdown
);
const
findDropdownItems
=
()
=>
wrapper
.
findAllComponents
(
GlDropdownItem
);
const
findSearch
=
()
=>
wrapper
.
findComponent
(
GlSearchBoxByType
);
const
createComponent
=
(
props
=
{},
mountFn
=
shallowMount
)
=>
{
wrapper
=
mountFn
(
BranchesSelect
,
{
propsData
:
{
projectId
:
'
1
'
,
...
props
,
},
});
};
beforeEach
(()
=>
{
jest
.
spyOn
(
Api
,
'
projectProtectedBranches
'
)
.
mockReturnValue
(
Promise
.
resolve
(
TEST_PROTECTED_BRANCHES
));
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
Initialization
'
,
()
=>
{
it
(
'
renders dropdown
'
,
async
()
=>
{
createComponent
();
await
waitForPromises
();
expect
(
findDropdown
().
exists
()).
toBe
(
true
);
});
it
(
'
renders dropdown with invalid class if is invalid
'
,
async
()
=>
{
createComponent
({
isInvalid
:
true
});
await
waitForPromises
();
expect
(
findDropdown
().
classes
(
'
is-invalid
'
)).
toBe
(
true
);
});
it
(
'
sets the initially selected item
'
,
async
()
=>
{
createComponent
({
selectedBranches
:
[
{
id
:
1
,
name
:
'
main
'
,
},
],
});
await
waitForPromises
();
expect
(
findDropdown
().
props
(
'
text
'
)).
toBe
(
'
main
'
);
expect
(
findDropdownItems
()
.
filter
((
item
)
=>
item
.
text
()
===
'
main
'
)
.
at
(
0
)
.
props
(
'
isChecked
'
),
).
toBe
(
true
);
});
it
(
'
displays all the protected branches and any branch
'
,
async
()
=>
{
createComponent
();
await
nextTick
();
expect
(
findDropdown
().
props
(
'
loading
'
)).
toBe
(
true
);
await
waitForPromises
();
expect
(
wrapper
.
emitted
().
apiError
).
toStrictEqual
([[
false
]]);
expect
(
findDropdownItems
()).
toHaveLength
(
branchNames
().
length
);
expect
(
findDropdown
().
props
(
'
loading
'
)).
toBe
(
false
);
});
describe
(
'
when fetching the branch list fails
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
Api
,
'
projectProtectedBranches
'
).
mockRejectedValueOnce
(
error
);
createComponent
({});
});
it
(
'
emits the `apiError` event
'
,
()
=>
{
expect
(
wrapper
.
emitted
().
apiError
).
toStrictEqual
([[
true
,
error
]]);
});
it
(
'
returns just the any branch dropdown items
'
,
()
=>
{
expect
(
findDropdownItems
()).
toHaveLength
(
1
);
expect
(
findDropdownItems
().
at
(
0
).
text
()).
toBe
(
TEST_DEFAULT_BRANCH
.
name
);
});
});
});
describe
(
'
with search term
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({},
mount
);
return
waitForPromises
();
});
it
(
'
fetches protected branches with search term
'
,
async
()
=>
{
const
term
=
'
lorem
'
;
findSearch
().
vm
.
$emit
(
'
input
'
,
term
);
await
nextTick
();
expect
(
findSearch
().
props
(
'
isLoading
'
)).
toBe
(
true
);
await
waitForPromises
();
expect
(
Api
.
projectProtectedBranches
).
toHaveBeenCalledWith
(
TEST_PROJECT_ID
,
term
);
expect
(
wrapper
.
emitted
().
apiError
).
toStrictEqual
([[
false
],
[
false
]]);
expect
(
findSearch
().
props
(
'
isLoading
'
)).
toBe
(
false
);
});
it
(
'
fetches protected branches with no any branch if there is a search
'
,
async
()
=>
{
findSearch
().
vm
.
$emit
(
'
input
'
,
'
main
'
);
await
waitForPromises
();
expect
(
findDropdownItems
()).
toHaveLength
(
protectedBranchNames
().
length
);
});
it
(
'
fetches protected branches with any branch if search contains term "any"
'
,
async
()
=>
{
findSearch
().
vm
.
$emit
(
'
input
'
,
'
any
'
);
await
waitForPromises
();
expect
(
findDropdownItems
()).
toHaveLength
(
branchNames
().
length
);
});
describe
(
'
when fetching the branch list fails while searching
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
Api
,
'
projectProtectedBranches
'
).
mockRejectedValueOnce
(
error
);
findSearch
().
vm
.
$emit
(
'
input
'
,
'
main
'
);
return
waitForPromises
();
});
it
(
'
emits the `apiError` event
'
,
()
=>
{
expect
(
wrapper
.
emitted
().
apiError
).
toStrictEqual
([[
false
],
[
true
,
error
]]);
});
it
(
'
returns no dropdown items
'
,
()
=>
{
expect
(
findDropdownItems
()).
toHaveLength
(
0
);
});
});
describe
(
'
when fetching the branch list fails while searching for the term "any"
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
Api
,
'
projectProtectedBranches
'
).
mockRejectedValueOnce
(
error
);
findSearch
().
vm
.
$emit
(
'
input
'
,
'
any
'
);
return
waitForPromises
();
});
it
(
'
emits the `apiError` event
'
,
()
=>
{
expect
(
wrapper
.
emitted
().
apiError
).
toStrictEqual
([[
false
],
[
true
,
error
]]);
});
it
(
'
returns just the any branch dropdown item
'
,
()
=>
{
expect
(
findDropdownItems
()).
toHaveLength
(
1
);
expect
(
findDropdownItems
().
at
(
0
).
text
()).
toBe
(
TEST_DEFAULT_BRANCH
.
name
);
});
});
});
it
(
'
when the branch is changed it sets the isChecked property and emits the input event
'
,
async
()
=>
{
createComponent
();
await
waitForPromises
();
await
findDropdownItems
().
at
(
1
).
vm
.
$emit
(
'
click
'
);
expect
(
findDropdownItems
().
at
(
1
).
props
(
'
isChecked
'
)).
toBe
(
true
);
expect
(
wrapper
.
emitted
().
input
).
toStrictEqual
([[
TEST_PROTECTED_BRANCHES
[
0
]]]);
});
});
ee/spec/frontend/status_checks/components/form_spec.js
0 → 100644
View file @
79b6a429
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
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
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
'
,
};
const
sentryError
=
new
Error
(
'
Network error
'
);
describe
(
'
Status checks form
'
,
()
=>
{
let
wrapper
;
const
createWrapper
=
(
props
=
{})
=>
{
wrapper
=
shallowMountExtended
(
Form
,
{
propsData
:
{
projectId
,
...
props
},
stubs
:
{
GlFormGroup
:
stubComponent
(
GlFormGroup
,
{
props
:
[
'
state
'
,
'
invalidFeedback
'
],
}),
GlFormInput
:
stubComponent
(
GlFormInput
,
{
props
:
[
'
state
'
,
'
disabled
'
,
'
value
'
],
template
:
`<input />`
,
}),
},
});
};
const
findNameInput
=
()
=>
wrapper
.
findByTestId
(
'
name
'
);
const
findNameValidation
=
()
=>
wrapper
.
findByTestId
(
'
name-group
'
);
const
findBranchesSelect
=
()
=>
wrapper
.
findComponent
(
BranchesSelect
);
const
findUrlInput
=
()
=>
wrapper
.
findByTestId
(
'
url
'
);
const
findUrlValidation
=
()
=>
wrapper
.
findByTestId
(
'
url-group
'
);
const
findBranchesValidation
=
()
=>
wrapper
.
findByTestId
(
'
branches-group
'
);
const
findBranchesErrorAlert
=
()
=>
wrapper
.
findComponent
(
GlAlert
);
const
findValidations
=
()
=>
[
findNameValidation
(),
findUrlValidation
(),
findBranchesValidation
(),
];
const
inputsAreValid
=
()
=>
findValidations
().
every
((
x
)
=>
x
.
props
(
'
state
'
));
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
initialization
'
,
()
=>
{
it
(
'
shows empty inputs when no initial data is given
'
,
()
=>
{
createWrapper
();
expect
(
inputsAreValid
()).
toBe
(
true
);
expect
(
findNameInput
().
props
(
'
value
'
)).
toBe
(
''
);
expect
(
findBranchesSelect
().
props
(
'
selectedBranches
'
)).
toStrictEqual
([]);
expect
(
findUrlInput
().
props
(
'
value
'
)).
toBe
(
undefined
);
});
it
(
'
shows filled inputs when initial data is given
'
,
()
=>
{
createWrapper
({
statusCheck
});
expect
(
inputsAreValid
()).
toBe
(
true
);
expect
(
findNameInput
().
props
(
'
value
'
)).
toBe
(
statusCheck
.
name
);
expect
(
findBranchesSelect
().
props
(
'
selectedBranches
'
)).
toStrictEqual
(
statusCheck
.
branches
);
expect
(
findUrlInput
().
props
(
'
value
'
)).
toBe
(
statusCheck
.
externalUrl
);
});
});
describe
(
'
Validation
'
,
()
=>
{
it
(
'
shows the validation messages if showValidation is passed
'
,
()
=>
{
createWrapper
({
showValidation
:
true
,
branches
:
[
'
abc
'
]
});
expect
(
inputsAreValid
()).
toBe
(
false
);
expect
(
findNameValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Please provide a name.
'
);
expect
(
findBranchesValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Please select a valid target branch.
'
,
);
expect
(
findUrlValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Please provide a valid URL.
'
);
});
it
(
'
shows the invalid URL error if the URL is unsafe
'
,
()
=>
{
createWrapper
({
showValidation
:
true
,
statusCheck
:
{
...
statusCheck
,
externalUrl
:
'
ftp://foo.com
'
},
});
expect
(
inputsAreValid
()).
toBe
(
false
);
expect
(
findUrlValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Please provide a valid URL.
'
);
});
it
(
'
shows the serverValidationErrors if given
'
,
()
=>
{
createWrapper
({
showValidation
:
true
,
serverValidationErrors
:
[
NAME_TAKEN_SERVER_ERROR
,
URL_TAKEN_SERVER_ERROR
],
});
expect
(
inputsAreValid
()).
toBe
(
false
);
expect
(
findNameValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
Name is already taken.
'
);
expect
(
findUrlValidation
().
props
(
'
invalidFeedback
'
)).
toBe
(
'
External API is already in use by another status check.
'
,
);
});
it
(
'
does not show any errors if the values are valid
'
,
()
=>
{
createWrapper
({
showValidation
:
true
,
statusCheck
});
expect
(
inputsAreValid
()).
toBe
(
true
);
});
});
describe
(
'
Branches error alert
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
Sentry
,
'
captureException
'
);
createWrapper
();
});
it
(
'
sends the error to sentry
'
,
()
=>
{
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
expect
(
Sentry
.
captureException
.
mock
.
calls
[
0
][
0
]).
toStrictEqual
(
sentryError
);
});
it
(
'
shows the alert
'
,
async
()
=>
{
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
false
);
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
await
nextTick
();
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
true
);
});
it
(
'
hides the alert if the apiError is reset
'
,
async
()
=>
{
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
await
nextTick
();
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
true
);
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
false
);
await
nextTick
();
expect
(
findBranchesErrorAlert
().
exists
()).
toBe
(
false
);
});
it
(
'
only calls sentry once while the branches api is failing
'
,
()
=>
{
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
findBranchesSelect
().
vm
.
$emit
(
'
apiError
'
,
true
,
sentryError
);
expect
(
Sentry
.
captureException
.
mock
.
calls
).
toEqual
([[
sentryError
]]);
});
});
});
ee/spec/frontend/status_checks/mock_data.js
0 → 100644
View file @
79b6a429
export
const
TEST_DEFAULT_BRANCH
=
{
name
:
'
Any branch
'
};
export
const
TEST_PROJECT_ID
=
'
1
'
;
export
const
TEST_PROTECTED_BRANCHES
=
[
{
id
:
1
,
name
:
'
main
'
},
{
id
:
2
,
name
:
'
development
'
},
];
export
const
TEST_BRANCHES_SELECTIONS
=
[
TEST_DEFAULT_BRANCH
,
...
TEST_PROTECTED_BRANCHES
];
locale/gitlab.pot
View file @
79b6a429
...
...
@@ -21619,6 +21619,9 @@ msgstr ""
msgid "Name has already been taken"
msgstr ""
msgid "Name is already taken."
msgstr ""
msgid "Name new label"
msgstr ""
...
...
@@ -24633,12 +24636,18 @@ msgstr ""
msgid "Please provide a name"
msgstr ""
msgid "Please provide a name."
msgstr ""
msgid "Please provide a valid URL"
msgstr ""
msgid "Please provide a valid URL ending with .git"
msgstr ""
msgid "Please provide a valid URL."
msgstr ""
msgid "Please provide a valid YouTube URL or ID"
msgstr ""
...
...
@@ -24675,6 +24684,9 @@ msgstr ""
msgid "Please select a valid target branch"
msgstr ""
msgid "Please select a valid target branch."
msgstr ""
msgid "Please select and add a member"
msgstr ""
...
...
@@ -31045,12 +31057,24 @@ msgstr ""
msgid "StatusCheck|An error occurred fetching the status checks."
msgstr ""
msgid "StatusCheck|Apply this status check to any branch or a specific protected branch."
msgstr ""
msgid "StatusCheck|Check for a status response in Merge Requests. Failures do not block merges. %{link_start}Learn more%{link_end}."
msgstr ""
msgid "StatusCheck|Examples: QA, Security."
msgstr ""
msgid "StatusCheck|External API is already in use by another status check."
msgstr ""
msgid "StatusCheck|Invoke an external API as part of the approvals"
msgstr ""
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
msgid "StatusCheck|No status checks are defined yet."
msgstr ""
...
...
@@ -31069,6 +31093,9 @@ msgstr ""
msgid "StatusCheck|Status to check"
msgstr ""
msgid "StatusCheck|Target branch"
msgstr ""
msgid "StatusCheck|You are about to remove the %{name} status check."
msgstr ""
...
...
@@ -34609,6 +34636,9 @@ msgstr ""
msgid "Unable to fetch branch list for this project."
msgstr ""
msgid "Unable to fetch branches list, please close the form and try again"
msgstr ""
msgid "Unable to fetch unscanned projects"
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