Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f8bb64721a
commit
bbede1e22c
|
@ -1,13 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
import { mapActions } from 'vuex';
|
import { mapActions } from 'vuex';
|
||||||
import { GlBadge } from '@gitlab/ui';
|
import { GlBadge, GlSprintf } from '@gitlab/ui';
|
||||||
import { n__ } from '~/locale';
|
|
||||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TestIssueBody',
|
name: 'TestIssueBody',
|
||||||
components: {
|
components: {
|
||||||
GlBadge,
|
GlBadge,
|
||||||
|
GlSprintf,
|
||||||
},
|
},
|
||||||
mixins: [glFeatureFlagsMixin()],
|
mixins: [glFeatureFlagsMixin()],
|
||||||
props: {
|
props: {
|
||||||
|
@ -28,18 +28,15 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showRecentFailures() {
|
showRecentFailures() {
|
||||||
return this.glFeatures.testFailureHistory && this.issue.recent_failures;
|
return (
|
||||||
|
this.glFeatures.testFailureHistory &&
|
||||||
|
this.issue.recent_failures?.count &&
|
||||||
|
this.issue.recent_failures?.base_branch
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['openModal']),
|
...mapActions(['openModal']),
|
||||||
recentFailuresText(count) {
|
|
||||||
return n__(
|
|
||||||
'Failed %d time in the last 14 days',
|
|
||||||
'Failed %d times in the last 14 days',
|
|
||||||
count,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -53,7 +50,18 @@ export default {
|
||||||
>
|
>
|
||||||
<gl-badge v-if="isNew" variant="danger" class="gl-mr-2">{{ s__('New') }}</gl-badge>
|
<gl-badge v-if="isNew" variant="danger" class="gl-mr-2">{{ s__('New') }}</gl-badge>
|
||||||
<gl-badge v-if="showRecentFailures" variant="warning" class="gl-mr-2">
|
<gl-badge v-if="showRecentFailures" variant="warning" class="gl-mr-2">
|
||||||
{{ recentFailuresText(issue.recent_failures) }}
|
<gl-sprintf
|
||||||
|
:message="
|
||||||
|
n__(
|
||||||
|
'Reports|Failed %{count} time in %{base_branch} in the last 14 days',
|
||||||
|
'Reports|Failed %{count} times in %{base_branch} in the last 14 days',
|
||||||
|
issue.recent_failures.count,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #count>{{ issue.recent_failures.count }}</template>
|
||||||
|
<template #base_branch>{{ issue.recent_failures.base_branch }}</template>
|
||||||
|
</gl-sprintf>
|
||||||
</gl-badge>
|
</gl-badge>
|
||||||
{{ issue.name }}
|
{{ issue.name }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -62,12 +62,8 @@ export const recentFailuresTextBuilder = (summary = {}) => {
|
||||||
}
|
}
|
||||||
return sprintf(
|
return sprintf(
|
||||||
n__(
|
n__(
|
||||||
s__(
|
'Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days',
|
||||||
'Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days',
|
'Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days',
|
||||||
),
|
|
||||||
s__(
|
|
||||||
'Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days',
|
|
||||||
),
|
|
||||||
recentlyFailed,
|
recentlyFailed,
|
||||||
),
|
),
|
||||||
{ recentlyFailed, failed },
|
{ recentlyFailed, failed },
|
||||||
|
@ -83,7 +79,10 @@ export const countRecentlyFailedTests = subject => {
|
||||||
return (
|
return (
|
||||||
[report.new_failures, report.existing_failures, report.resolved_failures]
|
[report.new_failures, report.existing_failures, report.resolved_failures]
|
||||||
// only count tests which have failed more than once
|
// only count tests which have failed more than once
|
||||||
.map(failureArray => failureArray.filter(failure => failure.recent_failures > 1).length)
|
.map(
|
||||||
|
failureArray =>
|
||||||
|
failureArray.filter(failure => failure.recent_failures?.count > 1).length,
|
||||||
|
)
|
||||||
.reduce((total, count) => total + count, 0)
|
.reduce((total, count) => total + count, 0)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
|
@ -94,7 +94,13 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<gl-modal modal-id="modal-merge-info" :title="$options.i18n.title" no-fade hide-footer>
|
<gl-modal
|
||||||
|
modal-id="modal-merge-info"
|
||||||
|
:no-enforce-focus="true"
|
||||||
|
:title="$options.i18n.title"
|
||||||
|
no-fade
|
||||||
|
hide-footer
|
||||||
|
>
|
||||||
<p>
|
<p>
|
||||||
<strong>
|
<strong>
|
||||||
{{ $options.i18n.steps.step1.label }}
|
{{ $options.i18n.steps.step1.label }}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
= _("When enabled, any user visiting %{host} will be able to create an account.") % { host: "#{new_user_session_url(host: Gitlab.config.gitlab.host)}" }
|
= _("When enabled, any user visiting %{host} will be able to create an account.") % { host: "#{new_user_session_url(host: Gitlab.config.gitlab.host)}" }
|
||||||
.form-group
|
.form-group
|
||||||
.form-check
|
.form-check
|
||||||
= f.check_box :require_admin_approval_after_user_signup, class: 'form-check-input'
|
= f.check_box :require_admin_approval_after_user_signup, class: 'form-check-input', data: { qa_selector: 'require_admin_approval_after_user_signup_checkbox' }
|
||||||
= f.label :require_admin_approval_after_user_signup, class: 'form-check-label' do
|
= f.label :require_admin_approval_after_user_signup, class: 'form-check-label' do
|
||||||
= _('Require admin approval for new sign-ups')
|
= _('Require admin approval for new sign-ups')
|
||||||
.form-text.text-muted
|
.form-text.text-muted
|
||||||
|
@ -77,4 +77,4 @@
|
||||||
= f.label :after_sign_up_text, class: 'label-bold'
|
= f.label :after_sign_up_text, class: 'label-bold'
|
||||||
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
|
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
|
||||||
.form-text.text-muted Markdown enabled
|
.form-text.text-muted Markdown enabled
|
||||||
= f.submit 'Save changes', class: "gl-button btn btn-success"
|
= f.submit 'Save changes', class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
.settings-content
|
.settings-content
|
||||||
= render 'diff_limits'
|
= render 'diff_limits'
|
||||||
|
|
||||||
%section.settings.as-signup.no-animate#js-signup-settings{ class: ('expanded' if expanded_by_default?) }
|
%section.settings.as-signup.no-animate#js-signup-settings{ class: ('expanded' if expanded_by_default?), data: { qa_selector: 'sign_up_restrictions_settings_content' } }
|
||||||
.settings-header
|
.settings-header
|
||||||
%h4
|
%h4
|
||||||
= _('Sign-up restrictions')
|
= _('Sign-up restrictions')
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
.card-body
|
.card-body
|
||||||
= render partial: 'admin/users/user_approve_effects'
|
= render partial: 'admin/users/user_approve_effects'
|
||||||
%br
|
%br
|
||||||
= link_to s_('AdminUsers|Approve user'), approve_admin_user_path(user), method: :put, class: "btn gl-button btn-info", data: { confirm: s_('AdminUsers|Are you sure?') }
|
= link_to s_('AdminUsers|Approve user'), approve_admin_user_path(user), method: :put, class: "btn gl-button btn-info", data: { confirm: s_('AdminUsers|Are you sure?'), qa_selector: 'approve_user_button' }
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
= s_('AdminUsers|Blocked')
|
= s_('AdminUsers|Blocked')
|
||||||
%small.badge.badge-pill= limited_counter_with_delimiter(User.blocked)
|
%small.badge.badge-pill= limited_counter_with_delimiter(User.blocked)
|
||||||
= nav_link(html_options: { class: "#{active_when(params[:filter] == 'blocked_pending_approval')} filter-blocked-pending-approval" }) do
|
= nav_link(html_options: { class: "#{active_when(params[:filter] == 'blocked_pending_approval')} filter-blocked-pending-approval" }) do
|
||||||
= link_to admin_users_path(filter: "blocked_pending_approval") do
|
= link_to admin_users_path(filter: "blocked_pending_approval"), data: { qa_selector: 'pending_approval_tab' } do
|
||||||
= s_('AdminUsers|Pending approval')
|
= s_('AdminUsers|Pending approval')
|
||||||
%small.badge.badge-pill= limited_counter_with_delimiter(User.blocked_pending_approval)
|
%small.badge.badge-pill= limited_counter_with_delimiter(User.blocked_pending_approval)
|
||||||
= nav_link(html_options: { class: active_when(params[:filter] == 'deactivated') }) do
|
= nav_link(html_options: { class: active_when(params[:filter] == 'deactivated') }) do
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
= sprite_icon('close', size: 16, css_class: 'gl-icon')
|
= sprite_icon('close', size: 16, css_class: 'gl-icon')
|
||||||
%li
|
%li
|
||||||
%span.light ID:
|
%span.light ID:
|
||||||
%strong
|
%strong{ data: { qa_selector: 'user_id_content' } }
|
||||||
= @user.id
|
= @user.id
|
||||||
%li
|
%li
|
||||||
%span.light= _('Namespace ID:')
|
%span.light= _('Namespace ID:')
|
||||||
|
|
|
@ -8,6 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30213) in GitLab 12.1.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30213) in GitLab 12.1.
|
||||||
|
|
||||||
|
Similar to [project-level](../user/project/clusters/index.md) and
|
||||||
|
[instance-level](../user/instance/clusters/index.md) Kubernetes clusters,
|
||||||
|
group-level Kubernetes clusters allow you to connect a Kubernetes cluster to
|
||||||
|
your group, enabling you to use the same cluster across multiple projects.
|
||||||
|
|
||||||
Users need at least [Maintainer](../user/permissions.md) access for the group to use these endpoints.
|
Users need at least [Maintainer](../user/permissions.md) access for the group to use these endpoints.
|
||||||
|
|
||||||
## List group clusters
|
## List group clusters
|
||||||
|
|
|
@ -301,9 +301,9 @@ Be aware that:
|
||||||
be deducted from your Additional Minutes quota immediately after your purchase of additional
|
be deducted from your Additional Minutes quota immediately after your purchase of additional
|
||||||
minutes.
|
minutes.
|
||||||
|
|
||||||
## Customers portal
|
## Customers Portal
|
||||||
|
|
||||||
GitLab provides a [customer portal](../index.md#customers-portal) where you can
|
GitLab provides the [Customers Portal](../index.md#customers-portal) where you can
|
||||||
manage your subscriptions and your account details.
|
manage your subscriptions and your account details.
|
||||||
|
|
||||||
## Contact Support
|
## Contact Support
|
||||||
|
|
|
@ -77,7 +77,7 @@ With the [Customers Portal](https://customers.gitlab.com/) you can:
|
||||||
- [Change your payment method](#change-your-payment-method)
|
- [Change your payment method](#change-your-payment-method)
|
||||||
- [Change the linked account](#change-the-linked-account)
|
- [Change the linked account](#change-the-linked-account)
|
||||||
- [Change the associated namespace](#change-the-associated-namespace)
|
- [Change the associated namespace](#change-the-associated-namespace)
|
||||||
- [Change customers portal account password](#change-customer-portal-account-password)
|
- [Change customers portal account password](#change-customers-portal-account-password)
|
||||||
|
|
||||||
### Change your personal details
|
### Change your personal details
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ With a linked GitLab.com account:
|
||||||
|
|
||||||
Subscription charges are calculated based on the total number of users in a group, including its subgroups and nested projects. If the total number of users exceeds the number of seats in your subscription, your account is charged for the additional users.
|
Subscription charges are calculated based on the total number of users in a group, including its subgroups and nested projects. If the total number of users exceeds the number of seats in your subscription, your account is charged for the additional users.
|
||||||
|
|
||||||
### Change customer portal account password
|
### Change Customers Portal account password
|
||||||
|
|
||||||
To change the password for this customers portal account:
|
To change the password for this customers portal account:
|
||||||
|
|
||||||
|
|
|
@ -315,9 +315,9 @@ only.
|
||||||
However, if you remove the license, you immediately revert to Core
|
However, if you remove the license, you immediately revert to Core
|
||||||
features, and the instance become read / write again.
|
features, and the instance become read / write again.
|
||||||
|
|
||||||
## Customers portal
|
## Customers Portal
|
||||||
|
|
||||||
GitLab provides a [customer portal](../index.md#customers-portal) where you can
|
GitLab provides the [Customers Portal](../index.md#customers-portal) where you can
|
||||||
manage your subscriptions and your account details.
|
manage your subscriptions and your account details.
|
||||||
|
|
||||||
## Contact Support
|
## Contact Support
|
||||||
|
|
|
@ -11375,11 +11375,6 @@ msgstr ""
|
||||||
msgid "Failed"
|
msgid "Failed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed %d time in the last 14 days"
|
|
||||||
msgid_plural "Failed %d times in the last 14 days"
|
|
||||||
msgstr[0] ""
|
|
||||||
msgstr[1] ""
|
|
||||||
|
|
||||||
msgid "Failed Jobs"
|
msgid "Failed Jobs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -22939,10 +22934,9 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed test has failed more th
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days"
|
msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days"
|
||||||
msgstr ""
|
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
|
||||||
|
msgstr[0] ""
|
||||||
msgid "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
|
msgstr[1] ""
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
|
msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
|
||||||
msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
|
msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
|
||||||
|
@ -22976,6 +22970,11 @@ msgstr ""
|
||||||
msgid "Reports|Execution time"
|
msgid "Reports|Execution time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
|
||||||
|
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
msgid "Reports|Failure"
|
msgid "Reports|Failure"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -26699,9 +26698,6 @@ msgstr ""
|
||||||
msgid "Telephone number"
|
msgid "Telephone number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Telephone number (Optional)"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Template"
|
msgid "Template"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
8
qa/qa.rb
8
qa/qa.rb
|
@ -20,6 +20,7 @@ module QA
|
||||||
autoload :User, 'qa/flow/user'
|
autoload :User, 'qa/flow/user'
|
||||||
autoload :MergeRequest, 'qa/flow/merge_request'
|
autoload :MergeRequest, 'qa/flow/merge_request'
|
||||||
autoload :Pipeline, 'qa/flow/pipeline'
|
autoload :Pipeline, 'qa/flow/pipeline'
|
||||||
|
autoload :SignUp, 'qa/flow/sign_up'
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -181,10 +182,14 @@ module QA
|
||||||
autoload :Menu, 'qa/page/main/menu'
|
autoload :Menu, 'qa/page/main/menu'
|
||||||
autoload :OAuth, 'qa/page/main/oauth'
|
autoload :OAuth, 'qa/page/main/oauth'
|
||||||
autoload :TwoFactorAuth, 'qa/page/main/two_factor_auth'
|
autoload :TwoFactorAuth, 'qa/page/main/two_factor_auth'
|
||||||
autoload :SignUp, 'qa/page/main/sign_up'
|
|
||||||
autoload :Terms, 'qa/page/main/terms'
|
autoload :Terms, 'qa/page/main/terms'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Registration
|
||||||
|
autoload :SignUp, 'qa/page/registration/sign_up'
|
||||||
|
autoload :Welcome, 'qa/page/registration/welcome'
|
||||||
|
end
|
||||||
|
|
||||||
module Settings
|
module Settings
|
||||||
autoload :Common, 'qa/page/settings/common'
|
autoload :Common, 'qa/page/settings/common'
|
||||||
end
|
end
|
||||||
|
@ -431,6 +436,7 @@ module QA
|
||||||
autoload :OutboundRequests, 'qa/page/admin/settings/component/outbound_requests'
|
autoload :OutboundRequests, 'qa/page/admin/settings/component/outbound_requests'
|
||||||
autoload :AccountAndLimit, 'qa/page/admin/settings/component/account_and_limit'
|
autoload :AccountAndLimit, 'qa/page/admin/settings/component/account_and_limit'
|
||||||
autoload :PerformanceBar, 'qa/page/admin/settings/component/performance_bar'
|
autoload :PerformanceBar, 'qa/page/admin/settings/component/performance_bar'
|
||||||
|
autoload :SignUpRestrictions, 'qa/page/admin/settings/component/sign_up_restrictions'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module QA
|
||||||
|
module Flow
|
||||||
|
module SignUp
|
||||||
|
module_function
|
||||||
|
|
||||||
|
def sign_up!(user)
|
||||||
|
Page::Main::Login.perform(&:switch_to_register_page)
|
||||||
|
|
||||||
|
success = Support::Retrier.retry_until(raise_on_failure: false) do
|
||||||
|
Page::Registration::SignUp.perform do |sign_up|
|
||||||
|
sign_up.fill_new_user_first_name_field(user.first_name)
|
||||||
|
sign_up.fill_new_user_last_name_field(user.last_name)
|
||||||
|
sign_up.fill_new_user_username_field(user.username)
|
||||||
|
sign_up.fill_new_user_email_field(user.email)
|
||||||
|
sign_up.fill_new_user_password_field(user.password)
|
||||||
|
sign_up.click_new_user_register_button
|
||||||
|
end
|
||||||
|
|
||||||
|
# Because invisible_captcha would prevent submitting this form
|
||||||
|
# within 4 seconds, sleep here. This can be removed once we
|
||||||
|
# implement invisible_captcha as an application setting instead
|
||||||
|
# of a feature flag, so we can turn it off while testing.
|
||||||
|
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/284113
|
||||||
|
sleep 4
|
||||||
|
|
||||||
|
Page::Registration::Welcome.perform(&:click_get_started_button_if_available)
|
||||||
|
|
||||||
|
if user.expect_fabrication_success
|
||||||
|
Page::Main::Menu.perform(&:has_personal_area?)
|
||||||
|
else
|
||||||
|
Page::Main::Menu.perform(&:not_signed_in?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
raise "Failed to register the user" unless success
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,6 +8,7 @@ module QA
|
||||||
class Index < QA::Page::Base
|
class Index < QA::Page::Base
|
||||||
view 'app/views/admin/users/index.html.haml' do
|
view 'app/views/admin/users/index.html.haml' do
|
||||||
element :user_search_field
|
element :user_search_field
|
||||||
|
element :pending_approval_tab
|
||||||
end
|
end
|
||||||
|
|
||||||
view 'app/views/admin/users/_user.html.haml' do
|
view 'app/views/admin/users/_user.html.haml' do
|
||||||
|
@ -22,6 +23,10 @@ module QA
|
||||||
find_element(:user_search_field).set(username).send_keys(:return)
|
find_element(:user_search_field).set(username).send_keys(:return)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def click_pending_approval_tab
|
||||||
|
click_element :pending_approval_tab
|
||||||
|
end
|
||||||
|
|
||||||
def click_user(username)
|
def click_user(username)
|
||||||
within_element(:user_row_content, text: username) do
|
within_element(:user_row_content, text: username) do
|
||||||
click_element(:username_link)
|
click_element(:username_link)
|
||||||
|
|
|
@ -12,17 +12,32 @@ module QA
|
||||||
|
|
||||||
view 'app/views/admin/users/show.html.haml' do
|
view 'app/views/admin/users/show.html.haml' do
|
||||||
element :confirm_user_button
|
element :confirm_user_button
|
||||||
|
element :user_id_content
|
||||||
|
end
|
||||||
|
|
||||||
|
view 'app/views/admin/users/_approve_user.html.haml' do
|
||||||
|
element :approve_user_button
|
||||||
end
|
end
|
||||||
|
|
||||||
def click_impersonate_user
|
def click_impersonate_user
|
||||||
click_element(:impersonate_user_link)
|
click_element(:impersonate_user_link)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_id
|
||||||
|
find_element(:user_id_content).text
|
||||||
|
end
|
||||||
|
|
||||||
def confirm_user
|
def confirm_user
|
||||||
accept_confirm do
|
accept_confirm do
|
||||||
click_element :confirm_user_button
|
click_element :confirm_user_button
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def approve_user
|
||||||
|
accept_confirm do
|
||||||
|
click_element :approve_user_button
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module QA
|
||||||
|
module Page
|
||||||
|
module Admin
|
||||||
|
module Settings
|
||||||
|
module Component
|
||||||
|
class SignUpRestrictions < Page::Base
|
||||||
|
view 'app/views/admin/application_settings/_signup.html.haml' do
|
||||||
|
element :require_admin_approval_after_user_signup_checkbox
|
||||||
|
element :save_changes_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_admin_approval_after_user_signup
|
||||||
|
check_element :require_admin_approval_after_user_signup_checkbox
|
||||||
|
click_element :save_changes_button
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,6 +9,7 @@ module QA
|
||||||
|
|
||||||
view 'app/views/admin/application_settings/general.html.haml' do
|
view 'app/views/admin/application_settings/general.html.haml' do
|
||||||
element :account_and_limit_settings_content
|
element :account_and_limit_settings_content
|
||||||
|
element :sign_up_restrictions_settings_content
|
||||||
end
|
end
|
||||||
|
|
||||||
def expand_account_and_limit(&block)
|
def expand_account_and_limit(&block)
|
||||||
|
@ -16,6 +17,12 @@ module QA
|
||||||
Component::AccountAndLimit.perform(&block)
|
Component::AccountAndLimit.perform(&block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def expand_sign_up_restrictions(&block)
|
||||||
|
expand_content(:sign_up_restrictions_settings_content) do
|
||||||
|
Component::SignUpRestrictions.perform(&block)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -93,6 +93,10 @@ module QA
|
||||||
has_personal_area?(wait: 0)
|
has_personal_area?(wait: 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def not_signed_in?
|
||||||
|
has_no_personal_area?
|
||||||
|
end
|
||||||
|
|
||||||
def sign_out
|
def sign_out
|
||||||
retry_until do
|
retry_until do
|
||||||
wait_if_retry_later
|
wait_if_retry_later
|
||||||
|
@ -129,6 +133,10 @@ module QA
|
||||||
has_element?(:user_avatar, wait: wait)
|
has_element?(:user_avatar, wait: wait)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_no_personal_area?(wait: Capybara.default_max_wait_time)
|
||||||
|
has_no_element?(:user_avatar, wait: wait)
|
||||||
|
end
|
||||||
|
|
||||||
def has_admin_area_link?(wait: Capybara.default_max_wait_time)
|
def has_admin_area_link?(wait: Capybara.default_max_wait_time)
|
||||||
has_element?(:admin_area_link, wait: wait)
|
has_element?(:admin_area_link, wait: wait)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module QA
|
|
||||||
module Page
|
|
||||||
module Main
|
|
||||||
class SignUp < Page::Base
|
|
||||||
view 'app/views/devise/shared/_signup_box.html.haml' do
|
|
||||||
element :new_user_first_name_field
|
|
||||||
element :new_user_last_name_field
|
|
||||||
element :new_user_username_field
|
|
||||||
element :new_user_email_field
|
|
||||||
element :new_user_password_field
|
|
||||||
element :new_user_register_button
|
|
||||||
end
|
|
||||||
|
|
||||||
view 'app/views/registrations/welcome/show.html.haml' do
|
|
||||||
element :get_started_button
|
|
||||||
end
|
|
||||||
|
|
||||||
def sign_up!(user)
|
|
||||||
signed_in = retry_until(raise_on_failure: false) do
|
|
||||||
fill_element :new_user_first_name_field, user.first_name
|
|
||||||
fill_element :new_user_last_name_field, user.last_name
|
|
||||||
fill_element :new_user_username_field, user.username
|
|
||||||
fill_element :new_user_email_field, user.email
|
|
||||||
fill_element :new_user_password_field, user.password
|
|
||||||
|
|
||||||
# Because invisible_captcha would prevent submitting this form
|
|
||||||
# within 4 seconds, sleep here. This can be removed once we
|
|
||||||
# implement invisible_captcha as an application setting instead
|
|
||||||
# of a feature flag, so we can turn it off while testing.
|
|
||||||
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/284113
|
|
||||||
sleep 4
|
|
||||||
|
|
||||||
click_element :new_user_register_button if has_element?(:new_user_register_button)
|
|
||||||
click_element :get_started_button if has_element?(:get_started_button)
|
|
||||||
|
|
||||||
Page::Main::Menu.perform(&:has_personal_area?)
|
|
||||||
end
|
|
||||||
|
|
||||||
raise "Failed to register and sign in" unless signed_in
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
QA::Page::Main::SignUp.prepend_if_ee('QA::EE::Page::Main::SignUp')
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module QA
|
||||||
|
module Page
|
||||||
|
module Registration
|
||||||
|
class SignUp < Page::Base
|
||||||
|
view 'app/views/devise/shared/_signup_box.html.haml' do
|
||||||
|
element :new_user_first_name_field
|
||||||
|
element :new_user_last_name_field
|
||||||
|
element :new_user_username_field
|
||||||
|
element :new_user_email_field
|
||||||
|
element :new_user_password_field
|
||||||
|
element :new_user_register_button
|
||||||
|
end
|
||||||
|
|
||||||
|
view 'app/views/registrations/welcome/show.html.haml' do
|
||||||
|
element :get_started_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_new_user_first_name_field(first_name)
|
||||||
|
fill_element :new_user_first_name_field, first_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_new_user_last_name_field(last_name)
|
||||||
|
fill_element :new_user_last_name_field, last_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_new_user_username_field(username)
|
||||||
|
fill_element :new_user_username_field, username
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_new_user_email_field(email)
|
||||||
|
fill_element :new_user_email_field, email
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_new_user_password_field(password)
|
||||||
|
fill_element :new_user_password_field, password
|
||||||
|
end
|
||||||
|
|
||||||
|
def click_new_user_register_button
|
||||||
|
click_element :new_user_register_button if has_element?(:new_user_register_button)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module QA
|
||||||
|
module Page
|
||||||
|
module Registration
|
||||||
|
class Welcome < Page::Base
|
||||||
|
view 'app/views/registrations/welcome/show.html.haml' do
|
||||||
|
element :get_started_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def click_get_started_button_if_available
|
||||||
|
click_element :get_started_button if has_element?(:get_started_button)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
QA::Page::Registration::Welcome.prepend_if_ee('QA::EE::Page::Registration::Welcome')
|
|
@ -7,7 +7,7 @@ module QA
|
||||||
class User < Base
|
class User < Base
|
||||||
attr_reader :unique_id
|
attr_reader :unique_id
|
||||||
attr_writer :username, :password
|
attr_writer :username, :password
|
||||||
attr_accessor :admin, :provider, :extern_uid
|
attr_accessor :admin, :provider, :extern_uid, :expect_fabrication_success
|
||||||
|
|
||||||
attribute :id
|
attribute :id
|
||||||
attribute :name
|
attribute :name
|
||||||
|
@ -18,6 +18,7 @@ module QA
|
||||||
def initialize
|
def initialize
|
||||||
@admin = false
|
@admin = false
|
||||||
@unique_id = SecureRandom.hex(8)
|
@unique_id = SecureRandom.hex(8)
|
||||||
|
@expect_fabrication_success = true
|
||||||
end
|
end
|
||||||
|
|
||||||
def admin?
|
def admin?
|
||||||
|
@ -74,12 +75,7 @@ module QA
|
||||||
login.sign_in_using_credentials(user: self)
|
login.sign_in_using_credentials(user: self)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Page::Main::Login.perform do |login|
|
Flow::SignUp.sign_up!(self)
|
||||||
login.switch_to_register_page
|
|
||||||
end
|
|
||||||
Page::Main::SignUp.perform do |signup|
|
|
||||||
signup.sign_up!(self)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ module QA
|
||||||
ldap_username = Runtime::Env.ldap_username
|
ldap_username = Runtime::Env.ldap_username
|
||||||
Runtime::Env.ldap_username = nil
|
Runtime::Env.ldap_username = nil
|
||||||
|
|
||||||
disable_require_admin_approval_after_user_signup
|
set_require_admin_approval_after_user_signup_via_api(false)
|
||||||
|
|
||||||
Runtime::Env.ldap_username = ldap_username
|
Runtime::Env.ldap_username = ldap_username
|
||||||
end
|
end
|
||||||
|
@ -39,60 +39,135 @@ module QA
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'standard', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/936' do
|
describe 'standard', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/936' do
|
||||||
before(:all) do
|
context 'when admin approval is not required' do
|
||||||
disable_require_admin_approval_after_user_signup
|
before(:all) do
|
||||||
|
set_require_admin_approval_after_user_signup_via_api(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'registration and login'
|
||||||
|
|
||||||
|
context 'when user account is deleted' do
|
||||||
|
let(:user) do
|
||||||
|
Resource::User.fabricate_via_api! do |resource|
|
||||||
|
resource.api_client = admin_api_client
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
# Use the UI instead of API to delete the account since
|
||||||
|
# this is the only test that exercise this UI.
|
||||||
|
# Other tests should use the API for this purpose.
|
||||||
|
Flow::Login.sign_in(as: user)
|
||||||
|
Page::Main::Menu.perform(&:click_settings_link)
|
||||||
|
Page::Profile::Menu.perform(&:click_account)
|
||||||
|
Page::Profile::Accounts::Show.perform do |show|
|
||||||
|
show.delete_account(user.password)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'allows recreating with same credentials', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/937' do
|
||||||
|
expect(Page::Main::Menu.perform(&:signed_in?)).to be_falsy
|
||||||
|
|
||||||
|
Flow::Login.sign_in(as: user, skip_page_validation: true)
|
||||||
|
|
||||||
|
expect(page).to have_text("Invalid Login or password")
|
||||||
|
|
||||||
|
@recreated_user = Resource::User.fabricate_via_browser_ui! do |resource|
|
||||||
|
resource.name = user.name
|
||||||
|
resource.username = user.username
|
||||||
|
resource.email = user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
@recreated_user.remove_via_api!
|
||||||
|
end
|
||||||
|
|
||||||
|
def admin_api_client
|
||||||
|
@admin_api_client ||= Runtime::API::Client.as_admin
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'registration and login'
|
context 'when admin approval is required' do
|
||||||
|
let(:signed_up_waiting_approval_text) { 'You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator.' }
|
||||||
context 'when user account is deleted' do
|
let(:pending_approval_blocked_text) { 'Your account is pending approval from your GitLab administrator and hence blocked. Please contact your GitLab administrator if you think this is an error.' }
|
||||||
let(:user) do
|
|
||||||
Resource::User.fabricate_via_api! do |resource|
|
|
||||||
resource.api_client = admin_api_client
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
# Use the UI instead of API to delete the account since
|
enable_require_admin_approval_after_user_signup_via_ui
|
||||||
# this is the only test that exercise this UI.
|
|
||||||
# Other tests should use the API for this purpose.
|
@user = Resource::User.fabricate_via_browser_ui! do |user|
|
||||||
Flow::Login.sign_in(as: user)
|
user.expect_fabrication_success = false
|
||||||
Page::Main::Menu.perform(&:click_settings_link)
|
|
||||||
Page::Profile::Menu.perform(&:click_account)
|
|
||||||
Page::Profile::Accounts::Show.perform do |show|
|
|
||||||
show.delete_account(user.password)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'allows recreating with same credentials', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/937' do
|
it 'allows user login after approval', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1076' do
|
||||||
expect(Page::Main::Menu.perform(&:signed_in?)).to be_falsy
|
expect(page).to have_text(signed_up_waiting_approval_text)
|
||||||
|
|
||||||
Flow::Login.sign_in(as: user, skip_page_validation: true)
|
Flow::Login.sign_in(as: @user, skip_page_validation: true)
|
||||||
|
|
||||||
expect(page).to have_text("Invalid Login or password")
|
expect(page).to have_text(pending_approval_blocked_text)
|
||||||
|
|
||||||
@recreated_user = Resource::User.fabricate_via_browser_ui! do |resource|
|
approve_user(@user)
|
||||||
resource.name = user.name
|
|
||||||
resource.username = user.username
|
Flow::Login.sign_in(as: @user, skip_page_validation: true)
|
||||||
resource.email = user.email
|
|
||||||
|
Page::Registration::Welcome.perform(&:click_get_started_button_if_available)
|
||||||
|
|
||||||
|
Page::Main::Menu.perform do |menu|
|
||||||
|
expect(menu).to have_personal_area
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy
|
|
||||||
end
|
end
|
||||||
|
|
||||||
after do
|
after do
|
||||||
@recreated_user.remove_via_api!
|
@user.remove_via_api! if @user
|
||||||
end
|
|
||||||
|
|
||||||
def admin_api_client
|
|
||||||
@admin_api_client ||= Runtime::API::Client.as_admin
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_require_admin_approval_after_user_signup
|
def approve_user(user)
|
||||||
Runtime::ApplicationSettings.set_application_settings(require_admin_approval_after_user_signup: false)
|
Flow::Login.while_signed_in_as_admin do
|
||||||
|
Page::Main::Menu.perform(&:go_to_admin_area)
|
||||||
|
Page::Admin::Menu.perform(&:go_to_users_overview)
|
||||||
|
Page::Admin::Overview::Users::Index.perform do |index|
|
||||||
|
index.click_pending_approval_tab
|
||||||
|
index.search_user(user.username)
|
||||||
|
index.click_user(user.username)
|
||||||
|
end
|
||||||
|
|
||||||
|
Page::Admin::Overview::Users::Show.perform do |show|
|
||||||
|
user.id = show.user_id.to_i
|
||||||
|
show.approve_user
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(page).to have_text('Successfully approved')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_require_admin_approval_after_user_signup_via_api(enable_or_disable)
|
||||||
|
return if Runtime::ApplicationSettings.get_application_settings[:require_admin_approval_after_user_signup] == enable_or_disable
|
||||||
|
|
||||||
|
Runtime::ApplicationSettings.set_application_settings(require_admin_approval_after_user_signup: enable_or_disable)
|
||||||
|
|
||||||
sleep 10 # It takes a moment for the setting to come into effect
|
sleep 10 # It takes a moment for the setting to come into effect
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def enable_require_admin_approval_after_user_signup_via_ui
|
||||||
|
unless Runtime::ApplicationSettings.get_application_settings[:require_admin_approval_after_user_signup]
|
||||||
|
Flow::Login.while_signed_in_as_admin do
|
||||||
|
Page::Main::Menu.perform(&:go_to_admin_area)
|
||||||
|
QA::Page::Admin::Menu.perform(&:go_to_general_settings)
|
||||||
|
Page::Admin::Settings::General.perform do |setting|
|
||||||
|
setting.expand_sign_up_restrictions do |settings|
|
||||||
|
settings.require_admin_approval_after_user_signup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sleep 10 # It takes a moment for the setting to come into effect
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -264,7 +264,9 @@ describe('Grouped test reports app', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the recent failures count on the test case', () => {
|
it('renders the recent failures count on the test case', () => {
|
||||||
expect(findIssueDescription().text()).toContain('Failed 8 times in the last 14 days');
|
expect(findIssueDescription().text()).toContain(
|
||||||
|
'Failed 8 times in master in the last 14 days',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
"name": "Test#sum when a is 1 and b is 2 returns summary",
|
"name": "Test#sum when a is 1 and b is 2 returns summary",
|
||||||
"execution_time": 0.009411,
|
"execution_time": 0.009411,
|
||||||
"system_output": "Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in <top (required)>'",
|
"system_output": "Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in <top (required)>'",
|
||||||
"recent_failures": 8
|
"recent_failures": {
|
||||||
|
"count": 8,
|
||||||
|
"base_branch": "master"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"result": "failure",
|
"result": "failure",
|
||||||
|
@ -33,7 +36,10 @@
|
||||||
"result": "failure",
|
"result": "failure",
|
||||||
"name": "Test#sum when a is 100 and b is 200 returns summary",
|
"name": "Test#sum when a is 100 and b is 200 returns summary",
|
||||||
"execution_time": 0.000562,
|
"execution_time": 0.000562,
|
||||||
"recent_failures": 3
|
"recent_failures": {
|
||||||
|
"count": 3,
|
||||||
|
"base_branch": "master"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"resolved_failures": [],
|
"resolved_failures": [],
|
||||||
|
|
|
@ -46,7 +46,10 @@ describe('Reports Store Mutations', () => {
|
||||||
name: 'StringHelper#concatenate when a is git and b is lab returns summary',
|
name: 'StringHelper#concatenate when a is git and b is lab returns summary',
|
||||||
execution_time: 0.0092435,
|
execution_time: 0.0092435,
|
||||||
system_output: "Failure/Error: is_expected.to eq('gitlab')",
|
system_output: "Failure/Error: is_expected.to eq('gitlab')",
|
||||||
recent_failures: 4,
|
recent_failures: {
|
||||||
|
count: 4,
|
||||||
|
base_branch: 'master',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
resolved_failures: [
|
resolved_failures: [
|
||||||
|
|
|
@ -188,9 +188,9 @@ describe('Reports store utils', () => {
|
||||||
describe('countRecentlyFailedTests', () => {
|
describe('countRecentlyFailedTests', () => {
|
||||||
it('counts tests with more than one recent failure in a report', () => {
|
it('counts tests with more than one recent failure in a report', () => {
|
||||||
const report = {
|
const report = {
|
||||||
new_failures: [{ recent_failures: 2 }],
|
new_failures: [{ recent_failures: { count: 2 } }],
|
||||||
existing_failures: [{ recent_failures: 1 }],
|
existing_failures: [{ recent_failures: { count: 1 } }],
|
||||||
resolved_failures: [{ recent_failures: 20 }, { recent_failures: 5 }],
|
resolved_failures: [{ recent_failures: { count: 20 } }, { recent_failures: { count: 5 } }],
|
||||||
};
|
};
|
||||||
const result = utils.countRecentlyFailedTests(report);
|
const result = utils.countRecentlyFailedTests(report);
|
||||||
|
|
||||||
|
@ -200,14 +200,17 @@ describe('Reports store utils', () => {
|
||||||
it('counts tests with more than one recent failure in an array of reports', () => {
|
it('counts tests with more than one recent failure in an array of reports', () => {
|
||||||
const reports = [
|
const reports = [
|
||||||
{
|
{
|
||||||
new_failures: [{ recent_failures: 2 }],
|
new_failures: [{ recent_failures: { count: 2 } }],
|
||||||
existing_failures: [{ recent_failures: 20 }, { recent_failures: 5 }],
|
existing_failures: [
|
||||||
resolved_failures: [{ recent_failures: 2 }],
|
{ recent_failures: { count: 20 } },
|
||||||
|
{ recent_failures: { count: 5 } },
|
||||||
|
],
|
||||||
|
resolved_failures: [{ recent_failures: { count: 2 } }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
new_failures: [{ recent_failures: 8 }, { recent_failures: 14 }],
|
new_failures: [{ recent_failures: { count: 8 } }, { recent_failures: { count: 14 } }],
|
||||||
existing_failures: [{ recent_failures: 1 }],
|
existing_failures: [{ recent_failures: { count: 1 } }],
|
||||||
resolved_failures: [{ recent_failures: 7 }, { recent_failures: 5 }],
|
resolved_failures: [{ recent_failures: { count: 7 } }, { recent_failures: { count: 5 } }],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const result = utils.countRecentlyFailedTests(reports);
|
const result = utils.countRecentlyFailedTests(reports);
|
||||||
|
|
Loading…
Reference in New Issue