Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-11-02 15:11:46 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-11-02 15:11:46 +0300
commitd8c4c08d4999959ca9b5a87a32153013791e96e0 (patch)
tree5772e13f80e3e85334f8b059c103a4065de8d682
parentaa84824d04b32ce9cd3abeac90a6bf78fb2be34c (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/access_tokens/components/access_token_table_app.vue2
-rw-r--r--app/assets/javascripts/access_tokens/components/expires_at_field.vue2
-rw-r--r--app/assets/javascripts/access_tokens/components/new_access_token_app.vue4
-rw-r--r--app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue12
-rw-r--r--app/assets/javascripts/invite_members/components/invite_group_trigger.vue7
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_trigger.vue9
-rw-r--r--app/assets/javascripts/invite_members/components/invite_modal_base.vue3
-rw-r--r--app/assets/javascripts/invite_members/components/members_token_select.vue1
-rw-r--r--app/assets/javascripts/invite_members/constants.js1
-rw-r--r--app/assets/javascripts/pages/profiles/two_factor_auths/index.js2
-rw-r--r--app/assets/javascripts/profile/account/components/delete_account_modal.vue4
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_menu.vue4
-rw-r--r--app/assets/javascripts/terms/components/app.vue4
-rw-r--r--app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue1
-rw-r--r--app/helpers/auth_helper.rb12
-rw-r--r--app/services/admin/plan_limits/update_service.rb52
-rw-r--r--app/views/devise/passwords/edit.html.haml6
-rw-r--r--app/views/devise/sessions/_new_base.html.haml5
-rw-r--r--app/views/devise/sessions/_new_ldap.html.haml6
-rw-r--r--app/views/devise/sessions/new.html.haml2
-rw-r--r--app/views/devise/sessions/two_factor.html.haml4
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml2
-rw-r--r--app/views/devise/shared/_signup_omniauth_provider_list.haml4
-rw-r--r--app/views/devise/shared/_tab_single.html.haml2
-rw-r--r--app/views/devise/shared/_tabs_ldap.html.haml6
-rw-r--r--app/views/doorkeeper/authorizations/new.html.haml2
-rw-r--r--app/views/layouts/devise.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml2
-rw-r--r--app/views/layouts/terms.html.haml2
-rw-r--r--app/views/profiles/accounts/show.html.haml4
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml8
-rw-r--r--app/views/shared/access_tokens/_form.html.haml4
-rw-r--r--app/views/shared/deploy_tokens/_form.html.haml16
-rw-r--r--app/views/shared/deploy_tokens/_new_deploy_token.html.haml6
-rw-r--r--doc/api/users.md1
-rw-r--r--doc/architecture/blueprints/gcp_integration/decisions/001_no_credentials.md19
-rw-r--r--doc/architecture/blueprints/gcp_integration/index.md95
-rw-r--r--lib/gitlab/analytics/cycle_analytics/request_params.rb3
-rw-r--r--package.json2
-rw-r--r--qa/qa/mobile/page/main/menu.rb4
-rw-r--r--qa/qa/page/component/access_tokens.rb26
-rw-r--r--qa/qa/page/component/confirm_modal.rb10
-rw-r--r--qa/qa/page/component/members/invite_members_modal.rb22
-rw-r--r--qa/qa/page/group/settings/group_deploy_tokens.rb42
-rw-r--r--qa/qa/page/main/login.rb86
-rw-r--r--qa/qa/page/main/menu.rb14
-rw-r--r--qa/qa/page/main/oauth.rb4
-rw-r--r--qa/qa/page/main/terms.rb8
-rw-r--r--qa/qa/page/main/two_factor_auth.rb8
-rw-r--r--qa/qa/page/profile/accounts/show.rb16
-rw-r--r--qa/qa/page/profile/ssh_keys.rb6
-rw-r--r--qa/qa/page/profile/two_factor_auth.rb38
-rw-r--r--qa/qa/page/project/settings/deploy_tokens.rb46
-rw-r--r--spec/features/alert_management/alert_details_spec.rb2
-rw-r--r--spec/features/alert_management/alert_management_list_spec.rb6
-rw-r--r--spec/features/projects/members/manage_groups_spec.rb2
-rw-r--r--spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap2
-rw-r--r--spec/frontend/access_tokens/components/access_token_table_app_spec.js2
-rw-r--r--spec/frontend/access_tokens/components/new_access_token_app_spec.js14
-rw-r--r--spec/frontend/invite_members/components/invite_members_trigger_spec.js13
-rw-r--r--spec/frontend/invite_members/components/invite_modal_base_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js2
-rw-r--r--spec/models/integrations/integration_list_spec.rb4
-rw-r--r--spec/services/admin/plan_limits/update_service_spec.rb76
-rw-r--r--spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb12
-rw-r--r--yarn.lock8
68 files changed, 359 insertions, 445 deletions
diff --git a/app/assets/javascripts/access_tokens/components/access_token_table_app.vue b/app/assets/javascripts/access_tokens/components/access_token_table_app.vue
index 9a7296b6b1f..3b71e39d69b 100644
--- a/app/assets/javascripts/access_tokens/components/access_token_table_app.vue
+++ b/app/assets/javascripts/access_tokens/components/access_token_table_app.vue
@@ -158,7 +158,7 @@ export default {
:aria-label="$options.i18n.revokeButton"
:data-confirm="modalMessage(name)"
data-confirm-btn-variant="danger"
- data-qa-selector="revoke_button"
+ data-testid="revoke-button"
data-method="put"
:href="revokePath"
icon="remove"
diff --git a/app/assets/javascripts/access_tokens/components/expires_at_field.vue b/app/assets/javascripts/access_tokens/components/expires_at_field.vue
index 38501d63d3a..65206670a3c 100644
--- a/app/assets/javascripts/access_tokens/components/expires_at_field.vue
+++ b/app/assets/javascripts/access_tokens/components/expires_at_field.vue
@@ -68,7 +68,7 @@ export default {
:input-name="inputAttrs.name"
:input-id="inputAttrs.id"
:placeholder="inputAttrs.placeholder"
- data-qa-selector="expiry_date_field"
+ data-testid="expiry-date-field"
/>
<template #description>
<template v-if="description">
diff --git a/app/assets/javascripts/access_tokens/components/new_access_token_app.vue b/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
index 4b51b4333aa..f476503c091 100644
--- a/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
+++ b/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
@@ -45,7 +45,7 @@ export default {
formInputGroupProps() {
return {
id: this.$options.tokenInputId,
- 'data-qa-selector': 'created_access_token_field',
+ 'data-testid': 'created-access-token-field',
name: this.$options.tokenInputId,
};
},
@@ -110,7 +110,7 @@ export default {
@[$options.EVENT_ERROR]="onError"
@[$options.EVENT_SUCCESS]="onSuccess"
>
- <div ref="container" data-testid="access-token-section" data-qa-selector="access_token_section">
+ <div ref="container" data-testid="access-token-section">
<gl-alert
v-if="newToken"
variant="success"
diff --git a/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue b/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue
index d3b914ea8aa..240bf005532 100644
--- a/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue
+++ b/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue
@@ -115,14 +115,10 @@ export default {
</gl-sprintf>
</p>
- <gl-card
- class="codes-to-print gl-my-5"
- data-testid="recovery-codes"
- data-qa-selector="codes_content"
- >
+ <gl-card class="codes-to-print gl-my-5" data-testid="recovery-codes">
<ul class="gl-m-0 gl-pl-5">
<li v-for="(code, index) in codes" :key="index">
- <span class="gl-font-monospace" data-qa-selector="code_content">{{ code }}</span>
+ <span class="gl-font-monospace" data-testid="code-content">{{ code }}</span>
</li>
</ul>
</gl-card>
@@ -131,7 +127,7 @@ export default {
<clipboard-button
:title="$options.i18n.copyButton"
:text="codesAsString"
- data-qa-selector="copy_button"
+ data-testid="copy-button"
@click="handleButtonClick($options.copyButtonAction)"
>
{{ $options.i18n.copyButton }}
@@ -163,7 +159,7 @@ export default {
:disabled="proceedButtonDisabled"
:title="$options.i18n.proceedButton"
variant="confirm"
- data-qa-selector="proceed_button"
+ data-testid="proceed-button"
data-track-action="click_button"
:data-track-label="`${$options.trackingLabelPrefix}proceed_button`"
>{{ $options.i18n.proceedButton }}</gl-button
diff --git a/app/assets/javascripts/invite_members/components/invite_group_trigger.vue b/app/assets/javascripts/invite_members/components/invite_group_trigger.vue
index 424a9d3fabd..7db315fda1a 100644
--- a/app/assets/javascripts/invite_members/components/invite_group_trigger.vue
+++ b/app/assets/javascripts/invite_members/components/invite_group_trigger.vue
@@ -28,12 +28,7 @@ export default {
</script>
<template>
- <gl-button
- :class="classes"
- data-qa-selector="invite_a_group_button"
- data-test-id="invite-group-button"
- @click="openModal"
- >
+ <gl-button :class="classes" data-testid="invite-a-group-button" @click="openModal">
{{ displayText }}
</gl-button>
</template>
diff --git a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
index 6efb7a6cdf1..7f76b7ca1ac 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
@@ -4,7 +4,6 @@ import { s__ } from '~/locale';
import eventHub from '../event_hub';
import {
TRIGGER_ELEMENT_BUTTON,
- TRIGGER_DEFAULT_QA_SELECTOR,
TRIGGER_ELEMENT_WITH_EMOJI,
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN,
@@ -42,18 +41,12 @@ export default {
required: false,
default: 'button',
},
- qaSelector: {
- type: String,
- required: false,
- default: TRIGGER_DEFAULT_QA_SELECTOR,
- },
},
computed: {
componentAttributes() {
return {
class: this.classes,
- 'data-qa-selector': this.qaSelector,
- 'data-test-id': 'invite-members-button',
+ 'data-testid': 'invite-members-button',
};
},
item() {
diff --git a/app/assets/javascripts/invite_members/components/invite_modal_base.vue b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
index 18d22395104..20b7096785d 100644
--- a/app/assets/javascripts/invite_members/components/invite_modal_base.vue
+++ b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
@@ -173,7 +173,6 @@ export default {
variant: 'confirm',
disabled: this.submitDisabled,
loading: this.isLoading,
- 'data-qa-selector': 'invite_button',
},
};
},
@@ -311,7 +310,7 @@ export default {
<gl-form-select
:id="dropdownId"
v-model="selectedAccessLevel"
- data-qa-selector="access_level_dropdown"
+ data-testid="access-level-dropdown"
:options="accessLevelsOptions"
/>
</gl-form-group>
diff --git a/app/assets/javascripts/invite_members/components/members_token_select.vue b/app/assets/javascripts/invite_members/components/members_token_select.vue
index 0be04b7af35..015cadc9993 100644
--- a/app/assets/javascripts/invite_members/components/members_token_select.vue
+++ b/app/assets/javascripts/invite_members/components/members_token_select.vue
@@ -102,7 +102,6 @@ export default {
textInputAttrs() {
return {
'data-testid': 'members-token-select-input',
- 'data-qa-selector': 'members_token_select_input',
id: this.inputId,
};
},
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
index 93386e5504b..3b2840ecf11 100644
--- a/app/assets/javascripts/invite_members/constants.js
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -20,7 +20,6 @@ export const TRIGGER_ELEMENT_WITH_EMOJI = 'text-emoji';
export const TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI = 'dropdown-text-emoji';
export const TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN = 'dropdown-text';
export const INVITE_MEMBER_MODAL_TRACKING_CATEGORY = 'invite_members_modal';
-export const TRIGGER_DEFAULT_QA_SELECTOR = 'invite_members_button';
export const IMPORT_PROJECT_MEMBERS_MODAL_TRACKING_CATEGORY = 'invite_project_members_modal';
export const IMPORT_PROJECT_MEMBERS_MODAL_TRACKING_LABEL = 'project-members-page';
export const MEMBERS_MODAL_DEFAULT_TITLE = s__('InviteMembersModal|Invite members');
diff --git a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
index 8fe822e4639..41952a33c05 100644
--- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
+++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
@@ -8,7 +8,7 @@ const skippable = twoFactorNode ? parseBoolean(twoFactorNode.dataset.twoFactorSk
if (skippable) {
const button = `<div class="gl-alert-actions">
- <a class="btn gl-button btn-md btn-confirm gl-alert-action" data-qa-selector="configure_it_later_button" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>
+ <a class="btn gl-button btn-md btn-confirm gl-alert-action" data-testid="configure-it-later-button" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>
</div>`;
const flashAlert = document.querySelector('.flash-alert');
if (flashAlert) {
diff --git a/app/assets/javascripts/profile/account/components/delete_account_modal.vue b/app/assets/javascripts/profile/account/components/delete_account_modal.vue
index 915f6578ac3..e9a67a401b8 100644
--- a/app/assets/javascripts/profile/account/components/delete_account_modal.vue
+++ b/app/assets/javascripts/profile/account/components/delete_account_modal.vue
@@ -42,7 +42,7 @@ export default {
text: __('Delete account'),
attributes: {
variant: 'danger',
- 'data-qa-selector': 'confirm_delete_account_button',
+ 'data-testid': 'confirm-delete-account-button',
category: 'primary',
disabled: !this.canSubmit,
},
@@ -128,7 +128,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
name="password"
class="form-control"
type="password"
- data-qa-selector="password_confirmation_field"
+ data-testid="password-confirmation-field"
aria-labelledby="input-label"
/>
<input
diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue
index 891e883b6c0..c3655572e2f 100644
--- a/app/assets/javascripts/super_sidebar/components/user_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue
@@ -88,7 +88,7 @@ export default {
text: this.$options.i18n.editProfile,
href: this.data.settings.profile_path,
extraAttrs: {
- 'data-testid': 'edit_profile_link',
+ 'data-testid': 'edit-profile-link',
...USER_MENU_TRACKING_DEFAULTS,
'data-track-label': 'user_edit_profile',
},
@@ -235,7 +235,7 @@ export default {
:entity-name="data.name"
:src="data.avatar_url"
aria-hidden="true"
- data-testid="user_avatar_content"
+ data-testid="user-avatar-content"
/>
<span
v-if="showNotificationDot"
diff --git a/app/assets/javascripts/terms/components/app.vue b/app/assets/javascripts/terms/components/app.vue
index 29099bcc366..75ee0e16d4e 100644
--- a/app/assets/javascripts/terms/components/app.vue
+++ b/app/assets/javascripts/terms/components/app.vue
@@ -66,7 +66,7 @@ export default {
<template>
<div>
- <div class="gl-relative gl-pb-0 gl-px-0" data-qa-selector="terms_content">
+ <div class="gl-relative gl-pb-0 gl-px-0" data-testid="terms-content">
<div
class="terms-fade gl-absolute gl-left-5 gl-right-5 gl-bottom-0 gl-h-11 gl-pointer-events-none"
></div>
@@ -97,7 +97,7 @@ export default {
type="submit"
variant="confirm"
:disabled="acceptDisabled"
- data-qa-selector="accept_terms_button"
+ data-testid="accept-terms-button"
>{{ $options.i18n.accept }}</gl-button
>
<input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
diff --git a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
index 8c46c6152ce..e84b3f53b53 100644
--- a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
+++ b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
@@ -30,7 +30,7 @@ import AlertSidebar from './alert_sidebar.vue';
import AlertSummaryRow from './alert_summary_row.vue';
import SystemNote from './system_notes/system_note.vue';
-const containerEl = document.querySelector('.page-with-contextual-sidebar');
+const containerEl = document.querySelector('.layout-page');
export default {
i18n: {
diff --git a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
index a1ef1f30ebb..5019ab901fd 100644
--- a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
@@ -72,7 +72,7 @@ export default {
attributes: {
variant: 'danger',
disabled: !this.isValid,
- 'data-qa-selector': 'confirm_danger_modal_button',
+ 'data-testid': 'confirm-danger-modal-button',
},
};
},
@@ -133,8 +133,7 @@ export default {
id="confirm_name_input"
v-model="confirmationPhrase"
class="form-control"
- data-qa-selector="confirm_danger_field"
- data-testid="confirm-danger-input"
+ data-testid="confirm-danger-field"
type="text"
/>
</gl-form-group>
diff --git a/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue b/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
index d97f1ae6135..344edc1082e 100644
--- a/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
+++ b/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
@@ -176,7 +176,6 @@ export default {
:aria-label="toggleVisibilityLabel"
:icon="toggleVisibilityIcon"
data-testid="toggle-visibility-button"
- data-qa-selector="toggle_visibility_button"
@click.stop="handleToggleVisibilityButtonClick"
/>
<clipboard-button
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index fc157df3891..2d6c9d4a068 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -47,13 +47,13 @@ module AuthHelper
provider_has_builtin_icon?(name) || provider_has_custom_icon?(name)
end
- def qa_selector_for_provider(provider)
+ def test_id_for_provider(provider)
{
- saml: 'saml_login_button',
- openid_connect: 'oidc_login_button',
- github: 'github_login_button',
- gitlab: 'gitlab_oauth_login_button',
- facebook: 'facebook_login_button'
+ saml: 'saml-login-button',
+ openid_connect: 'oidc-login-button',
+ github: 'github-login-button',
+ gitlab: 'gitlab-oauth-login-button',
+ facebook: 'facebook-login-button'
}[provider.to_sym]
end
diff --git a/app/services/admin/plan_limits/update_service.rb b/app/services/admin/plan_limits/update_service.rb
index 24ce3c4095f..7412f9852d1 100644
--- a/app/services/admin/plan_limits/update_service.rb
+++ b/app/services/admin/plan_limits/update_service.rb
@@ -51,35 +51,63 @@ module Admin
def validate_notification_limit
return unless parsed_params.include?(:notification_limit)
- return if notification_limit >= storage_size_limit && notification_limit <= enforcement_limit
+ return if unlimited_value?(:notification_limit)
- plan_limits.errors.add(:notification_limit, "must be greater than or equal to " \
- "storage_size_limit (Dashboard limit): #{storage_size_limit} " \
- "and less than or equal to enforcement_limit: #{enforcement_limit}")
+ if storage_size_limit > 0 && notification_limit < storage_size_limit
+ plan_limits.errors.add(
+ :notification_limit, "must be greater than or equal to the dashboard limit (#{storage_size_limit})"
+ )
+ end
+
+ return unless enforcement_limit > 0 && notification_limit > enforcement_limit
+
+ plan_limits.errors.add(
+ :notification_limit, "must be less than or equal to the enforcement limit (#{enforcement_limit})"
+ )
end
def validate_enforcement_limit
return unless parsed_params.include?(:enforcement_limit)
- return if enforcement_limit >= storage_size_limit && enforcement_limit >= notification_limit
+ return if unlimited_value?(:enforcement_limit)
+
+ if storage_size_limit > 0 && enforcement_limit < storage_size_limit
+ plan_limits.errors.add(
+ :enforcement_limit, "must be greater than or equal to the dashboard limit (#{storage_size_limit})"
+ )
+ end
+
+ return unless notification_limit > 0 && enforcement_limit < notification_limit
- plan_limits.errors.add(:enforcement_limit, "must be greater than or equal to " \
- "storage_size_limit (Dashboard limit): #{storage_size_limit} and " \
- "greater than or equal to notification_limit: #{notification_limit}")
+ plan_limits.errors.add(
+ :enforcement_limit, "must be greater than or equal to the notification limit (#{notification_limit})"
+ )
end
def validate_storage_size_limit
return unless parsed_params.include?(:storage_size_limit)
- return if storage_size_limit <= enforcement_limit && storage_size_limit <= notification_limit
+ return if unlimited_value?(:storage_size_limit)
- plan_limits.errors.add(:storage_size_limit, "(Dashboard limit) must be less than or equal to " \
- "enforcement_limit: #{enforcement_limit} " \
- "and notification_limit: #{notification_limit}")
+ if enforcement_limit > 0 && storage_size_limit > enforcement_limit
+ plan_limits.errors.add(
+ :dashboard_limit, "must be less than or equal to the enforcement limit (#{enforcement_limit})"
+ )
+ end
+
+ return unless notification_limit > 0 && storage_size_limit > notification_limit
+
+ plan_limits.errors.add(
+ :dashboard_limit, "must be less than or equal to the notification limit (#{notification_limit})"
+ )
end
# Overridden in EE
def parsed_params
params
end
+
+ def unlimited_value?(limit)
+ parsed_params[limit] == 0
+ end
end
end
end
diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml
index 35ee9a7679a..7dd4d119a62 100644
--- a/app/views/devise/passwords/edit.html.haml
+++ b/app/views/devise/passwords/edit.html.haml
@@ -7,13 +7,13 @@
= f.hidden_field :reset_password_token
.form-group.gl-px-5
= f.label _('New password'), for: "user_password"
- = f.password_field :password, autocomplete: 'new-password', class: "form-control gl-form-input top js-password-complexity-validation", required: true, title: _('This field is required.'), data: { qa_selector: 'password_field'}
+ = f.password_field :password, autocomplete: 'new-password', class: "form-control gl-form-input top js-password-complexity-validation", required: true, title: _('This field is required.'), data: { testid: 'password-field'}
= render_if_exists 'shared/password_requirements_list'
.form-group.gl-px-5
= f.label _('Confirm new password'), for: "user_password_confirmation"
- = f.password_field :password_confirmation, autocomplete: 'new-password', class: "form-control gl-form-input bottom", title: _('This field is required.'), data: { qa_selector: 'password_confirmation_field' }, required: true
+ = f.password_field :password_confirmation, autocomplete: 'new-password', class: "form-control gl-form-input bottom", title: _('This field is required.'), data: { testid: 'password-confirmation-field' }, required: true
.clearfix.gl-px-5.gl-pb-5
- = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { qa_selector: 'change_password_button' } }) do
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { testid: 'change-password-button' } }) do
= _('Change your password')
.clearfix.prepend-top-20
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
index 88dd4fd1721..d9b7c986a9f 100644
--- a/app/views/devise/sessions/_new_base.html.haml
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -1,11 +1,10 @@
= gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'gl-p-5 gl-show-field-errors js-arkose-labs-form', aria: { live: 'assertive' }, data: { testid: 'sign-in-form' }}) do |f|
.form-group
= f.label :login, _('Username or primary email')
- = f.text_field :login, value: @invite_email, class: 'form-control gl-form-input js-username-field', autocomplete: 'username', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off', required: true, title: _('This field is required.'), data: { qa_selector: 'login_field', testid: 'username-field' }
+ = f.text_field :login, value: @invite_email, class: 'form-control gl-form-input js-username-field', autocomplete: 'username', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off', required: true, title: _('This field is required.'), data: { testid: 'username-field' }
.form-group
= f.label :password, _('Password')
= f.password_field :password, class: 'form-control gl-form-input js-password', data: { id: "#{resource_name}_password",
- qa_selector: 'password_field',
testid: 'password-field',
name: "#{resource_name}[password]" }
.form-text.gl-text-right
@@ -22,5 +21,5 @@
.form-group
= f.gitlab_ui_checkbox_component :remember_me, _('Remember me'), checkbox_options: { autocomplete: 'off' }
- = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { class: 'js-sign-in-button', data: { qa_selector: 'sign_in_button', testid: 'sign-in-button' } }) do
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { class: 'js-sign-in-button', data: { testid: 'sign-in-button' } }) do
= _('Sign in')
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index 471cc053e6e..db7b7a4f729 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -6,13 +6,13 @@
= gitlab_ui_form_for(provider, url: omniauth_callback_path(:user, provider), html: { class: 'gl-p-5 gl-show-field-errors', aria: { live: 'assertive' }, data: { testid: 'new_ldap_user' }}) do |f|
.form-group
= f.label :username, _('Username')
- = f.text_field :username, name: :username, autocomplete: :username, class: 'form-control gl-form-input', title: _('This field is required.'), autofocus: 'autofocus', data: { qa_selector: 'username_field' }, required: true
+ = f.text_field :username, name: :username, autocomplete: :username, class: 'form-control gl-form-input', title: _('This field is required.'), autofocus: 'autofocus', data: { testid: 'username-field' }, required: true
.form-group
= f.label :password, _('Password')
- %input.form-control.gl-form-input.js-password{ data: { id: "#{provider}_password", name: 'password', qa_selector: 'password_field' } }
+ %input.form-control.gl-form-input.js-password{ data: { id: "#{provider}_password", name: 'password', testid: 'password-field' } }
- if render_remember_me
= f.gitlab_ui_checkbox_component :remember_me, _('Remember me'), checkbox_options: { name: :remember_me, autocomplete: 'off' }
- = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { qa_selector: 'sign_in_button' } }) do
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { testid: 'sign-in-button' } }) do
= submit_message
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index acfb16b64cd..1caf0bb5893 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -29,6 +29,6 @@
- if allow_signup?
%p{ class: "gl-mt-3 #{'gl-text-center' if Feature.enabled?(:restyle_login_page, @project)}" }
= _("Don't have an account yet?")
- = link_to _("Register now"), new_registration_path(:user, invite_email: @invite_email), data: { qa_selector: 'register_link' }
+ = link_to _("Register now"), new_registration_path(:user, invite_email: @invite_email), data: { testid: 'register-link' }
- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
= render 'devise/shared/omniauth_box'
diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml
index e3457040e6c..96f6f5cb095 100644
--- a/app/views/devise/sessions/two_factor.html.haml
+++ b/app/views/devise/sessions/two_factor.html.haml
@@ -5,7 +5,7 @@
= gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if @user.two_factor_webauthn_enabled?}" }) do |f|
.form-group
= f.label :otp_attempt, _('Enter verification code')
- = f.text_field :otp_attempt, class: 'form-control gl-form-input', required: true, autofocus: true, autocomplete: 'off', inputmode: 'numeric', title: _('This field is required.'), data: { qa_selector: 'two_fa_code_field' }
+ = f.text_field :otp_attempt, class: 'form-control gl-form-input', required: true, autofocus: true, autocomplete: 'off', inputmode: 'numeric', title: _('This field is required.'), data: { testid: 'two-fa-code-field' }
%p.form-text.text-muted.hint
= _("Enter the code from your two-factor authenticator app. If you've lost your device, you can enter one of your recovery codes.")
@@ -13,7 +13,7 @@
- resource_params = params[resource_name].presence || params
= f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0)
- = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { qa_selector: 'verify_code_button' } }) do
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { testid: 'verify-code-button' } }) do
= _("Verify code")
- if @user.two_factor_webauthn_enabled?
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index 73b9a3d5c5a..45062745b77 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -11,7 +11,7 @@
= _('Sign in with')
- enabled_button_based_providers.each do |provider|
- has_icon = provider_has_icon?(provider)
- = button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", data: { qa_selector: "#{qa_selector_for_provider(provider)}" }, class: "btn gl-button btn-default gl-mb-2 js-oauth-login gl-w-full", form: { class: restyle_login_page_enabled ? 'gl-mb-3' : 'gl-w-full gl-mb-3' } do
+ = button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", data: { testid: "#{test_id_for_provider(provider)}" }, class: "btn gl-button btn-default gl-mb-2 js-oauth-login gl-w-full", form: { class: restyle_login_page_enabled ? 'gl-mb-3' : 'gl-w-full gl-mb-3' } do
- if has_icon
= provider_image_tag(provider)
%span.gl-button-text
diff --git a/app/views/devise/shared/_signup_omniauth_provider_list.haml b/app/views/devise/shared/_signup_omniauth_provider_list.haml
index b9efcaa11b4..da778120e01 100644
--- a/app/views/devise/shared/_signup_omniauth_provider_list.haml
+++ b/app/views/devise/shared/_signup_omniauth_provider_list.haml
@@ -4,7 +4,7 @@
= _("Register with:")
.gl-text-center.gl-ml-auto.gl-mr-auto
- providers.each do |provider|
- = button_to omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}", data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label }, id: "oauth-login-#{provider}" do
+ = button_to omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{test_id_for_provider(provider)}", data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label }, id: "oauth-login-#{provider}" do
- if provider_has_icon?(provider)
= provider_image_tag(provider)
%span.gl-button-text
@@ -15,7 +15,7 @@
.gl-display-flex.gl-justify-content-between.gl-flex-wrap
- providers.each do |provider|
= button_to omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)),
- class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}",
+ class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{test_id_for_provider(provider)}",
data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label },
id: "oauth-login-#{provider}" do
- if provider_has_icon?(provider)
diff --git a/app/views/devise/shared/_tab_single.html.haml b/app/views/devise/shared/_tab_single.html.haml
index b7ba8870df5..9348a5e3451 100644
--- a/app/views/devise/shared/_tab_single.html.haml
+++ b/app/views/devise/shared/_tab_single.html.haml
@@ -1,2 +1,2 @@
= gl_tabs_nav({ class: 'new-session-tabs gl-border-0' }) do
- = gl_tab_link_to tab_title, '#', { item_active: true, class: 'gl-cursor-default!', tab_class: 'gl-bg-transparent!', tabindex: '-1', data: { qa_selector: 'sign_in_tab', testid: 'sign-in-tab' } }
+ = gl_tab_link_to tab_title, '#', { item_active: true, class: 'gl-cursor-default!', tab_class: 'gl-bg-transparent!', tabindex: '-1', data: { testid: 'sign-in-tab' } }
diff --git a/app/views/devise/shared/_tabs_ldap.html.haml b/app/views/devise/shared/_tabs_ldap.html.haml
index 76c4cf41a2d..e6bc38ba6dd 100644
--- a/app/views/devise/shared/_tabs_ldap.html.haml
+++ b/app/views/devise/shared/_tabs_ldap.html.haml
@@ -8,13 +8,13 @@
= render_if_exists "devise/shared/kerberos_tab"
- ldap_servers.each_with_index do |server, i|
%li.nav-item
- = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i == 0 && form_based_auth_provider_has_active_class?(:ldapmain))}", data: { toggle: 'tab', qa_selector: 'ldap_tab', testid: 'ldap-tab' }, role: 'tab'
+ = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i == 0 && form_based_auth_provider_has_active_class?(:ldapmain))}", data: { toggle: 'tab', testid: 'ldap-tab' }, role: 'tab'
= render_if_exists 'devise/shared/tab_smartcard'
- if show_password_form
%li.nav-item
- = link_to _('Standard'), '#login-pane', class: 'nav-link', data: { toggle: 'tab', qa_selector: 'standard_tab' }, role: 'tab'
+ = link_to _('Standard'), '#login-pane', class: 'nav-link', data: { toggle: 'tab', testid: 'standard-tab' }, role: 'tab'
- if render_signup_link && allow_signup?
%li.nav-item
- = link_to _('Register'), '#register-pane', class: 'nav-link', data: { toggle: 'tab', qa_selector: 'register_tab' }, role: 'tab'
+ = link_to _('Register'), '#register-pane', class: 'nav-link', data: { toggle: 'tab', testid: 'register-tab' }, role: 'tab'
diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml
index fd5088e04b0..116732cd98d 100644
--- a/app/views/doorkeeper/authorizations/new.html.haml
+++ b/app/views/doorkeeper/authorizations/new.html.haml
@@ -51,5 +51,5 @@
= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method
= render Pajamas::ButtonComponent.new(type: :submit,
variant: :danger,
- button_options: { id: 'commit-changes', class: 'gl-ml-3', qa_selector: 'authorization_button'}) do
+ button_options: { id: 'commit-changes', class: 'gl-ml-3', testid: 'authorization_button'}) do
= _("Authorize")
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index 4e9ae7c7fd8..7794e3c9853 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -3,7 +3,7 @@
!!! 5
%html.html-devise-layout{ lang: I18n.locale }
= render "layouts/head", { startup_filename: 'signin' }
- %body.gl-h-full.login-page.navless{ class: "#{system_message_class} #{user_application_theme} #{client_class_list}", data: { page: body_data_page, qa_selector: 'login_page' } }
+ %body.gl-h-full.login-page.navless{ class: "#{system_message_class} #{user_application_theme} #{client_class_list}", data: { page: body_data_page, testid: 'login-page' } }
= header_message
= render "layouts/init_client_detection_flags"
- if Feature.enabled?(:restyle_login_page, @project)
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 993094c6889..fb875c67b6d 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -110,7 +110,7 @@
- if header_link?(:user_dropdown)
%li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { testid: 'user-dropdown' }, class: ('mr-0' if has_impersonation_link) }
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown", track_label: "profile_dropdown", track_action: "click_dropdown", track_property: "navigation_top" } do
- = render Pajamas::AvatarComponent.new(current_user, size: 24, class: 'header-user-avatar', avatar_options: { data: { testid: 'user_avatar_content' } })
+ = render Pajamas::AvatarComponent.new(current_user, size: 24, class: 'header-user-avatar', avatar_options: { data: { testid: 'user-avatar-content' } })
= render_if_exists 'layouts/header/user_notification_dot', project: project, namespace: group
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
diff --git a/app/views/layouts/terms.html.haml b/app/views/layouts/terms.html.haml
index 32f00a4c0c6..621c0579226 100644
--- a/app/views/layouts/terms.html.haml
+++ b/app/views/layouts/terms.html.haml
@@ -25,6 +25,6 @@
.gl-text-right.gl-line-height-normal
.gl-font-weight-bold= current_user.name
.gl-text-gray-700 @#{current_user.username}
- = render Pajamas::AvatarComponent.new(current_user, size: 32, avatar_options: { data: { qa_selector: 'user_avatar_content' } })
+ = render Pajamas::AvatarComponent.new(current_user, size: 32, avatar_options: { data: { testid: 'user-avatar-content' } })
- c.with_body do
= yield
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 799dfaae8c5..75dba925328 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -30,7 +30,7 @@
= render Pajamas::ButtonComponent.new(variant: :confirm, href: profile_two_factor_auth_path) do
= _('Manage two-factor authentication')
- else
- = render Pajamas::ButtonComponent.new(variant: :confirm, href: profile_two_factor_auth_path, button_options: { data: { qa_selector: 'enable_2fa_button' }}) do
+ = render Pajamas::ButtonComponent.new(variant: :confirm, href: profile_two_factor_auth_path, button_options: { data: { testid: 'enable-2fa-button' }}) do
= _('Enable two-factor authentication')
- if display_providers_on_profile?
@@ -76,7 +76,7 @@
= render 'users/deletion_guidance', user: current_user
-# Delete button here
- = render Pajamas::ButtonComponent.new(variant: :danger, button_options: { id: 'delete-account-button', disabled: true, data: { qa_selector: 'delete_account_button' }}) do
+ = render Pajamas::ButtonComponent.new(variant: :danger, button_options: { id: 'delete-account-button', disabled: true, data: { testid: 'delete-account-button' }}) do
= s_('Profiles|Delete account')
#delete-account-modal{ data: { action_url: user_registration_path,
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index ff0b31da022..25badbcdb16 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -29,7 +29,7 @@
= _("To add the entry manually, provide the following details to the application on your phone.")
%p.gl-mt-0.gl-mb-0
= _('Account: %{account}') % { account: @account_string }
- %p.gl-mt-0.gl-mb-0{ data: { qa_selector: 'otp_secret_content' } }
+ %p.gl-mt-0.gl-mb-0{ data: { testid: 'otp-secret-content' } }
= _('Key:')
%code.two-factor-secret= current_user.otp_secret.scan(/.{4}/).join(' ')
%p.gl-mb-0.two-factor-new-manual-content
@@ -46,14 +46,14 @@
- if current_password_required?
.form-group
= label_tag :current_password, _('Current password'), class: 'label-bold'
- = password_field_tag :current_password, nil, autocomplete: 'current-password', required: true, class: 'form-control gl-form-input', data: { qa_selector: 'current_password_field' }
+ = password_field_tag :current_password, nil, autocomplete: 'current-password', required: true, class: 'form-control gl-form-input', data: { testid: 'current-password-field' }
%p.form-text.text-muted
= _('Your current password is required to register a two-factor authenticator app.')
.form-group
= label_tag :pin_code, _('Enter verification code'), class: "label-bold"
- = text_field_tag :pin_code, nil, autocomplete: 'off', inputmode: 'numeric', class: "form-control gl-form-input", required: true, data: { qa_selector: 'pin_code_field' }
+ = text_field_tag :pin_code, nil, autocomplete: 'off', inputmode: 'numeric', class: "form-control gl-form-input", required: true, data: { testid: 'pin-code-field' }
.gl-mt-3
- = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, button_options: { data: { qa_selector: 'register_2fa_app_button' } }) do
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, button_options: { data: { testid: 'register-2fa-app-button' } }) do
= _('Register with two-factor app')
%hr
diff --git a/app/views/shared/access_tokens/_form.html.haml b/app/views/shared/access_tokens/_form.html.haml
index 3bf85da83b1..79c4bfca630 100644
--- a/app/views/shared/access_tokens/_form.html.haml
+++ b/app/views/shared/access_tokens/_form.html.haml
@@ -15,7 +15,7 @@
.form-group
= f.label :name, s_('AccessTokens|Token name'), class: 'label-bold'
- = f.text_field :name, class: 'form-control gl-form-input gl-form-input-xl', required: true, data: { qa_selector: 'access_token_name_field' }, :'aria-describedby' => 'access_token_help_text'
+ = f.text_field :name, class: 'form-control gl-form-input gl-form-input-xl', required: true, data: { testid: 'access-token-name-field' }, :'aria-describedby' => 'access_token_help_text'
%span.form-text.text-muted#access_token_help_text
- if resource
- resource_type = resource.is_a?(Group) ? "group" : "project"
@@ -42,6 +42,6 @@
= render 'shared/tokens/scopes_form', prefix: prefix, description_prefix: description_prefix, token: token, scopes: scopes, f: f
.gl-mt-3
- = f.submit s_('AccessTokens|Create %{type}') % { type: type }, data: { qa_selector: 'create_token_button' }, pajamas_button: true
+ = f.submit s_('AccessTokens|Create %{type}') % { type: type }, data: { testid: 'create-token-button' }, pajamas_button: true
= render Pajamas::ButtonComponent.new(button_options: { type: 'reset', class: 'gl-ml-2 js-toggle-button' }) do
= _('Cancel')
diff --git a/app/views/shared/deploy_tokens/_form.html.haml b/app/views/shared/deploy_tokens/_form.html.haml
index bb7e0d774cc..44d261b84f1 100644
--- a/app/views/shared/deploy_tokens/_form.html.haml
+++ b/app/views/shared/deploy_tokens/_form.html.haml
@@ -6,12 +6,12 @@
.form-group
= f.label :name, class: 'label-bold'
- = f.text_field :name, class: 'form-control gl-form-input', data: { qa_selector: 'deploy_token_name_field' }, required: true
+ = f.text_field :name, class: 'form-control gl-form-input', data: { testid: 'deploy-token-name-field' }, required: true
.text-secondary= s_('DeployTokens|Enter a unique name for your deploy token.')
.form-group
= f.label :expires_at, _('Expiration date (optional)'), class: 'label-bold'
- = f.gitlab_ui_datepicker :expires_at, data: { qa_selector: 'deploy_token_expires_at_field' }, value: f.object.expires_at
+ = f.gitlab_ui_datepicker :expires_at, data: { testid: 'deploy-token-expires-at-field' }, value: f.object.expires_at
.text-secondary= s_('DeployTokens|Enter an expiration date for your token. Defaults to never expire.')
.form-group
@@ -22,15 +22,15 @@
.form-group
= f.label :scopes, _('Scopes (select at least one)'), class: 'label-bold'
- = f.gitlab_ui_checkbox_component :read_repository, 'read_repository', help_text: s_('DeployTokens|Allows read-only access to the repository.'), checkbox_options: { data: { qa_selector: 'deploy_token_read_repository_checkbox' } }
+ = f.gitlab_ui_checkbox_component :read_repository, 'read_repository', help_text: s_('DeployTokens|Allows read-only access to the repository.'), checkbox_options: { data: { testid: 'deploy-token-read-repository-checkbox' } }
- if container_registry_enabled?(group_or_project)
- = f.gitlab_ui_checkbox_component :read_registry, 'read_registry', help_text: s_('DeployTokens|Allows read-only access to registry images.'), checkbox_options: { data: { qa_selector: 'deploy_token_read_registry_checkbox' } }
- = f.gitlab_ui_checkbox_component :write_registry, 'write_registry', help_text: s_('DeployTokens|Allows write access to registry images.'), checkbox_options: { data: { qa_selector: 'deploy_token_write_registry_checkbox' } }
+ = f.gitlab_ui_checkbox_component :read_registry, 'read_registry', help_text: s_('DeployTokens|Allows read-only access to registry images.'), checkbox_options: { data: { testid: 'deploy-token-read-registry-checkbox' } }
+ = f.gitlab_ui_checkbox_component :write_registry, 'write_registry', help_text: s_('DeployTokens|Allows write access to registry images.'), checkbox_options: { data: { testid: 'deploy-token-write-registry-checkbox' } }
- if packages_registry_enabled?(group_or_project)
- = f.gitlab_ui_checkbox_component :read_package_registry, 'read_package_registry', help_text: s_('DeployTokens|Allows read-only access to the package registry.'), checkbox_options: { data: { qa_selector: 'deploy_token_read_package_registry_checkbox' } }
- = f.gitlab_ui_checkbox_component :write_package_registry, 'write_package_registry', help_text: s_('DeployTokens|Allows read and write access to the package registry.'), checkbox_options: { data: { qa_selector: 'deploy_token_write_package_registry_checkbox' } }
+ = f.gitlab_ui_checkbox_component :read_package_registry, 'read_package_registry', help_text: s_('DeployTokens|Allows read-only access to the package registry.'), checkbox_options: { data: { testid: 'deploy-token-read-package-registry-checkbox' } }
+ = f.gitlab_ui_checkbox_component :write_package_registry, 'write_package_registry', help_text: s_('DeployTokens|Allows read and write access to the package registry.'), checkbox_options: { data: { testid: 'deploy-token-write-package-registry-checkbox' } }
.gl-mt-3
- = f.submit s_('DeployTokens|Create deploy token'), data: { qa_selector: 'create_deploy_token_button' }, pajamas_button: true
+ = f.submit s_('DeployTokens|Create deploy token'), data: { testid: 'create-deploy-token-button' }, pajamas_button: true
diff --git a/app/views/shared/deploy_tokens/_new_deploy_token.html.haml b/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
index 30917ee6fff..2bc2e6c5b81 100644
--- a/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
+++ b/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
@@ -1,11 +1,11 @@
-.created-deploy-token-container.info-well{ data: { qa_selector: 'created_deploy_token_container' } }
+.created-deploy-token-container.info-well{ data: { testid: 'created-deploy-token-container' } }
.well-segment
%h5.gl-mt-0
= s_('DeployTokens|Your new Deploy Token username')
.form-group
.input-group
- = text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { qa_selector: 'deploy_token_user_field' }
+ = text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { testid: 'deploy-token-user-field' }
.input-group-append
= deprecated_clipboard_button(text: deploy_token.username, title: s_('DeployTokens|Copy username'), placement: 'left')
%span.deploy-token-help-block.gl-mt-2.text-success
@@ -15,7 +15,7 @@
.form-group
.input-group
- = text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { qa_selector: 'deploy_token_field' }
+ = text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { testid: 'deploy-token-field' }
.input-group-append
= deprecated_clipboard_button(text: deploy_token.token, title: s_('DeployTokens|Copy deploy token'), placement: 'left')
%span.deploy-token-help-block.gl-mt-2.text-danger
diff --git a/doc/api/users.md b/doc/api/users.md
index a1159441056..cb9951a1c45 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -2336,6 +2336,7 @@ Prerequisites:
- You must be an administrator or have the Owner role of the target namespace or project.
- For `instance_type`, you must be an administrator of the GitLab instance.
+- For `group_type` or `project_type` with an Owner role, an administrator must not have enabled [restrict runner registration](../administration/settings/continuous_integration.md#restrict-runner-registration-by-all-users-in-an-instance).
- An access token with the `create_runner` scope.
Be sure to copy or save the `token` in the response, the value cannot be retrieved again.
diff --git a/doc/architecture/blueprints/gcp_integration/decisions/001_no_credentials.md b/doc/architecture/blueprints/gcp_integration/decisions/001_no_credentials.md
deleted file mode 100644
index 70e696def96..00000000000
--- a/doc/architecture/blueprints/gcp_integration/decisions/001_no_credentials.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-description: 'GCP Integration ADR 001: Do not store GCP credentials in GitLab'
----
-
-# GCP Integration ADR 001: Do not store GCP credentials in GitLab
-
-## Context
-
-Users need to be able to perform certain actions within GCP based on their
-GitLab project membership and permissions. For example, users of the
-integration need a mechanism to push packages to the Google Artifact Registry
-and to provision Runners within their GCP projects.
-
-## Decision
-
-Rely primarily on [Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation)
-to manage authorization across the platform. This enables a GitLab user or a
-group / project owner to authenticate within GCP via OAuth and have the ability
-to assume / configure IAM roles in GCP based on their GitLab user attributes.
diff --git a/doc/architecture/blueprints/gcp_integration/index.md b/doc/architecture/blueprints/gcp_integration/index.md
deleted file mode 100644
index ec5412442e6..00000000000
--- a/doc/architecture/blueprints/gcp_integration/index.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-status: proposed
-creation-date: "2023-10-26"
-authors: [ "@sgoldstein" ]
-coach: "@jessieay"
-approvers: []
-owning-stage: "~devops::verify"
-participating-stages: ["~devops::verify", "~devops::package", "~devops::govern"]
----
-
-<!-- Blueprints often contain forward-looking statements -->
-<!-- vale gitlab.FutureTense = NO -->
-
-# GCP Integration
-
-## Summary
-
-GitLab and Google Cloud Platform (GCP) provide complementary tooling which we are integrating via our [partnership](https://about.gitlab.com/blog/2023/08/29/gitlab-google-partnership-s3c/).
-
-As phase 1 of this integration, we plan to:
-
-1. Authentication/Authorization Integration. Onboarding, account-linking and permission management between GitLab and GCP Identities.
-1. Continuous Integration. Provision Runners into linked GCP projects.
-1. Artifact Management. Package Registry integration with Google Artifact Registry.
-
-This design doc intends to capture the architecture for this initial integration phase. It should answer the following:
-
-1. How users, permissions, and service accounts managed between GitLab and GCP identities
-1. How to automatically provision GitLab Runners on Google Cloud Compute (GCE) in GCP customer project via Terraform, with or without VPC configured
-1. How to automatically push containers from GitLab CI to Google Artifact Registry, view those containers in GitLab, and trace to builds.
-
-NOTE:
-GitLab package team has begun work on architecture design in [Google Artifact Registry Integration](../google_artifact_registry_integration/index.md)
-
-## Decisions
-
-- [ADR-001: Do not store GCP credentials in GitLab](decisions/001_no_credentials.md)
-
-## Proposal
-
-### Authentication/Authorization
-
-Rely primarily on [Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation) to manage authorization across the platform. This enables a GitLab user to authenticate within GCP via OAuth and have the ability to assume IAM roles in GCP based on their GitLab user attributes.
-
-#### Workload Identity Pool Provider creation in GCP
-
-As a GCP and GitLab customer (GitLab Group Owner), I would like to create a Workload Identity Pool and Provider to allow GitLab users to authenticate with GCP when executing CI workloads that utilize GCP services.
-
-Steps:
-
- 1. Customer navigates to GitLab → Operate → Google Cloud
- 1. Customer authenticates with GCP through an OAuth flow, if the customer is not already authenticated.
- 1. Creates a GCP Workload Identity Pool and Provider with OpenID Connect configuration in customers GCP Project, by providing the GCP project number at creation time.
- 1. There is an [API to go from projectNum->projectID and back](https://cloud.google.com/resource-manager/reference/rest/v3/projects/get).
-
-#### GCP resource policy creation in GitLab for Workload Identity Provider
-
-As a GCP customer, I would like to authorize GitLab’s use of my GCP resources for the purpose of the GitLab - GCP Integration:
-
-Steps:
-
-1. Customer navigates to GitLab → Operate → Google Cloud
-1. Customer authenticates with GCP through an OAuth flow, if the customer is not already authenticated.
-1. Customer selects previously created Workload Identity Provider and adds applicable resource policies by specifying the:
- 1. GCP project number
- 1. One or more GitLab OpenID claims and associated values to use for authenticating a workload
- 1. One or more GCP resources IAM roles the authenticated workload will be authorized to use
-1. Customer is presented with a prompt asking them to confirm that they wish to proceed in creating this GCP resource policy
- 1. If a customer confirms, a policy for the Workload Identity Provider is created in the specified GCP project.
-1. If additional GCP resource policies are required, the customer can repeat steps 2 and 3.
-
-NOTE:
-The user should also be able to edit (claims, values and IAM roles) and delete GCP resources policies.
-
-#### User to User authentication linkage
-
-As an existing GitLab user, I can use OAuth to link my existing GCP account so that I can seamlessly exchange data between the two
-
-This will be used for the following use cases:
-
- 1. In Artifact Registry where the individual user can see artifacts in GCP
- 1. Creation of workload identity federation pools
- 1. List, pull and push images to Artifact Registry from GitLab
-
-Also applies in the reverse direction. Existing GCP users can OAuth into GitLab and link their accounts.
-
-#### Runner Provisioning
-
-TBA
-
-#### GitLab CI to Google Artifact Registry Authn/Authz
-
-TBA
-
-## Design and implementation details
diff --git a/lib/gitlab/analytics/cycle_analytics/request_params.rb b/lib/gitlab/analytics/cycle_analytics/request_params.rb
index cea25ba2db4..0c4a0afa1d5 100644
--- a/lib/gitlab/analytics/cycle_analytics/request_params.rb
+++ b/lib/gitlab/analytics/cycle_analytics/request_params.rb
@@ -203,7 +203,8 @@ module Gitlab
def validate_date_range
return if created_after.nil? || created_before.nil?
- if (created_before - created_after) > MAX_RANGE_DAYS
+ time_period = created_before.at_beginning_of_day - created_after.at_beginning_of_day
+ if time_period > MAX_RANGE_DAYS
errors.add(:created_after, s_('CycleAnalytics|The given date range is larger than 180 days'))
end
end
diff --git a/package.json b/package.json
index cc9c846c800..cf61540faca 100644
--- a/package.json
+++ b/package.json
@@ -58,7 +58,7 @@
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.3.0",
"@gitlab/svgs": "3.69.0",
- "@gitlab/ui": "67.3.0",
+ "@gitlab/ui": "67.3.3",
"@gitlab/visual-review-tools": "1.7.3",
"@gitlab/web-ide": "0.0.1-dev-20231004090414",
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
diff --git a/qa/qa/mobile/page/main/menu.rb b/qa/qa/mobile/page/main/menu.rb
index 73d3b9f7982..9bd2fbccbbb 100644
--- a/qa/qa/mobile/page/main/menu.rb
+++ b/qa/qa/mobile/page/main/menu.rb
@@ -22,10 +22,10 @@ module QA
end
def open_mobile_menu
- if has_no_element?(:user_avatar_content)
+ if has_no_element?('user-avatar-content')
Support::Retrier.retry_until do
click_element(:mobile_navbar_button)
- has_element?(:user_avatar_content)
+ has_element?('user-avatar-content')
end
end
end
diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb
index c80df535aba..3f411c05587 100644
--- a/qa/qa/page/component/access_tokens.rb
+++ b/qa/qa/page/component/access_tokens.rb
@@ -15,12 +15,12 @@ module QA
end
base.view 'app/assets/javascripts/access_tokens/components/expires_at_field.vue' do
- element :expiry_date_field
+ element 'expiry-date-field'
end
base.view 'app/views/shared/access_tokens/_form.html.haml' do
- element :access_token_name_field
- element :create_token_button
+ element 'access-token-name-field'
+ element 'create-token-button'
end
base.view 'app/views/shared/tokens/_scopes_form.html.haml' do
@@ -28,16 +28,16 @@ module QA
end
base.view 'app/assets/javascripts/access_tokens/components/new_access_token_app.vue' do
- element :access_token_section
- element :created_access_token_field
+ element 'access-token-section'
+ element 'created-access-token-field'
end
base.view 'app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue' do
- element :toggle_visibility_button
+ element 'toggle-visibility-button'
end
base.view 'app/assets/javascripts/access_tokens/components/access_token_table_app.vue' do
- element :revoke_button
+ element 'revoke-button'
end
base.view 'app/views/profiles/personal_access_tokens/index.html.haml' do
@@ -62,7 +62,7 @@ module QA
end
def fill_token_name(name)
- fill_element(:access_token_name_field, name)
+ fill_element('access-token-name-field', name)
end
def check_api
@@ -70,12 +70,12 @@ module QA
end
def click_create_token_button
- click_element(:create_token_button)
+ click_element('create-token-button')
end
def created_access_token
- within_element(:access_token_section) do
- find_element(:created_access_token_field).value
+ within_element('access-token-section') do
+ find_element('created-access-token-field').value
end
end
@@ -87,7 +87,7 @@ module QA
raise "Expiry date must be in YYYY-MM-DD format"
end
- fill_element(:expiry_date_field, date)
+ fill_element('expiry-date-field', date)
end
def has_token_row_for_name?(token_name)
@@ -100,7 +100,7 @@ module QA
def revoke_first_token_with_name(token_name)
within first_token_row_for_name(token_name) do
- click_element(:revoke_button)
+ click_element('revoke-button')
end
click_confirmation_ok_button
diff --git a/qa/qa/page/component/confirm_modal.rb b/qa/qa/page/component/confirm_modal.rb
index 26d06ecaa22..fbc3cfa9aed 100644
--- a/qa/qa/page/component/confirm_modal.rb
+++ b/qa/qa/page/component/confirm_modal.rb
@@ -15,24 +15,24 @@ module QA
end
base.view 'app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue' do
- element :confirm_danger_modal_button
- element :confirm_danger_field
+ element 'confirm-danger-modal-button'
+ element 'confirm-danger-field'
end
end
def fill_confirmation_text(text)
- fill_element(:confirm_danger_field, text)
+ fill_element('confirm-danger-field', text)
end
def wait_for_confirm_button_enabled
wait_until(reload: false) do
- !find_element(:confirm_danger_modal_button).disabled?
+ !find_element('confirm-danger-modal-button').disabled?
end
end
def confirm_transfer
wait_for_confirm_button_enabled
- click_element(:confirm_danger_modal_button)
+ click_element('confirm-danger-modal-button')
end
def click_confirmation_ok_button
diff --git a/qa/qa/page/component/members/invite_members_modal.rb b/qa/qa/page/component/members/invite_members_modal.rb
index b9d0b382ba1..66f5cef87f4 100644
--- a/qa/qa/page/component/members/invite_members_modal.rb
+++ b/qa/qa/page/component/members/invite_members_modal.rb
@@ -12,37 +12,37 @@ module QA
super
base.view 'app/assets/javascripts/invite_members/components/invite_modal_base.vue' do
- element :invite_button
- element :access_level_dropdown
+ element 'invite-modal-submit'
+ element 'access-level-dropdown'
element 'invite-modal'
end
base.view 'app/assets/javascripts/invite_members/components/members_token_select.vue' do
- element :members_token_select_input
+ element 'members-token-select-input'
end
base.view 'app/assets/javascripts/invite_members/components/invite_group_trigger.vue' do
- element :invite_a_group_button
+ element 'invite-a-group-button'
end
- base.view 'app/assets/javascripts/invite_members/constants.js' do
- element :invite_members_button
+ base.view 'app/assets/javascripts/invite_members/components/invite_members_trigger.vue' do
+ element 'invite-members-button'
end
end
def open_invite_members_modal
- click_element :invite_members_button
+ click_element 'invite-members-button'
end
def open_invite_group_modal
- click_element :invite_a_group_button
+ click_element 'invite-a-group-button'
end
def add_member(username, access_level = 'Developer', refresh_page: true)
open_invite_members_modal
within_element('invite-modal') do
- fill_element(:members_token_select_input, username)
+ fill_element('members-token-select-input', username)
Support::WaitForRequests.wait_for_requests
click_button(username, match: :prefer_exact)
set_access_level(access_level)
@@ -68,7 +68,7 @@ module QA
end
def send_invite(refresh = false)
- click_element :invite_button
+ click_element 'invite-modal-submit'
Support::WaitForRequests.wait_for_requests
page.refresh if refresh
end
@@ -77,7 +77,7 @@ module QA
def set_access_level(access_level)
# Guest option is selected by default, skipping these steps if desired option is 'Guest'
- select_element(:access_level_dropdown, access_level) unless access_level == 'Guest'
+ select_element('access-level-dropdown', access_level) unless access_level == 'Guest'
end
end
end
diff --git a/qa/qa/page/group/settings/group_deploy_tokens.rb b/qa/qa/page/group/settings/group_deploy_tokens.rb
index c1c3303113b..c76c910e857 100644
--- a/qa/qa/page/group/settings/group_deploy_tokens.rb
+++ b/qa/qa/page/group/settings/group_deploy_tokens.rb
@@ -6,58 +6,58 @@ module QA
module Settings
class GroupDeployTokens < Page::Base
view 'app/views/shared/deploy_tokens/_form.html.haml' do
- element :deploy_token_name_field
- element :deploy_token_expires_at_field
- element :deploy_token_read_repository_checkbox
- element :deploy_token_read_package_registry_checkbox
- element :deploy_token_read_registry_checkbox
- element :deploy_token_write_package_registry_checkbox
- element :create_deploy_token_button
+ element 'deploy-token-name-field'
+ element 'deploy-token-expires-at-field'
+ element 'deploy-token-read-repository-checkbox'
+ element 'deploy-token-read-package-registry-checkbox'
+ element 'deploy-token-read-registry-checkbox'
+ element 'deploy-token-write-package-registry-checkbox'
+ element 'create-deploy-token-button'
end
view 'app/views/shared/deploy_tokens/_new_deploy_token.html.haml' do
- element :created_deploy_token_container
- element :deploy_token_user_field
- element :deploy_token_field
+ element 'created-deploy-token-container'
+ element 'deploy-token-user-field'
+ element 'deploy-token-field'
end
def fill_token_name(name)
- fill_element(:deploy_token_name_field, name)
+ fill_element('deploy-token-name-field', name)
end
def fill_token_expires_at(expires_at)
- fill_element(:deploy_token_expires_at_field, expires_at.to_s + "\n")
+ fill_element('deploy-token-expires-at-field', expires_at.to_s + "\n")
end
def fill_scopes(read_repository: false, read_registry: false, read_package_registry: false, write_package_registry: false )
- check_element(:deploy_token_read_repository_checkbox, true) if read_repository
- check_element(:deploy_token_read_package_registry_checkbox, true) if read_package_registry
- check_element(:deploy_token_read_registry_checkbox, true) if read_registry
- check_element(:deploy_token_write_package_registry_checkbox, true) if write_package_registry
+ check_element('deploy-token-read-repository-checkbox', true) if read_repository
+ check_element('deploy-token-read-package-registry-checkbox', true) if read_package_registry
+ check_element('deploytoken-read-registry-checkbox', true) if read_registry
+ check_element('deploy-token-write-package-registry-checkbox', true) if write_package_registry
end
def add_token
- click_element(:create_deploy_token_button)
+ click_element('create-deploy-token-button')
end
def token_username
within_new_project_deploy_token do
- find_element(:deploy_token_user_field).value
+ find_element('deploy-token-user-field').value
end
end
def token_password
within_new_project_deploy_token do
- find_element(:deploy_token_field).value
+ find_element('deploy-token-field').value
end
end
private
def within_new_project_deploy_token(&block)
- has_element?(:created_deploy_token_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
+ has_element?('created-deploy-token-container', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
- within_element(:created_deploy_token_container, &block)
+ within_element('created-deploy-token-container', &block)
end
end
end
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index 1fd0b5b453c..a1c496a1f57 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -7,55 +7,55 @@ module QA
include Layout::Flash
view 'app/views/devise/passwords/edit.html.haml' do
- element :password_field
- element :password_confirmation_field
- element :change_password_button
+ element 'password-field'
+ element 'password-confirmation-field'
+ element 'change-password-button'
end
view 'app/views/devise/sessions/new.html.haml' do
- element :register_link
+ element 'register-link'
end
view 'app/views/devise/sessions/_new_base.html.haml' do
- element :login_field
- element :password_field
- element :sign_in_button
+ element 'username-field'
+ element 'password-field'
+ element 'sign-in-button'
end
view 'app/views/devise/sessions/_new_ldap.html.haml' do
- element :username_field
- element :password_field
- element :sign_in_button
+ element 'username-field'
+ element 'password-field'
+ element 'sign-in-button'
end
view 'app/views/devise/shared/_tabs_ldap.html.haml' do
- element :ldap_tab
- element :standard_tab
- element :register_tab
+ element 'ldap-tab'
+ element 'standard-tab'
+ element 'register-tab'
end
view 'app/views/devise/shared/_tab_single.html.haml' do
- element :sign_in_tab
+ element 'sign-in-tab'
end
view 'app/helpers/auth_helper.rb' do
- element :saml_login_button
- element :github_login_button
- element :oidc_login_button
- element :gitlab_oauth_login_button
- element :facebook_login_button
+ element 'saml-login-button'
+ element 'github-login-button'
+ element 'oidc-login-button'
+ element 'gitlab-oauth-login-button'
+ element 'facebook-login-button'
end
view 'app/views/layouts/devise.html.haml' do
- element :login_page, required: true
+ element 'login-page', required: true
end
def can_sign_in?
- has_element?(:sign_in_button)
+ has_element?('sign-in-button')
end
def on_login_page?
- has_element?(:login_page, wait: 0)
+ has_element?('login-page', wait: 0)
end
def sign_in_using_credentials(user: nil, skip_page_validation: false)
@@ -98,9 +98,9 @@ module QA
switch_to_ldap_tab
- fill_element :username_field, user.ldap_username
- fill_element :password_field, user.ldap_password
- click_element :sign_in_button
+ fill_element 'username-field', user.ldap_username
+ fill_element 'password-field', user.ldap_password
+ click_element 'sign-in-button'
end
Page::Main::Menu.perform(&:signed_in?)
@@ -130,15 +130,15 @@ module QA
end
def has_sign_in_tab?(wait: Capybara.default_max_wait_time)
- has_element?(:sign_in_tab, wait: wait)
+ has_element?('sign-in-tab', wait: wait)
end
def has_ldap_tab?
- has_element?(:ldap_tab)
+ has_element?('ldap-tab')
end
def has_standard_tab?
- has_element?(:standard_tab)
+ has_element?('standard-tab')
end
def sign_in_tab?
@@ -162,45 +162,45 @@ module QA
end
def switch_to_sign_in_tab
- click_element :sign_in_tab
+ click_element 'sign-in-tab'
end
def switch_to_register_page
set_initial_password_if_present
- click_element :register_link
+ click_element 'register-link'
end
def switch_to_ldap_tab
- click_element :ldap_tab
+ click_element 'ldap-tab'
end
def switch_to_standard_tab
- click_element :standard_tab
+ click_element 'standard-tab'
end
def sign_in_with_github
set_initial_password_if_present
- click_element :github_login_button
+ click_element 'github-login-button'
end
def sign_in_with_facebook
set_initial_password_if_present
- click_element :facebook_login_button
+ click_element 'facebook-login-button'
end
def sign_in_with_saml
set_initial_password_if_present
- click_element :saml_login_button
+ click_element 'saml-login-button'
end
def sign_in_with_gitlab_oidc
set_initial_password_if_present
- click_element :oidc_login_button
+ click_element 'oidc-login-button'
end
def sign_in_with_gitlab_oauth
set_initial_password_if_present
- click_element :gitlab_oauth_login_button
+ click_element 'gitlab-oauth-login-button'
end
def sign_out_and_sign_in_as(user:)
@@ -233,7 +233,7 @@ module QA
click_accept_all_cookies if Runtime::Env.running_on_dot_com? && has_accept_all_cookies_button?
- click_element :sign_in_button
+ click_element 'sign-in-button'
Support::WaitForRequests.wait_for_requests
@@ -254,16 +254,16 @@ module QA
end
def fill_in_credential(user)
- fill_element :login_field, user.username
- fill_element :password_field, user.password
+ fill_element 'username-field', user.username
+ fill_element 'password-field', user.password
end
def set_initial_password_if_present
return unless has_content?('Change your password')
- fill_element :password_field, Runtime::User.password
- fill_element :password_confirmation_field, Runtime::User.password
- click_element :change_password_button
+ fill_element 'password-field', Runtime::User.password
+ fill_element 'password-confirmation-field', Runtime::User.password
+ click_element 'change-password-button'
end
end
end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 73d48c6fcbf..af446291b3c 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -16,9 +16,9 @@ module QA
view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do
element 'user-dropdown', required: !Runtime::Env.phone_layout?
- element :user_avatar_content, required: !Runtime::Env.phone_layout?
+ element 'user-avatar-content', required: !Runtime::Env.phone_layout?
element :sign_out_link
- element :edit_profile_link
+ element 'edit-profile-link'
end
view 'app/assets/javascripts/super_sidebar/components/user_menu_profile_item.vue' do
@@ -118,7 +118,7 @@ module QA
has_element?('user-profile-link', text: /#{user.username}/)
end
# we need to close user menu because plain user link check will leave it open
- click_element :user_avatar_content if has_element?('user-profile-link', wait: 0)
+ click_element 'user-avatar-content' if has_element?('user-profile-link', wait: 0)
end
def not_signed_in?
@@ -150,7 +150,7 @@ module QA
def click_edit_profile_link
retry_until(reload: false) do
within_user_menu do
- click_element(:edit_profile_link)
+ click_element('edit-profile-link')
end
has_text?('User Settings')
@@ -164,11 +164,11 @@ module QA
end
def has_personal_area?(wait: Capybara.default_max_wait_time)
- has_element?(:user_avatar_content, wait: wait)
+ has_element?('user-avatar-content', wait: wait)
end
def has_no_personal_area?(wait: Capybara.default_max_wait_time)
- has_no_element?(:user_avatar_content, wait: wait)
+ has_no_element?('user-avatar-content', wait: wait)
end
def click_stop_impersonation_link
@@ -189,7 +189,7 @@ module QA
def within_user_menu(&block)
within_element(:navbar) do
- click_element :user_avatar_content unless has_element?('user-profile-link', wait: 1)
+ click_element 'user-avatar-content' unless has_element?('user-profile-link', wait: 1)
within_element('user-dropdown', &block)
end
diff --git a/qa/qa/page/main/oauth.rb b/qa/qa/page/main/oauth.rb
index 2b1a9ab2b6a..2ac99df905a 100644
--- a/qa/qa/page/main/oauth.rb
+++ b/qa/qa/page/main/oauth.rb
@@ -5,7 +5,7 @@ module QA
module Main
class OAuth < Page::Base
view 'app/views/doorkeeper/authorizations/new.html.haml' do
- element :authorization_button
+ element 'authorization_button'
end
def needs_authorization?
@@ -13,7 +13,7 @@ module QA
end
def authorize!
- click_element :authorization_button
+ click_element 'authorization_button'
end
end
end
diff --git a/qa/qa/page/main/terms.rb b/qa/qa/page/main/terms.rb
index 24f6b03549b..1443c5b56f3 100644
--- a/qa/qa/page/main/terms.rb
+++ b/qa/qa/page/main/terms.rb
@@ -5,17 +5,17 @@ module QA
module Main
class Terms < Page::Base
view 'app/views/layouts/terms.html.haml' do
- element :user_avatar_content, required: true
+ element 'user-avatar-content', required: true
end
view 'app/assets/javascripts/terms/components/app.vue' do
- element :terms_content, required: true
+ element 'terms-content', required: true
- element :accept_terms_button
+ element 'accept-terms-button'
end
def accept_terms
- click_element :accept_terms_button, Page::Main::Menu
+ click_element 'accept-terms-button', Page::Main::Menu
end
end
end
diff --git a/qa/qa/page/main/two_factor_auth.rb b/qa/qa/page/main/two_factor_auth.rb
index 003bd8dd1b1..186027900ca 100644
--- a/qa/qa/page/main/two_factor_auth.rb
+++ b/qa/qa/page/main/two_factor_auth.rb
@@ -5,16 +5,16 @@ module QA
module Main
class TwoFactorAuth < Page::Base
view 'app/views/devise/sessions/two_factor.html.haml' do
- element :verify_code_button
- element :two_fa_code_field
+ element 'verify-code-button'
+ element 'two-fa-code-field'
end
def click_verify_code_button
- click_element :verify_code_button
+ click_element 'verify-code-button'
end
def set_2fa_code(code)
- fill_element(:two_fa_code_field, code)
+ fill_element('two-fa-code-field', code)
end
end
end
diff --git a/qa/qa/page/profile/accounts/show.rb b/qa/qa/page/profile/accounts/show.rb
index 84a34d1da78..b29c1d9da12 100644
--- a/qa/qa/page/profile/accounts/show.rb
+++ b/qa/qa/page/profile/accounts/show.rb
@@ -6,24 +6,24 @@ module QA
module Accounts
class Show < Page::Base
view 'app/views/profiles/accounts/show.html.haml' do
- element :delete_account_button, required: true
- element :enable_2fa_button
+ element 'delete-account-button', required: true
+ element 'enable-2fa-button'
end
view 'app/assets/javascripts/profile/account/components/delete_account_modal.vue' do
- element :password_confirmation_field
- element :confirm_delete_account_button
+ element 'password-confirmation-field'
+ element 'confirm-delete-account-button'
end
def click_enable_2fa_button
- click_element(:enable_2fa_button)
+ click_element('enable-2fa-button')
end
def delete_account(password)
- click_element(:delete_account_button)
+ click_element('delete-account-button')
- find_element(:password_confirmation_field).set password
- click_element(:confirm_delete_account_button)
+ find_element('password-confirmation-field').set password
+ click_element('confirm-delete-account-button')
end
end
end
diff --git a/qa/qa/page/profile/ssh_keys.rb b/qa/qa/page/profile/ssh_keys.rb
index 2990ba6a4ac..c9ec056261a 100644
--- a/qa/qa/page/profile/ssh_keys.rb
+++ b/qa/qa/page/profile/ssh_keys.rb
@@ -11,7 +11,7 @@ module QA
end
view 'app/assets/javascripts/access_tokens/components/expires_at_field.vue' do
- element :expiry_date_field
+ element 'expiry-date-field'
end
view 'app/helpers/ssh_keys_helper.rb' do
@@ -31,7 +31,7 @@ module QA
# Expire in 2 days just in case the key is created just before midnight
fill_expiry_date(Date.today + 2)
# Close the datepicker
- find_element(:expiry_date_field).find('input').send_keys(:enter)
+ find_element('expiry-date-field').find('input').send_keys(:enter)
click_element(:add_key_button)
end
@@ -44,7 +44,7 @@ module QA
raise "Expiry date must be in YYYY-MM-DD format"
end
- fill_element(:expiry_date_field, date)
+ fill_element('expiry-date-field', date)
end
def remove_key(title)
diff --git a/qa/qa/page/profile/two_factor_auth.rb b/qa/qa/page/profile/two_factor_auth.rb
index 2add02b5c48..980d4a74a8c 100644
--- a/qa/qa/page/profile/two_factor_auth.rb
+++ b/qa/qa/page/profile/two_factor_auth.rb
@@ -5,61 +5,61 @@ module QA
module Profile
class TwoFactorAuth < Page::Base
view 'app/assets/javascripts/pages/profiles/two_factor_auths/index.js' do
- element :configure_it_later_button
+ element 'configure-it-later-button'
end
view 'app/views/profiles/two_factor_auths/show.html.haml' do
- element :otp_secret_content
- element :pin_code_field
- element :current_password_field
- element :register_2fa_app_button
+ element 'otp-secret-content'
+ element 'pin-code-field'
+ element 'current-password-field'
+ element 'register-2fa-app-button'
end
view 'app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue' do
- element :proceed_button
- element :copy_button
- element :codes_content
- element :code_content
+ element 'proceed-button'
+ element 'copy-button'
+ element 'recovery-codes'
+ element 'code-content'
end
def click_configure_it_later_button
# TO DO: Investigate why button does not appear sometimes:
# https://gitlab.com/gitlab-org/gitlab/-/issues/382698
page.refresh
- return unless has_element?(:configure_it_later_button, wait: 60)
+ return unless has_element?('configure-it-later-button', wait: 60)
- click_element :configure_it_later_button
+ click_element 'configure-it-later-button'
wait_until(max_duration: 10, message: "Waiting for create a group page") do
has_text?("Welcome to GitLab") && has_text?("Create a group")
end
end
def otp_secret_content
- find_element(:otp_secret_content).text.gsub('Key:', '').delete(' ')
+ find_element('otp-secret-content').text.gsub('Key:', '').delete(' ')
end
def set_pin_code(pin_code)
- fill_element(:pin_code_field, pin_code)
+ fill_element('pin-code-field', pin_code)
end
def set_current_password(password)
- fill_element(:current_password_field, password)
+ fill_element('current-password-field', password)
end
def click_register_2fa_app_button
- click_element :register_2fa_app_button
+ click_element 'register-2fa-app-button'
end
def recovery_codes
- code_elements = within_element(:codes_content) do
- all_elements(:code_content, minimum: 1)
+ code_elements = within_element('recovery-codes') do
+ all_elements('code-content', minimum: 1)
end
code_elements.map { |code_content| code_content.text }
end
def click_copy_and_proceed
- click_element :copy_button
- click_element :proceed_button
+ click_element 'copy-button'
+ click_element 'proceed-button'
end
end
end
diff --git a/qa/qa/page/project/settings/deploy_tokens.rb b/qa/qa/page/project/settings/deploy_tokens.rb
index cf25f4a0568..a1ba270a42f 100644
--- a/qa/qa/page/project/settings/deploy_tokens.rb
+++ b/qa/qa/page/project/settings/deploy_tokens.rb
@@ -6,74 +6,74 @@ module QA
module Settings
class DeployTokens < Page::Base
view 'app/views/shared/deploy_tokens/_form.html.haml' do
- element :deploy_token_name_field
- element :deploy_token_expires_at_field
- element :deploy_token_read_repository_checkbox
- element :deploy_token_read_package_registry_checkbox
- element :deploy_token_write_package_registry_checkbox
- element :deploy_token_read_registry_checkbox
- element :deploy_token_write_registry_checkbox
- element :create_deploy_token_button
+ element 'deploy-token-name-field'
+ element 'deploy-token-expires-at-field'
+ element 'deploy-token-read-repository-checkbox'
+ element 'deploy-token-read-package-registry-checkbox'
+ element 'deploy-token-write-package-registry-checkbox'
+ element 'deploy-token-read-registry-checkbox'
+ element 'deploy-token-write-registry-checkbox'
+ element 'create-deploy-token-button'
end
view 'app/views/shared/deploy_tokens/_new_deploy_token.html.haml' do
- element :created_deploy_token_container
- element :deploy_token_user_field
- element :deploy_token_field
+ element 'created-deploy-token-container'
+ element 'deploy-token-user-field'
+ element 'deploy-token-field'
end
def fill_token_name(name)
- fill_element(:deploy_token_name_field, name)
+ fill_element('deploy-token-name-field', name)
end
def fill_token_expires_at(expires_at)
- fill_element(:deploy_token_expires_at_field, expires_at.to_s + "\n")
+ fill_element('deploy-token-expires-at-field', expires_at.to_s + "\n")
end
def fill_scopes(scopes)
if scopes.include? :read_repository
- check_element(:deploy_token_read_repository_checkbox, true)
+ check_element('deploy-token-read-repository-checkbox', true)
end
if scopes.include? :read_package_registry
- check_element(:deploy_token_read_package_registry_checkbox, true)
+ check_element('deploy-token-read-package-registry-checkbox', true)
end
if scopes.include? :write_package_registry
- check_element(:deploy_token_write_package_registry_checkbox, true)
+ check_element('deploy-token-write-package-registry-checkbox', true)
end
if scopes.include? :read_registry
- check_element(:deploy_token_read_registry_checkbox, true)
+ check_element('deploy-token-read-registry-checkbox', true)
end
if scopes.include? :write_registry
- check_element(:deploy_token_write_registry_checkbox, true)
+ check_element('deploy-token-write-registry-checkbox', true)
end
end
def add_token
- click_element(:create_deploy_token_button)
+ click_element('create-deploy-token-button')
end
def token_username
within_new_project_deploy_token do
- find_element(:deploy_token_user_field).value
+ find_element('deploy-token-user-field').value
end
end
def token_password
within_new_project_deploy_token do
- find_element(:deploy_token_field).value
+ find_element('deploy-token-field').value
end
end
private
def within_new_project_deploy_token
- has_element?(:created_deploy_token_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
+ has_element?('created-deploy-token-container', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
- within_element(:created_deploy_token_container) do
+ within_element('created-deploy-token-container') do
yield
end
end
diff --git a/spec/features/alert_management/alert_details_spec.rb b/spec/features/alert_management/alert_details_spec.rb
index 66b7a9ca46c..7fa9bccbece 100644
--- a/spec/features/alert_management/alert_details_spec.rb
+++ b/spec/features/alert_management/alert_details_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Alert details', :js, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
- let_it_be(:developer) { create(:user, :no_super_sidebar) }
+ let_it_be(:developer) { create(:user) }
let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered', title: 'Alert') }
before_all do
diff --git a/spec/features/alert_management/alert_management_list_spec.rb b/spec/features/alert_management/alert_management_list_spec.rb
index cc54af249e1..058447b3be3 100644
--- a/spec/features/alert_management/alert_management_list_spec.rb
+++ b/spec/features/alert_management/alert_management_list_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Alert Management index', :js, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
- let_it_be(:developer) { create(:user, :no_super_sidebar) }
+ let_it_be(:developer) { create(:user) }
before_all do
project.add_developer(developer)
@@ -22,7 +22,7 @@ RSpec.describe 'Alert Management index', :js, feature_category: :incident_manage
expect(page).to have_content('Alerts')
expect(page).to have_content('Surface alerts in GitLab')
expect(page).not_to have_selector('.gl-table')
- page.within('.layout-page') do
+ page.within('.content-wrapper') do
expect(page).not_to have_css('[data-testid="search-icon"]')
end
end
@@ -31,7 +31,7 @@ RSpec.describe 'Alert Management index', :js, feature_category: :incident_manage
it 'renders correctly' do
expect(page).to have_content('Alerts')
expect(page).to have_selector('.gl-table')
- page.within('.layout-page') do
+ page.within('.content-wrapper') do
expect(page).to have_css('[data-testid="search-icon"]')
end
end
diff --git a/spec/features/projects/members/manage_groups_spec.rb b/spec/features/projects/members/manage_groups_spec.rb
index 63ff1ba8455..3a67879e33d 100644
--- a/spec/features/projects/members/manage_groups_spec.rb
+++ b/spec/features/projects/members/manage_groups_spec.rb
@@ -228,6 +228,6 @@ RSpec.describe 'Project > Members > Manage groups', :js, feature_category: :grou
end
def invite_group_selector
- 'button[data-test-id="invite-group-button"]'
+ 'button[data-testid="invite-a-group-button"]'
end
end
diff --git a/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap b/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap
index 2bd2b17a12d..7785693ff2a 100644
--- a/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap
+++ b/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap
@@ -11,7 +11,7 @@ exports[`~/access_tokens/components/expires_at_field should render datepicker wi
arialabel=""
autocomplete=""
container=""
- data-qa-selector="expiry_date_field"
+ data-testid="expiry-date-field"
defaultdate="Wed Aug 05 2020 00:00:00 GMT+0000 (Greenwich Mean Time)"
displayfield="true"
firstday="0"
diff --git a/spec/frontend/access_tokens/components/access_token_table_app_spec.js b/spec/frontend/access_tokens/components/access_token_table_app_spec.js
index ae767f8b3f5..aa7aad8e93e 100644
--- a/spec/frontend/access_tokens/components/access_token_table_app_spec.js
+++ b/spec/frontend/access_tokens/components/access_token_table_app_spec.js
@@ -153,7 +153,7 @@ describe('~/access_tokens/components/access_token_table_app', () => {
let button = cells.at(6).findComponent(GlButton);
expect(button.attributes()).toMatchObject({
'aria-label': __('Revoke'),
- 'data-qa-selector': __('revoke_button'),
+ 'data-testid': 'revoke-button',
href: '/-/profile/personal_access_tokens/1/revoke',
'data-confirm': sprintf(
__(
diff --git a/spec/frontend/access_tokens/components/new_access_token_app_spec.js b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
index d51ac638f0e..966a69fa60a 100644
--- a/spec/frontend/access_tokens/components/new_access_token_app_spec.js
+++ b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
@@ -81,20 +81,6 @@ describe('~/access_tokens/components/new_access_token_app', () => {
);
});
- it('input field should contain QA-related selectors', async () => {
- const newToken = '12345';
- await triggerSuccess(newToken);
-
- expect(findGlAlertError().exists()).toBe(false);
-
- const inputAttributes = wrapper
- .findByLabelText(sprintf(__('Your new %{accessTokenType}'), { accessTokenType }))
- .attributes();
- expect(inputAttributes).toMatchObject({
- 'data-qa-selector': 'created_access_token_field',
- });
- });
-
it('should render an info alert', async () => {
await triggerSuccess();
diff --git a/spec/frontend/invite_members/components/invite_members_trigger_spec.js b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
index 58c40a49b3c..f14d24538d8 100644
--- a/spec/frontend/invite_members/components/invite_members_trigger_spec.js
+++ b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
@@ -4,7 +4,6 @@ import InviteMembersTrigger from '~/invite_members/components/invite_members_tri
import eventHub from '~/invite_members/event_hub';
import {
TRIGGER_ELEMENT_BUTTON,
- TRIGGER_DEFAULT_QA_SELECTOR,
TRIGGER_ELEMENT_WITH_EMOJI,
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN,
@@ -66,18 +65,6 @@ describe.each(triggerItems)('with triggerElement as %s', (triggerItem) => {
expect(findButton().text()).toBe(displayText);
});
-
- it('uses the default qa selector value', () => {
- createComponent();
-
- expect(findButton().attributes('data-qa-selector')).toBe(TRIGGER_DEFAULT_QA_SELECTOR);
- });
-
- it('sets the qa selector value', () => {
- createComponent({ qaSelector: '_qaSelector_' });
-
- expect(findButton().attributes('data-qa-selector')).toBe('_qaSelector_');
- });
});
describe('clicking the link', () => {
diff --git a/spec/frontend/invite_members/components/invite_modal_base_spec.js b/spec/frontend/invite_members/components/invite_modal_base_spec.js
index e70c83a424e..45d2afb0eac 100644
--- a/spec/frontend/invite_members/components/invite_modal_base_spec.js
+++ b/spec/frontend/invite_members/components/invite_modal_base_spec.js
@@ -91,7 +91,6 @@ describe('InviteModalBase', () => {
const actionButton = findActionButton();
expect(actionButton.text()).toBe(INVITE_BUTTON_TEXT);
- expect(actionButton.attributes('data-qa-selector')).toBe('invite_button');
expect(actionButton.props()).toMatchObject({
variant: 'confirm',
diff --git a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
index 53218d794c7..b825a578cee 100644
--- a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
@@ -19,7 +19,7 @@ describe('Confirm Danger Modal', () => {
const findModal = () => wrapper.findComponent(GlModal);
const findConfirmationPhrase = () => wrapper.findByTestId('confirm-danger-phrase');
- const findConfirmationInput = () => wrapper.findByTestId('confirm-danger-input');
+ const findConfirmationInput = () => wrapper.findByTestId('confirm-danger-field');
const findDefaultWarning = () => wrapper.findByTestId('confirm-danger-warning');
const findAdditionalMessage = () => wrapper.findByTestId('confirm-danger-message');
const findPrimaryAction = () => findModal().props('actionPrimary');
diff --git a/spec/models/integrations/integration_list_spec.rb b/spec/models/integrations/integration_list_spec.rb
index b7ccbcecf6b..4bb7b100bc0 100644
--- a/spec/models/integrations/integration_list_spec.rb
+++ b/spec/models/integrations/integration_list_spec.rb
@@ -12,10 +12,10 @@ RSpec.describe Integrations::IntegrationList, feature_category: :integrations do
describe '#to_array' do
it 'returns array of Integration, columns, and values' do
- expect(subject.to_array).to eq([
+ expect(subject.to_array).to match_array([
Integration,
%w[active category project_id],
- [['true', 'common', projects.first.id], ['true', 'common', projects.second.id]]
+ contain_exactly(['true', 'common', projects.first.id], ['true', 'common', projects.second.id])
])
end
end
diff --git a/spec/services/admin/plan_limits/update_service_spec.rb b/spec/services/admin/plan_limits/update_service_spec.rb
index e57c234780c..eb9bbcf11aa 100644
--- a/spec/services/admin/plan_limits/update_service_spec.rb
+++ b/spec/services/admin/plan_limits/update_service_spec.rb
@@ -82,9 +82,9 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
response = update_plan_limits
expect(response[:status]).to eq :error
- expect(response[:message]).to eq ["Notification limit must be greater than or equal to " \
- "storage_size_limit (Dashboard limit): 5 " \
- "and less than or equal to enforcement_limit: 10"]
+ expect(response[:message]).to eq [
+ "Notification limit must be greater than or equal to the dashboard limit (5)"
+ ]
end
end
@@ -102,9 +102,9 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
response = update_plan_limits
expect(response[:status]).to eq :error
- expect(response[:message]).to eq ["Notification limit must be greater than or equal to " \
- "storage_size_limit (Dashboard limit): 5 " \
- "and less than or equal to enforcement_limit: 10"]
+ expect(response[:message]).to eq [
+ "Notification limit must be less than or equal to the enforcement limit (10)"
+ ]
end
end
@@ -113,8 +113,8 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
before do
limits.update!(
- storage_size_limit: 12,
- notification_limit: 12
+ storage_size_limit: 10,
+ notification_limit: 9
)
end
@@ -122,9 +122,9 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
response = update_plan_limits
expect(response[:status]).to eq :error
- expect(response[:message]).to eq ["Enforcement limit must be greater than " \
- "or equal to storage_size_limit (Dashboard limit): " \
- "12 and greater than or equal to notification_limit: 12"]
+ expect(response[:message]).to eq [
+ "Enforcement limit must be greater than or equal to the dashboard limit (10)"
+ ]
end
end
@@ -133,7 +133,7 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
before do
limits.update!(
- storage_size_limit: 10,
+ storage_size_limit: 9,
notification_limit: 10
)
end
@@ -142,9 +142,9 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
response = update_plan_limits
expect(response[:status]).to eq :error
- expect(response[:message]).to eq ["Enforcement limit must be greater than or equal to " \
- "storage_size_limit (Dashboard limit): " \
- "10 and greater than or equal to notification_limit: 10"]
+ expect(response[:message]).to eq [
+ "Enforcement limit must be greater than or equal to the notification limit (10)"
+ ]
end
end
@@ -162,8 +162,9 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
response = update_plan_limits
expect(response[:status]).to eq :error
- expect(response[:message]).to eq ["Storage size limit (Dashboard limit) must be less than or " \
- "equal to enforcement_limit: 12 and notification_limit: 10"]
+ expect(response[:message]).to eq [
+ "Dashboard limit must be less than or equal to the notification limit (10)"
+ ]
end
end
@@ -181,8 +182,45 @@ RSpec.describe Admin::PlanLimits::UpdateService, feature_category: :shared do
response = update_plan_limits
expect(response[:status]).to eq :error
- expect(response[:message]).to eq ["Storage size limit (Dashboard limit) must be less than or " \
- "equal to enforcement_limit: 10 and notification_limit: 11"]
+ expect(response[:message]).to eq [
+ "Dashboard limit must be less than or equal to the enforcement limit (10)"
+ ]
+ end
+
+ context 'when enforcement_limit is 0' do
+ before do
+ limits.update!(
+ enforcement_limit: 0
+ )
+ end
+
+ it 'does not return an error' do
+ response = update_plan_limits
+
+ expect(response[:status]).to eq :success
+ end
+ end
+ end
+ end
+
+ context 'when setting limit to unlimited' do
+ before do
+ limits.update!(
+ notification_limit: 10,
+ storage_size_limit: 10,
+ enforcement_limit: 10
+ )
+ end
+
+ [:notification_limit, :enforcement_limit, :storage_size_limit].each do |limit|
+ context "for #{limit}" do
+ let(:params) { { limit => 0 } }
+
+ it 'is successful' do
+ response = update_plan_limits
+
+ expect(response[:status]).to eq :success
+ end
end
end
end
diff --git a/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
index 0e7b909fce9..cf539174587 100644
--- a/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
+++ b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
@@ -45,9 +45,19 @@ RSpec.shared_examples 'unlicensed cycle analytics request params' do
end
end
+ context 'when the date range is exactly 180 days' do
+ before do
+ params[:created_before] = '2019-06-30'
+ end
+
+ it 'is valid' do
+ expect(subject).to be_valid
+ end
+ end
+
context 'when the date range exceeds 180 days' do
before do
- params[:created_before] = '2019-07-15'
+ params[:created_before] = '2019-07-01'
end
it 'is invalid' do
diff --git a/yarn.lock b/yarn.lock
index 7e4881aacf8..b4ecb9b9f6d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1274,10 +1274,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.69.0.tgz#bf76b8ffbe72a783807761a38abe8aaedcfe8c12"
integrity sha512-Zu8Fcjhi3Bk26jZOptcD5F4SHWC7/KuAe00NULViCeswKdoda1k19B+9oCSbsbxY7vMoFuD20kiCJdBCpxb3HA==
-"@gitlab/ui@67.3.0":
- version "67.3.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-67.3.0.tgz#e106c742591595c78282244dcf0632157c81e75f"
- integrity sha512-PSb/gpxRMRpZ99glO9u8hqWKA5vn+fKImS+0s1R3OuQOKIY36t4pYVtlZ/HD6eSQQzc92gx3GSpdfDdjPPmI7w==
+"@gitlab/ui@67.3.3":
+ version "67.3.3"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-67.3.3.tgz#11ce618a41288fd64ad0a5768dd517ac830fadc8"
+ integrity sha512-Gc+HYwB0MdEO0qDboNnDTROpItlWB1rFFqFqe7h/IuqJUHyr2NmUAvhrPINE6f56qa5GcMTDlFazmUUY4kcxCg==
dependencies:
"@floating-ui/dom" "1.2.9"
bootstrap-vue "2.23.1"