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-04 03:07:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-11-04 03:07:28 +0300
commit04b866f03b967470e20d5dd106fd493bebe40909 (patch)
treef118a6549de91f7f59b03ae180ded283349a24dc
parentcd353f0da2c1c9a6cdfe0a92f5f3236971ffaf9f (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.haml-lint_todo.yml43
-rw-r--r--app/assets/javascripts/environments/graphql/resolvers/flux.js95
-rw-r--r--app/assets/javascripts/pages/users/index.js4
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js3
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue44
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/utils.js2
-rw-r--r--app/assets/stylesheets/framework/layout.scss6
-rw-r--r--app/helpers/application_helper.rb1
-rw-r--r--app/helpers/nav_helper.rb4
-rw-r--r--app/services/ci/destroy_pipeline_service.rb2
-rw-r--r--app/views/admin/application_settings/_localization.html.haml2
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml4
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml2
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml2
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml2
-rw-r--r--app/views/projects/usage_quotas/index.html.haml2
-rw-r--r--app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml2
-rw-r--r--app/views/shared/_registration_features_discovery_message.html.haml2
-rw-r--r--app/views/shared/_service_ping_consent.html.haml2
-rw-r--r--app/views/shared/deploy_tokens/_form.html.haml2
-rw-r--r--app/views/shared/deploy_tokens/_table.html.haml2
-rw-r--r--app/views/shared/empty_states/_snippets.html.haml2
-rw-r--r--app/views/shared/web_hooks/_form.html.haml2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--config/feature_flags/development/super_sidebar_logged_out.yml8
-rw-r--r--doc/administration/audit_event_streaming/audit_event_types.md1
-rw-r--r--doc/ci/environments/kubernetes_dashboard.md2
-rw-r--r--jest.config.base.js9
-rw-r--r--jest.config.integration.js4
-rw-r--r--jest.config.js6
-rw-r--r--jest.config.scripts.js8
-rw-r--r--lib/sidebars/projects/menus/ci_cd_menu.rb2
-rw-r--r--lib/sidebars/projects/menus/scope_menu.rb2
-rw-r--r--locale/gitlab.pot2
-rw-r--r--package.json1
-rw-r--r--scripts/lib/glfm/update_example_snapshots.rb2
-rw-r--r--scripts/review_apps/base-config.yaml6
-rw-r--r--spec/features/calendar_spec.rb3
-rw-r--r--spec/features/contextual_sidebar_spec.rb32
-rw-r--r--spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb43
-rw-r--r--spec/features/dashboard/issuables_counter_spec.rb36
-rw-r--r--spec/features/dashboard/snippets_spec.rb2
-rw-r--r--spec/features/global_search_spec.rb17
-rw-r--r--spec/features/groups/merge_requests_spec.rb6
-rw-r--r--spec/features/monitor_sidebar_link_spec.rb102
-rw-r--r--spec/features/profiles/two_factor_auths_spec.rb2
-rw-r--r--spec/features/projects/files/user_find_file_spec.rb14
-rw-r--r--spec/features/projects/forks/fork_list_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb4
-rw-r--r--spec/features/projects/snippets/show_spec.rb59
-rw-r--r--spec/features/projects/work_items/work_item_spec.rb4
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb76
-rw-r--r--spec/features/snippets/show_spec.rb66
-rw-r--r--spec/frontend/environments/graphql/resolvers/flux_spec.js341
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js2
-rw-r--r--spec/helpers/application_helper_spec.rb8
-rw-r--r--spec/helpers/nav_helper_spec.rb22
-rw-r--r--spec/lib/sidebars/projects/menus/scope_menu_spec.rb2
-rw-r--r--spec/support/helpers/search_helpers.rb6
-rw-r--r--spec/support/rspec_order_todo.yml2
-rw-r--r--spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/snippets_shared_examples.rb26
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb6
-rw-r--r--spec/views/layouts/application.html.haml_spec.rb1
-rw-r--r--spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb1
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb2
66 files changed, 706 insertions, 472 deletions
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml
deleted file mode 100644
index c587e299c62..00000000000
--- a/.haml-lint_todo.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-# This configuration was generated by
-# `haml-lint --auto-gen-config`
-# on 2023-10-30 15:10:05 +0100 using Haml-Lint version 0.40.1.
-# The point is for the user to remove these configuration records
-# one by one as the lints are removed from the code base.
-# Note that changes in the inspected code, or installation of new
-# versions of Haml-Lint, may require this file to be generated again.
-
-linters:
-
- # Offense count: 37
- DocumentationLinks:
- exclude:
- - "app/views/admin/application_settings/_localization.html.haml"
- - "app/views/profiles/two_factor_auths/show.html.haml"
- - "app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml"
- - "app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml"
- - "app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml"
- - "app/views/projects/usage_quotas/index.html.haml"
- - "app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml"
- - "app/views/shared/_registration_features_discovery_message.html.haml"
- - "app/views/shared/_service_ping_consent.html.haml"
- - "app/views/shared/deploy_tokens/_form.html.haml"
- - "app/views/shared/deploy_tokens/_table.html.haml"
- - "app/views/shared/empty_states/_snippets.html.haml"
- - "app/views/shared/web_hooks/_form.html.haml"
- - "ee/app/views/admin/application_settings/_custom_templates_form.html.haml"
- - "ee/app/views/admin/application_settings/_elasticsearch_form.html.haml"
- - "ee/app/views/admin/application_settings/_microsoft_application.haml"
- - "ee/app/views/admin/application_settings/_templates.html.haml"
- - "ee/app/views/admin/push_rules/_merge_request_approvals.html.haml"
- - "ee/app/views/admin/push_rules/_merge_request_approvals_fields.html.haml"
- - "ee/app/views/compliance_management/compliance_framework/_project_settings.html.haml"
- - "ee/app/views/groups/_custom_project_templates_setting.html.haml"
- - "ee/app/views/groups/_templates_setting.html.haml"
- - "ee/app/views/profiles/preferences/_code_suggestions_settings_self_assignment.html.haml"
- - "ee/app/views/projects/settings/ci_cd/_auto_rollback.html.haml"
- - "ee/app/views/projects/settings/ci_cd/_pipeline_subscriptions.html.haml"
- - "ee/app/views/projects/settings/ci_cd/_protected_environments.html.haml"
- - "ee/app/views/projects/settings/merge_requests/_merge_request_approvals_settings.html.haml"
- - "ee/app/views/projects/settings/merge_requests/_target_branch_rules_settings.html.haml"
- - "ee/app/views/shared/_new_user_signups_cap_reached_alert.html.haml"
- - "ee/app/views/shared/promotions/_promote_mobile_devops.html.haml" \ No newline at end of file
diff --git a/app/assets/javascripts/environments/graphql/resolvers/flux.js b/app/assets/javascripts/environments/graphql/resolvers/flux.js
index d39b1bed7b6..627737276db 100644
--- a/app/assets/javascripts/environments/graphql/resolvers/flux.js
+++ b/app/assets/javascripts/environments/graphql/resolvers/flux.js
@@ -1,12 +1,18 @@
+import { Configuration, WatchApi, EVENT_DATA } from '@gitlab/cluster-client';
import axios from '~/lib/utils/axios_utils';
import {
HELM_RELEASES_RESOURCE_TYPE,
KUSTOMIZATIONS_RESOURCE_TYPE,
} from '~/environments/constants';
+import fluxKustomizationStatusQuery from '../queries/flux_kustomization_status.query.graphql';
+import fluxHelmReleaseStatusQuery from '../queries/flux_helm_release_status.query.graphql';
const helmReleasesApiVersion = 'helm.toolkit.fluxcd.io/v2beta1';
const kustomizationsApiVersion = 'kustomize.toolkit.fluxcd.io/v1beta1';
+const helmReleaseField = 'fluxHelmReleaseStatus';
+const kustomizationField = 'fluxKustomizationStatus';
+
const handleClusterError = (err) => {
const error = err?.response?.data?.message ? new Error(err.response.data.message) : err;
throw error;
@@ -22,14 +28,57 @@ const buildFluxResourceUrl = ({
return `${basePath}/apis/${apiVersion}/namespaces/${namespace}/${resourceType}/${environmentName}`;
};
-const getFluxResourceStatus = (configuration, url) => {
- const { headers } = configuration;
+const buildFluxResourceWatchPath = ({ namespace, apiVersion, resourceType }) => {
+ return `/apis/${apiVersion}/namespaces/${namespace}/${resourceType}`;
+};
+
+const watchFluxResource = ({ watchPath, resourceName, query, variables, field, client }) => {
+ const config = new Configuration(variables.configuration);
+ const watcherApi = new WatchApi(config);
+ const fieldSelector = `metadata.name=${decodeURIComponent(resourceName)}`;
+
+ watcherApi
+ .subscribeToStream(watchPath, { watch: true, fieldSelector })
+ .then((watcher) => {
+ let result = [];
+
+ watcher.on(EVENT_DATA, (data) => {
+ result = data[0]?.status?.conditions;
+
+ client.writeQuery({
+ query,
+ variables,
+ data: { [field]: result },
+ });
+ });
+ })
+ .catch((err) => {
+ handleClusterError(err);
+ });
+};
+
+const getFluxResourceStatus = ({ url, watchPath, query, variables, field, client }) => {
+ const { headers } = variables.configuration;
const withCredentials = true;
return axios
.get(url, { withCredentials, headers })
.then((res) => {
- return res?.data?.status?.conditions || [];
+ const fluxData = res?.data;
+ const resourceName = fluxData?.metadata?.name;
+
+ if (gon.features?.k8sWatchApi && resourceName) {
+ watchFluxResource({
+ watchPath,
+ resourceName,
+ query,
+ variables,
+ field,
+ client,
+ });
+ }
+
+ return fluxData?.status?.conditions || [];
})
.catch((err) => {
handleClusterError(err);
@@ -62,7 +111,16 @@ const getFluxResources = (configuration, url) => {
};
export default {
- fluxKustomizationStatus(_, { configuration, namespace, environmentName, fluxResourcePath = '' }) {
+ fluxKustomizationStatus(
+ _,
+ { configuration, namespace, environmentName, fluxResourcePath = '' },
+ { client },
+ ) {
+ const watchPath = buildFluxResourceWatchPath({
+ namespace,
+ apiVersion: kustomizationsApiVersion,
+ resourceType: KUSTOMIZATIONS_RESOURCE_TYPE,
+ });
let url;
if (fluxResourcePath) {
@@ -76,9 +134,25 @@ export default {
environmentName,
});
}
- return getFluxResourceStatus(configuration, url);
+ return getFluxResourceStatus({
+ url,
+ watchPath,
+ query: fluxKustomizationStatusQuery,
+ variables: { configuration, namespace, environmentName, fluxResourcePath },
+ field: kustomizationField,
+ client,
+ });
},
- fluxHelmReleaseStatus(_, { configuration, namespace, environmentName, fluxResourcePath }) {
+ fluxHelmReleaseStatus(
+ _,
+ { configuration, namespace, environmentName, fluxResourcePath },
+ { client },
+ ) {
+ const watchPath = buildFluxResourceWatchPath({
+ namespace,
+ apiVersion: helmReleasesApiVersion,
+ resourceType: HELM_RELEASES_RESOURCE_TYPE,
+ });
let url;
if (fluxResourcePath) {
@@ -92,7 +166,14 @@ export default {
environmentName,
});
}
- return getFluxResourceStatus(configuration, url);
+ return getFluxResourceStatus({
+ url,
+ watchPath,
+ query: fluxHelmReleaseStatusQuery,
+ variables: { configuration, namespace, environmentName, fluxResourcePath },
+ field: helmReleaseField,
+ client,
+ });
},
fluxKustomizations(_, { configuration, namespace }) {
const url = buildFluxResourceUrl({
diff --git a/app/assets/javascripts/pages/users/index.js b/app/assets/javascripts/pages/users/index.js
index 4215cfbf409..2e479da09e8 100644
--- a/app/assets/javascripts/pages/users/index.js
+++ b/app/assets/javascripts/pages/users/index.js
@@ -5,6 +5,10 @@ import { initProfileTabs } from '~/profile';
import UserTabs from './user_tabs';
function initUserProfile(action) {
+ // TODO: Remove both Vue and legacy JS tabs code/feature flag uses with the
+ // removal of the old navigation.
+ // See https://gitlab.com/groups/gitlab-org/-/epics/11875.
+
if (gon.features?.profileTabsVue) {
initProfileTabs();
} else {
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index d368c76b6cc..79eb3902116 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -1,3 +1,6 @@
+// TODO: Remove this with the removal of the old navigation.
+// See https://gitlab.com/groups/gitlab-org/-/epics/11875.
+
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
import Activities from '~/activities';
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
index fa309f89d89..dcefa66c403 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
@@ -51,7 +51,6 @@ export default {
lineHighlighter: new LineHighlighter(),
blameData: [],
renderedChunks: [],
- overlappingBlameRequested: false,
};
},
computed: {
@@ -72,6 +71,7 @@ export default {
showBlame: {
handler(shouldShow) {
toggleBlameClasses(this.blameData, shouldShow);
+ this.requestBlameInfo(this.renderedChunks[0]);
},
immediate: true,
},
@@ -92,32 +92,36 @@ export default {
this.selectLine();
},
methods: {
- async handleChunkAppear(chunkIndex) {
- const chunk = this.chunks[chunkIndex];
-
+ async handleChunkAppear(chunkIndex, handleOverlappingChunk = true) {
if (!this.renderedChunks.includes(chunkIndex)) {
this.renderedChunks.push(chunkIndex);
+ await this.requestBlameInfo(chunkIndex);
- const { data } = await this.$apollo.query({
- query: blameDataQuery,
- variables: {
- fullPath: this.projectPath,
- filePath: this.blob.path,
- fromLine: chunk.startingFrom + 1,
- toLine: chunk.startingFrom + chunk.totalLines,
- },
- });
-
- const blob = data?.project?.repository?.blobs?.nodes[0];
- const blameGroups = blob?.blame?.groups;
- if (blameGroups) this.blameData.push(...blameGroups);
- if (chunkIndex > 0 && !this.overlappingBlameRequested) {
+ if (chunkIndex > 0 && handleOverlappingChunk) {
// request the blame information for overlapping chunk incase it is visible in the DOM
- this.handleChunkAppear(chunkIndex - 1);
- this.overlappingBlameRequested = true;
+ this.handleChunkAppear(chunkIndex - 1, false);
}
}
},
+ async requestBlameInfo(chunkIndex) {
+ const chunk = this.chunks[chunkIndex];
+ if (!this.showBlame || !chunk) return;
+
+ const { data } = await this.$apollo.query({
+ query: blameDataQuery,
+ variables: {
+ fullPath: this.projectPath,
+ filePath: this.blob.path,
+ fromLine: chunk.startingFrom + 1,
+ toLine: chunk.startingFrom + chunk.totalLines,
+ },
+ });
+
+ const blob = data?.project?.repository?.blobs?.nodes[0];
+ const blameGroups = blob?.blame?.groups;
+ const isDuplicate = this.blameData.includes(blameGroups[0]);
+ if (blameGroups && !isDuplicate) this.blameData.push(...blameGroups);
+ },
async selectLine() {
await this.$nextTick();
this.lineHighlighter.highlightHash(this.$route.hash);
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/utils.js b/app/assets/javascripts/vue_shared/components/source_viewer/utils.js
index 71a6db1a72a..596829b51a4 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/utils.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/utils.js
@@ -10,7 +10,7 @@ const findLineContentElement = (lineNumber) => document.getElementById(`LC${line
export const calculateBlameOffset = (lineNumber) => {
if (lineNumber === 1) return '0px';
const blobViewerOffset = document.querySelector(VIEWER_SELECTOR)?.getBoundingClientRect().top;
- const lineContentOffset = findLineContentElement(lineNumber).getBoundingClientRect().top;
+ const lineContentOffset = findLineContentElement(lineNumber)?.getBoundingClientRect().top;
return `${lineContentOffset - blobViewerOffset}px`;
};
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 171f070d776..33c8a0254fd 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -4,12 +4,6 @@ html {
&.touch .tooltip {
display: none !important;
}
-
- @include media-breakpoint-up(sm) {
- &.logged-out-marketing-header {
- --header-height: 72px;
- }
- }
}
body {
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 541a71d3302..732f5a177a9 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -318,7 +318,6 @@ module ApplicationHelper
class_names << 'with-header' if !show_super_sidebar? || !current_user
class_names << 'with-top-bar' if show_super_sidebar? && !@hide_top_bar_padding
class_names << system_message_class
- class_names << 'logged-out-marketing-header' if !current_user && ::Gitlab.com? && !show_super_sidebar?
class_names
end
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 21c81eefce2..f1e05b43cd3 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -80,9 +80,7 @@ module NavHelper
def show_super_sidebar?(user = current_user)
# The new sidebar is not enabled for anonymous use
- # Once we enable the new sidebar by default, this
- # should return true
- return Feature.enabled?(:super_sidebar_logged_out) unless user
+ return true unless user
# Users who get the new nav unless they explicitly
# opt-out via the toggle
diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb
index a9d2e17657e..7adf573687a 100644
--- a/app/services/ci/destroy_pipeline_service.rb
+++ b/app/services/ci/destroy_pipeline_service.rb
@@ -28,3 +28,5 @@ module Ci
end
end
end
+
+Ci::DestroyPipelineService.prepend_mod
diff --git a/app/views/admin/application_settings/_localization.html.haml b/app/views/admin/application_settings/_localization.html.haml
index e1eb0ba84eb..62849a81633 100644
--- a/app/views/admin/application_settings/_localization.html.haml
+++ b/app/views/admin/application_settings/_localization.html.haml
@@ -11,7 +11,7 @@
.form-group
= f.label :time_tracking, _('Time tracking'), class: 'label-bold'
- - time_tracking_help_link = help_page_path('user/project/time_tracking.md')
+ - time_tracking_help_link = help_page_path('user/project/time_tracking')
- time_tracking_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: time_tracking_help_link }
= f.gitlab_ui_checkbox_component :time_tracking_limit_to_hours, _('Limit display of time tracking units to hours.'), help_text: _('Display time tracking in issues in total hours only. %{link_start}What is time tracking?%{link_end}').html_safe % { link_start: time_tracking_help_link_start, link_end: '</a>'.html_safe }
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index ff0b31da022..7c42053a376 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -41,7 +41,7 @@
alert_options: { class: 'gl-mb-3' },
dismissible: false) do |c|
- c.with_body do
- = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
- if current_password_required?
.form-group
@@ -130,7 +130,7 @@
alert_options: { class: 'gl-mb-3' },
dismissible: false) do |c|
- c.with_body do
- = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
.js-manage-two-factor-form{ data: { current_password_required: current_password_required?.to_s, profile_two_factor_auth_path: profile_two_factor_auth_path, profile_two_factor_auth_method: 'delete', codes_profile_two_factor_auth_path: codes_profile_two_factor_auth_path, codes_profile_two_factor_auth_method: 'post' } }
- else
%p
diff --git a/app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml b/app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml
index da1965f549c..0a6f940e41a 100644
--- a/app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml
@@ -9,5 +9,5 @@
%p.form-text.text-muted
= s_('ProjectSettings|Leave empty to use default template.')
= sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_COMMIT_TEMPLATE_LENGTH })
- - link = link_to('', help_page_path('user/project/merge_requests/commit_templates.md'), target: '_blank', rel: 'noopener noreferrer')
+ - link = link_to('', help_page_path('user/project/merge_requests/commit_templates'), target: '_blank', rel: 'noopener noreferrer')
= safe_format(s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}'), tag_pair(link, :link_start, :link_end))
diff --git a/app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml
index 501288f727b..5aa7449c72f 100644
--- a/app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml
@@ -9,5 +9,5 @@
%p.form-text.text-muted
= s_('ProjectSettings|Leave empty to use default template.')
= sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_SUGGESTIONS_TEMPLATE_LENGTH })
- - link = link_to('', help_page_path('user/project/merge_requests/reviews/suggestions.md', anchor: 'configure-the-commit-message-for-applied-suggestions'), target: '_blank', rel: 'noopener noreferrer')
+ - link = link_to('', help_page_path('user/project/merge_requests/reviews/suggestions', anchor: 'configure-the-commit-message-for-applied-suggestions'), target: '_blank', rel: 'noopener noreferrer')
= safe_format(s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}'), tag_pair(link, :link_start, :link_end))
diff --git a/app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml b/app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml
index bc6530b927c..26b038f1bf7 100644
--- a/app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml
@@ -9,5 +9,5 @@
%p.form-text.text-muted
= s_('ProjectSettings|Leave empty to use default template.')
= sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_COMMIT_TEMPLATE_LENGTH })
- - link = link_to('', help_page_path('user/project/merge_requests/commit_templates.md'), target: '_blank', rel: 'noopener noreferrer')
+ - link = link_to('', help_page_path('user/project/merge_requests/commit_templates'), target: '_blank', rel: 'noopener noreferrer')
= safe_format(s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}'), tag_pair(link, :link_start, :link_end))
diff --git a/app/views/projects/usage_quotas/index.html.haml b/app/views/projects/usage_quotas/index.html.haml
index 6f2a2aacf66..039df9738ff 100644
--- a/app/views/projects/usage_quotas/index.html.haml
+++ b/app/views/projects/usage_quotas/index.html.haml
@@ -14,7 +14,7 @@
.col-sm-12
%p.gl-text-secondary
= s_('UsageQuota|Usage of project resources across the %{strong_start}%{project_name}%{strong_end} project').html_safe % { strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe, project_name: @project.name } + '.'
- %a{ href: help_page_path('user/usage_quotas.md'), target: '_blank', rel: 'noopener noreferrer' }
+ %a{ href: help_page_path('user/usage_quotas'), target: '_blank', rel: 'noopener noreferrer' }
= s_('UsageQuota|Learn more about usage quotas') + '.'
= gl_tabs_nav({ id: 'js-project-usage-quotas-tabs' }) do
diff --git a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
index 79a9bafc4f0..0ff2ee935cc 100644
--- a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
+++ b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
@@ -9,4 +9,4 @@
= _('Container registry is not enabled on this GitLab instance. Ask an administrator to enable it in order for Auto DevOps to work.')
- c.with_actions do
= link_button_to _('Settings'), project_settings_ci_cd_path(project), class: 'alert-link', variant: :confirm
- = link_button_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank', class: 'alert-link gl-ml-3'
+ = link_button_to _('More information'), help_page_path('topics/autodevops/index'), target: '_blank', class: 'alert-link gl-ml-3'
diff --git a/app/views/shared/_registration_features_discovery_message.html.haml b/app/views/shared/_registration_features_discovery_message.html.haml
index 6e386866dfb..5fa554171aa 100644
--- a/app/views/shared/_registration_features_discovery_message.html.haml
+++ b/app/views/shared/_registration_features_discovery_message.html.haml
@@ -1,5 +1,5 @@
- feature_title = local_assigns.fetch(:feature_title, s_('RegistrationFeatures|use this feature'))
-- registration_features_docs_path = help_page_path('administration/settings/usage_statistics.md', anchor: 'registration-features-program')
+- registration_features_docs_path = help_page_path('administration/settings/usage_statistics', anchor: 'registration-features-program')
- registration_features_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: registration_features_docs_path }
%div
diff --git a/app/views/shared/_service_ping_consent.html.haml b/app/views/shared/_service_ping_consent.html.haml
index a5e63896367..b65808bfcd2 100644
--- a/app/views/shared/_service_ping_consent.html.haml
+++ b/app/views/shared/_service_ping_consent.html.haml
@@ -1,7 +1,7 @@
- if session[:ask_for_usage_stats_consent]
= render Pajamas::AlertComponent.new(alert_options: { class: 'service-ping-consent-message' }) do |c|
- c.with_body do
- - docs_link = link_to '', help_page_path('administration/settings/usage_statistics.md'), class: 'gl-link'
+ - docs_link = link_to '', help_page_path('administration/settings/usage_statistics'), class: 'gl-link'
- settings_link = link_to '', metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), class: 'gl-link'
= safe_format s_('ServicePing|To help improve GitLab, we would like to periodically %{link_start}collect usage information%{link_end}.'), tag_pair(docs_link, :link_start, :link_end)
= safe_format s_('ServicePing|This can be changed at any time in %{link_start}your settings%{link_end}.'), tag_pair(settings_link, :link_start, :link_end)
diff --git a/app/views/shared/deploy_tokens/_form.html.haml b/app/views/shared/deploy_tokens/_form.html.haml
index bb7e0d774cc..b172e3bf94f 100644
--- a/app/views/shared/deploy_tokens/_form.html.haml
+++ b/app/views/shared/deploy_tokens/_form.html.haml
@@ -1,5 +1,5 @@
%p
- - link = link_to('', help_page_path('user/project/deploy_tokens/index.md'), target: '_blank', rel: 'noopener noreferrer')
+ - link = link_to('', help_page_path('user/project/deploy_tokens/index'), target: '_blank', rel: 'noopener noreferrer')
= safe_format(s_('DeployTokens|Create a new deploy token for all projects in this group. %{link_start}What are deploy tokens?%{link_end}'), tag_pair(link, :link_start, :link_end))
= gitlab_ui_form_for token, url: create_deploy_token_path(group_or_project, anchor: 'js-deploy-tokens'), method: :post, remote: true do |f|
diff --git a/app/views/shared/deploy_tokens/_table.html.haml b/app/views/shared/deploy_tokens/_table.html.haml
index 3b351387d41..0b8a97a34f2 100644
--- a/app/views/shared/deploy_tokens/_table.html.haml
+++ b/app/views/shared/deploy_tokens/_table.html.haml
@@ -16,7 +16,7 @@
packages_registry_enabled: packages_registry_enabled?(group_or_project),
create_new_token_path: create_deploy_token_path(group_or_project),
token_type: group_or_project.is_a?(Group) ? 'group' : 'project',
- deploy_tokens_help_url: help_page_path('user/project/deploy_tokens/index.md')
+ deploy_tokens_help_url: help_page_path('user/project/deploy_tokens/index')
}
}
- if active_tokens.present?
diff --git a/app/views/shared/empty_states/_snippets.html.haml b/app/views/shared/empty_states/_snippets.html.haml
index a2457fb0810..800cfe8b0d1 100644
--- a/app/views/shared/empty_states/_snippets.html.haml
+++ b/app/views/shared/empty_states/_snippets.html.haml
@@ -13,6 +13,6 @@
.gl-mt-3<
- if button_path
= link_button_to s_('SnippetsEmptyState|New snippet'), button_path, title: s_('SnippetsEmptyState|New snippet'), id: 'new_snippet_link', data: { testid: 'create-first-snippet-link' }, variant: :confirm
- = link_button_to s_('SnippetsEmptyState|Documentation'), help_page_path('user/snippets.md'), title: s_('SnippetsEmptyState|Documentation')
+ = link_button_to s_('SnippetsEmptyState|Documentation'), help_page_path('user/snippets'), title: s_('SnippetsEmptyState|Documentation')
- else
%h4.gl-text-center= s_('SnippetsEmptyState|There are no snippets to show.')
diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml
index 7c713e63cd7..a3dfc6eb042 100644
--- a/app/views/shared/web_hooks/_form.html.haml
+++ b/app/views/shared/web_hooks/_form.html.haml
@@ -66,7 +66,7 @@
help_text: s_('Webhooks|A release is created, updated, or deleted.')
- if Feature.enabled?(:emoji_webhooks, hook.parent)
%li.gl-pb-5
- - emoji_help_link = link_to s_('Which emoji events trigger webhooks'), help_page_path('user/project/integrations/webhook_events.md', anchor: 'emoji-events')
+ - emoji_help_link = link_to s_('Which emoji events trigger webhooks'), help_page_path('user/project/integrations/webhook_events', anchor: 'emoji-events')
= form.gitlab_ui_checkbox_component :emoji_events,
integration_webhook_event_human_name(:emoji_events),
help_text: s_('Webhooks|An emoji is awarded or revoked. %{help_link}?').html_safe % { help_link: emoji_help_link }
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index c4a55a7d7ed..e23555428aa 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -114,6 +114,8 @@
%p.profile-user-bio.gl-mb-3
= @user.bio
+ -# TODO: Remove this with the removal of the old navigation.
+ -# See https://gitlab.com/groups/gitlab-org/-/epics/11875.
- if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user)
.scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] }
%button.fade-left{ type: 'button', title: _('Scroll left'), 'aria-label': _('Scroll left') }
diff --git a/config/feature_flags/development/super_sidebar_logged_out.yml b/config/feature_flags/development/super_sidebar_logged_out.yml
deleted file mode 100644
index 8deeb63b537..00000000000
--- a/config/feature_flags/development/super_sidebar_logged_out.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: super_sidebar_logged_out
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127756
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419936
-milestone: '16.3'
-type: development
-group: group::foundations
-default_enabled: false
diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md
index 6e1436284d0..ac630c18717 100644
--- a/doc/administration/audit_event_streaming/audit_event_types.md
+++ b/doc/administration/audit_event_streaming/audit_event_types.md
@@ -172,6 +172,7 @@ Audit event types belong to the following product categories.
| [`ci_variable_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91983) | Triggered when a CI variable is created at a project level| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [15.2](https://gitlab.com/gitlab-org/gitlab/-/issues/363090) |
| [`ci_variable_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91983) | Triggered when a project's CI variable is deleted| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [15.2](https://gitlab.com/gitlab-org/gitlab/-/issues/363090) |
| [`ci_variable_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91983) | Triggered when a project's CI variable is updated| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [15.2](https://gitlab.com/gitlab-org/gitlab/-/issues/363090) |
+| [`destroy_pipeline`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135255) | Event triggered when a pipeline is deleted| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.6](https://gitlab.com/gitlab-org/gitlab/-/issues/339041) |
### Deployment management
diff --git a/doc/ci/environments/kubernetes_dashboard.md b/doc/ci/environments/kubernetes_dashboard.md
index fe2e44f92f2..4062fbee25e 100644
--- a/doc/ci/environments/kubernetes_dashboard.md
+++ b/doc/ci/environments/kubernetes_dashboard.md
@@ -64,7 +64,7 @@ On GitLab.com, this feature is not available.
View a dashboard to see the status of any connected clusters.
If the `k8s_watch_api` feature flag is enabled, the status of your
-pods updates in real time.
+pods and Flux reconciliation updates in real time.
To view a configured dashboard:
diff --git a/jest.config.base.js b/jest.config.base.js
index 9183b83487a..18c13293275 100644
--- a/jest.config.base.js
+++ b/jest.config.base.js
@@ -17,6 +17,9 @@ module.exports = (path, options = {}) => {
moduleNameMapper: extModuleNameMapper = {},
moduleNameMapperEE: extModuleNameMapperEE = {},
moduleNameMapperJH: extModuleNameMapperJH = {},
+ roots: extRoots = [],
+ rootsEE: extRootsEE = [],
+ rootsJH: extRootsJH = [],
} = options;
const reporters = ['default'];
@@ -266,5 +269,11 @@ module.exports = (path, options = {}) => {
'<rootDir>/spec/frontend/__helpers__/html_string_serializer.js',
'<rootDir>/spec/frontend/__helpers__/clean_html_element_serializer.js',
],
+ roots: [
+ '<rootDir>/app/assets/javascripts/',
+ ...extRoots,
+ ...(IS_EE ? ['<rootDir>/ee/app/assets/javascripts/', ...extRootsEE] : []),
+ ...(IS_JH ? ['<rootDir>/jh/app/assets/javascripts/', ...extRootsJH] : []),
+ ],
};
};
diff --git a/jest.config.integration.js b/jest.config.integration.js
index 0693a500990..919c299000b 100644
--- a/jest.config.integration.js
+++ b/jest.config.integration.js
@@ -23,6 +23,10 @@ module.exports = {
moduleNameMapperJH: {
'^jh_else_ce_test_helpers(/.*)$': '<rootDir>/jh/spec/frontend_integration/test_helpers$1',
},
+ // We need to include spec/frontend in `roots` for the __mocks__ to be found
+ roots: ['<rootDir>/spec/frontend_integration/', '<rootDir>/spec/frontend/'],
+ rootsEE: ['<rootDir>/ee/spec/frontend_integration/'],
+ rootsJH: ['<rootDir>/jh/spec/frontend_integration/'],
}),
fakeTimers: {
enableGlobally: false,
diff --git a/jest.config.js b/jest.config.js
index 96a62b18d8f..3f3e1abbf0c 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -9,6 +9,10 @@ if (IS_JH && fs.existsSync('./jh/jest.config.js')) {
module.exports = require('./jh/jest.config');
} else {
module.exports = {
- ...baseConfig('spec/frontend'),
+ ...baseConfig('spec/frontend', {
+ roots: ['<rootDir>/spec/frontend'],
+ rootsEE: ['<rootDir>/ee/spec/frontend'],
+ rootsJH: ['<rootDir>/jh/spec/frontend'],
+ }),
};
}
diff --git a/jest.config.scripts.js b/jest.config.scripts.js
new file mode 100644
index 00000000000..dd824bd01bf
--- /dev/null
+++ b/jest.config.scripts.js
@@ -0,0 +1,8 @@
+const baseConfig = require('./jest.config.base');
+
+module.exports = {
+ ...baseConfig('spec/frontend', {
+ roots: ['<rootDir>/scripts/lib', '<rootDir>/spec/frontend'],
+ }),
+ testMatch: [],
+};
diff --git a/lib/sidebars/projects/menus/ci_cd_menu.rb b/lib/sidebars/projects/menus/ci_cd_menu.rb
index 02596b16cfa..c77e8e996b0 100644
--- a/lib/sidebars/projects/menus/ci_cd_menu.rb
+++ b/lib/sidebars/projects/menus/ci_cd_menu.rb
@@ -18,7 +18,7 @@ module Sidebars
override :extra_container_html_options
def extra_container_html_options
{
- class: 'shortcuts-pipelines rspec-link-pipelines'
+ class: 'shortcuts-pipelines'
}
end
diff --git a/lib/sidebars/projects/menus/scope_menu.rb b/lib/sidebars/projects/menus/scope_menu.rb
index f388c814bd7..d03abfdfb7e 100644
--- a/lib/sidebars/projects/menus/scope_menu.rb
+++ b/lib/sidebars/projects/menus/scope_menu.rb
@@ -22,7 +22,7 @@ module Sidebars
override :extra_container_html_options
def extra_container_html_options
{
- class: 'shortcuts-project rspec-project-link'
+ class: 'shortcuts-project'
}
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 58d123638b1..6edb19a1df3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -50388,7 +50388,7 @@ msgstr ""
msgid "Tracing|Time range"
msgstr ""
-msgid "Tracing|Toggle children spans"
+msgid "Tracing|Toggle child spans"
msgstr ""
msgid "Tracing|Trace ID"
diff --git a/package.json b/package.json
index 192aa370cee..c5900e31e33 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"jest:ci:predictive": "jest --config jest.config.js --ci --coverage --findRelatedTests $(cat $RSPEC_CHANGED_FILES_PATH) $(cat $RSPEC_MATCHING_JS_FILES_PATH) --passWithNoTests --testSequencer ./scripts/frontend/parallel_ci_sequencer.js",
"jest:contract": "PACT_DO_NOT_TRACK=true jest --config jest.config.contract.js --runInBand",
"jest:integration": "jest --config jest.config.integration.js",
+ "jest:scripts": "jest --config jest.config.scripts.js",
"jest:quarantine": "grep -r 'quarantine:' spec/frontend ee/spec/frontend",
"lint:eslint": "node scripts/frontend/eslint.js",
"lint:eslint:fix": "node scripts/frontend/eslint.js --fix",
diff --git a/scripts/lib/glfm/update_example_snapshots.rb b/scripts/lib/glfm/update_example_snapshots.rb
index 793f7521283..01760c23a68 100644
--- a/scripts/lib/glfm/update_example_snapshots.rb
+++ b/scripts/lib/glfm/update_example_snapshots.rb
@@ -289,7 +289,7 @@ module Glfm
wysiwyg_html_and_json_tempfile_path = Dir::Tmpname.create(WYSIWYG_HTML_AND_JSON_TEMPFILE_BASENAME) {}
ENV['OUTPUT_WYSIWYG_HTML_AND_JSON_TEMPFILE_PATH'] = wysiwyg_html_and_json_tempfile_path
- cmd = "yarn jest --testMatch '**/render_wysiwyg_html_and_json.js' #{__dir__}/render_wysiwyg_html_and_json.js"
+ cmd = "yarn jest:scripts #{__dir__}/render_wysiwyg_html_and_json.js"
run_external_cmd(cmd)
output("Reading generated WYSIWYG HTML and prosemirror JSON from tempfile " \
diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml
index a425aecc86b..721733f6f68 100644
--- a/scripts/review_apps/base-config.yaml
+++ b/scripts/review_apps/base-config.yaml
@@ -56,10 +56,10 @@ gitlab:
# Based on https://console.cloud.google.com/monitoring/metrics-explorer;duration=P14D?pageState=%7B%22xyChart%22:%7B%22constantLines%22:%5B%5D,%22dataSets%22:%5B%7B%22plotType%22:%22LINE%22,%22targetAxis%22:%22Y1%22,%22timeSeriesFilter%22:%7B%22aggregations%22:%5B%7B%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22groupByFields%22:%5B%5D,%22perSeriesAligner%22:%22ALIGN_RATE%22%7D,%7B%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22groupByFields%22:%5B%5D,%22perSeriesAligner%22:%22ALIGN_MEAN%22%7D%5D,%22apiSource%22:%22DEFAULT_CLOUD%22,%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22filter%22:%22metric.type%3D%5C%22kubernetes.io%2Fcontainer%2Fcpu%2Fcore_usage_time%5C%22%20resource.type%3D%5C%22k8s_container%5C%22%20resource.label.%5C%22container_name%5C%22%3D%5C%22gitlab-shell%5C%22%22,%22groupByFields%22:%5B%5D,%22minAlignmentPeriod%22:%2260s%22,%22perSeriesAligner%22:%22ALIGN_RATE%22,%22secondaryCrossSeriesReducer%22:%22REDUCE_NONE%22,%22secondaryGroupByFields%22:%5B%5D%7D%7D%5D,%22options%22:%7B%22mode%22:%22STATS%22%7D,%22y1Axis%22:%7B%22label%22:%22%22,%22scale%22:%22LINEAR%22%7D%7D%7D&project=gitlab-review-apps
cpu: 12m
# Based on https://console.cloud.google.com/monitoring/metrics-explorer;duration=P14D?pageState=%7B%22xyChart%22:%7B%22constantLines%22:%5B%5D,%22dataSets%22:%5B%7B%22plotType%22:%22LINE%22,%22targetAxis%22:%22Y1%22,%22timeSeriesFilter%22:%7B%22aggregations%22:%5B%7B%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22groupByFields%22:%5B%5D,%22perSeriesAligner%22:%22ALIGN_MEAN%22%7D%5D,%22apiSource%22:%22DEFAULT_CLOUD%22,%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22filter%22:%22metric.type%3D%5C%22kubernetes.io%2Fcontainer%2Fmemory%2Fused_bytes%5C%22%20resource.type%3D%5C%22k8s_container%5C%22%20resource.label.%5C%22container_name%5C%22%3D%5C%22gitlab-shell%5C%22%22,%22groupByFields%22:%5B%5D,%22minAlignmentPeriod%22:%2260s%22,%22perSeriesAligner%22:%22ALIGN_MEAN%22%7D%7D%5D,%22options%22:%7B%22mode%22:%22STATS%22%7D,%22y1Axis%22:%7B%22label%22:%22%22,%22scale%22:%22LINEAR%22%7D%7D%7D&project=gitlab-review-apps
- memory: 20Mi
+ memory: 50Mi
limits:
- cpu: 90m
- memory: 40Mi
+ cpu: 24m
+ memory: 100Mi
minReplicas: 1
maxReplicas: 1
hpa:
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index e22ae4f51fb..291c40f0f6b 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
include MobileHelpers
- let(:user) { create(:user, :no_super_sidebar) }
+ let(:user) { create(:user) }
let(:contributed_project) { create(:project, :public, :repository) }
let(:issue_note) { create(:note, project: contributed_project) }
@@ -83,7 +83,6 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
shared_context 'when user page is visited' do
before do
visit user.username
- page.click_link('Overview')
wait_for_requests
end
end
diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb
index ab322f18240..dffc87c2028 100644
--- a/spec/features/contextual_sidebar_spec.rb
+++ b/spec/features/contextual_sidebar_spec.rb
@@ -4,39 +4,19 @@ require 'spec_helper'
RSpec.describe 'Contextual sidebar', :js, feature_category: :remote_development do
context 'when context is a project' do
- let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
before do
sign_in(user)
+ visit project_path(project)
end
- context 'when analyzing the menu' do
- before do
- visit project_path(project)
- end
+ it 'shows flyout menu on other section on hover' do
+ expect(page).not_to have_link('Pipelines', href: project_pipelines_path(project))
- it 'shows flyout navs when collapsed or expanded apart from on the active item when expanded', :aggregate_failures do
- expect(page).not_to have_selector('.js-sidebar-collapsed')
-
- find('.rspec-link-pipelines').hover
-
- expect(page).to have_selector('.is-showing-fly-out')
-
- find('.rspec-project-link').hover
-
- expect(page).not_to have_selector('.is-showing-fly-out')
-
- find('.rspec-toggle-sidebar').click
-
- find('.rspec-link-pipelines').hover
-
- expect(page).to have_selector('.is-showing-fly-out')
-
- find('.rspec-project-link').hover
-
- expect(page).to have_selector('.is-showing-fly-out')
- end
+ find_button('Build').hover
+ expect(page).to have_link('Pipelines', href: project_pipelines_path(project))
end
end
end
diff --git a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
deleted file mode 100644
index a00666c2376..00000000000
--- a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'The group dashboard', :js, feature_category: :groups_and_projects do
- include ExternalAuthorizationServiceHelpers
- include Features::TopNavSpecHelpers
-
- let(:user) { create(:user, :no_super_sidebar) }
-
- before do
- sign_in user
- end
-
- describe 'The top navigation' do
- it 'has all the expected links' do
- visit dashboard_groups_path
-
- open_top_nav
-
- within_top_nav do
- expect(page).to have_button('Projects')
- expect(page).to have_button('Groups')
- expect(page).to have_link('Your work')
- expect(page).to have_link('Explore')
- end
- end
-
- it 'hides some links when an external authorization service is enabled' do
- enable_external_authorization_service_check
- visit dashboard_groups_path
-
- open_top_nav
-
- within_top_nav do
- expect(page).to have_button('Projects')
- expect(page).to have_button('Groups')
- expect(page).to have_link('Your work')
- expect(page).to have_link('Explore')
- end
- end
- end
-end
diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb
index 501405c5662..d34f8cb3e18 100644
--- a/spec/features/dashboard/issuables_counter_spec.rb
+++ b/spec/features/dashboard/issuables_counter_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching, feature_category: :team_planning do
- let(:user) { create(:user, :no_super_sidebar) }
+ let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project) }
@@ -17,33 +17,29 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching,
it 'reflects dashboard issues count', :js do
visit issues_path
- expect_counters('issues', '1', n_("%d assigned issue", "%d assigned issues", 1) % 1)
+ expect_issue_count(1)
issue.update!(assignees: [])
- Users::AssignedIssuesCountService.new(current_user: user).delete_cache
+ user.invalidate_cache_counts
- travel_to(3.minutes.from_now) do
- visit issues_path
+ visit issues_path
- expect_counters('issues', '0', n_("%d assigned issue", "%d assigned issues", 0) % 0)
- end
+ expect_issue_count(0)
end
it 'reflects dashboard merge requests count', :js do
visit merge_requests_path
- expect_counters('merge_requests', '1', n_("%d merge request", "%d merge requests", 1) % 1)
+ expect_merge_request_count(1)
merge_request.update!(assignees: [])
user.invalidate_cache_counts
- travel_to(3.minutes.from_now) do
- visit merge_requests_path
+ visit merge_requests_path
- expect_counters('merge_requests', '0', n_("%d merge request", "%d merge requests", 0) % 0)
- end
+ expect_merge_request_count(0)
end
def issues_path
@@ -54,11 +50,21 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching,
merge_requests_dashboard_path(assignee_username: user.username)
end
- def expect_counters(issuable_type, count, badge_label)
+ def expect_issue_count(count)
dashboard_count = find('.gl-tabs-nav li a.active')
+ expect(dashboard_count).to have_content(count)
+ within_testid('super-sidebar') do
+ expect(page).to have_link("Issues #{count}")
+ end
+ end
+
+ def expect_merge_request_count(count)
+ dashboard_count = find('.gl-tabs-nav li a.active')
expect(dashboard_count).to have_content(count)
- expect(page).to have_css(".dashboard-shortcuts-#{issuable_type}", visible: :all, text: count)
- expect(page).to have_css("span[aria-label='#{badge_label}']", visible: :all, text: count)
+
+ within_testid('super-sidebar') do
+ expect(page).to have_button("Merge requests #{count}")
+ end
end
end
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index d1fde4ba0f0..5ab5a27171c 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe 'Dashboard snippets', :js, feature_category: :source_code_managem
it 'shows documentation button in main comment area' do
parent_element = page.find('.row.empty-state')
- expect(parent_element).to have_link('Documentation', href: help_page_path('user/snippets.md'))
+ expect(parent_element).to have_link('Documentation', href: help_page_path('user/snippets'))
end
end
diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb
index dfafacf48e2..7d6d1648ff5 100644
--- a/spec/features/global_search_spec.rb
+++ b/spec/features/global_search_spec.rb
@@ -3,9 +3,7 @@
require 'spec_helper'
RSpec.describe 'Global search', :js, feature_category: :global_search do
- include AfterNextHelpers
-
- let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
before do
@@ -18,17 +16,18 @@ RSpec.describe 'Global search', :js, feature_category: :global_search do
visit dashboard_projects_path
end
- it 'renders updated search bar' do
- expect(page).to have_no_selector('.search-form')
- expect(page).to have_selector('#js-header-search')
+ it 'renders search button' do
+ expect(page).to have_button('Search or go to…')
end
- it 'focuses search input when shortcut "s" is pressed' do
- expect(page).not_to have_selector('#search:focus')
+ it 'opens search modal when shortcut "s" is pressed' do
+ search_selector = 'input[type="search"]:focus'
+
+ expect(page).not_to have_selector(search_selector)
find('body').native.send_key('s')
- expect(page).to have_selector('#search:focus')
+ expect(page).to have_selector(search_selector)
end
end
end
diff --git a/spec/features/groups/merge_requests_spec.rb b/spec/features/groups/merge_requests_spec.rb
index bbb7d322b9a..0a830e6715c 100644
--- a/spec/features/groups/merge_requests_spec.rb
+++ b/spec/features/groups/merge_requests_spec.rb
@@ -26,8 +26,10 @@ RSpec.describe 'Group merge requests page', feature_category: :code_review_workf
expect(page).not_to have_content(issuable_archived.title)
end
- it 'ignores archived merge request count badges in navbar' do
- expect(first(:link, text: 'Merge requests').find('.badge').text).to eq("1")
+ it 'ignores archived merge request count badges in navbar', :js do
+ within_testid('super-sidebar') do
+ expect(find_link(text: 'Merge requests').find('.badge').text).to eq("1")
+ end
end
it 'ignores archived merge request count badges in state-filters' do
diff --git a/spec/features/monitor_sidebar_link_spec.rb b/spec/features/monitor_sidebar_link_spec.rb
index 1d39f749ca7..1855379825b 100644
--- a/spec/features/monitor_sidebar_link_spec.rb
+++ b/spec/features/monitor_sidebar_link_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category: :shared do
+RSpec.describe 'Monitor dropdown sidebar', :js, feature_category: :shared do
let_it_be_with_reload(:project) { create(:project, :internal, :repository) }
- let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:user) { create(:user) }
let(:role) { nil }
@@ -13,7 +13,7 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category
sign_in(user)
end
- shared_examples 'shows Monitor menu based on the access level' do
+ shared_examples 'shows common Monitor menu item based on the access level' do
using RSpec::Parameterized::TableSyntax
let(:enabled) { Featurable::PRIVATE }
@@ -30,10 +30,14 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category
visit project_issues_path(project)
- if render
- expect(page).to have_selector('a.shortcuts-monitor', text: 'Monitor')
- else
- expect(page).not_to have_selector('a.shortcuts-monitor')
+ click_button('Monitor')
+
+ within_testid('super-sidebar') do
+ if render
+ expect(page).to have_link('Incidents')
+ else
+ expect(page).not_to have_link('Incidents', visible: :all)
+ end
end
end
end
@@ -44,32 +48,35 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category
before do
project.project_feature.update_attribute(:monitor_access_level, access_level)
+ visit project_issues_path(project)
+ click_button('Monitor')
end
- it 'has the correct `Monitor` menu items', :aggregate_failures do
- visit project_issues_path(project)
- expect(page).to have_selector('a.shortcuts-monitor', text: 'Monitor')
+ it 'has the correct `Monitor` and `Operate` menu items' do
expect(page).to have_link('Incidents', href: project_incidents_path(project))
+
+ click_button('Operate')
+
expect(page).to have_link('Environments', href: project_environments_path(project))
- expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
- expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
+ expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project), visible: :all)
+ expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project), visible: :all)
+ expect(page).not_to have_link('Kubernetes clusters', href: project_clusters_path(project), visible: :all)
end
context 'when monitor project feature is PRIVATE' do
let(:access_level) { ProjectFeature::PRIVATE }
- it 'does not show the `Monitor` menu' do
- expect(page).not_to have_selector('a.shortcuts-monitor')
+ it 'does not show common items of the `Monitor` menu' do
+ expect(page).not_to have_link('Error Tracking', href: project_incidents_path(project), visible: :all)
end
end
context 'when monitor project feature is DISABLED' do
let(:access_level) { ProjectFeature::DISABLED }
- it 'does not show the `Monitor` menu' do
- expect(page).not_to have_selector('a.shortcuts-monitor')
+ it 'does not show the `Incidents` menu' do
+ expect(page).not_to have_link('Error Tracking', href: project_incidents_path(project), visible: :all)
end
end
end
@@ -77,63 +84,86 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category
context 'when user has guest role' do
let(:role) { :guest }
- it 'has the correct `Monitor` menu items' do
+ it 'has the correct `Monitor` and `Operate` menu items' do
visit project_issues_path(project)
- expect(page).to have_selector('a.shortcuts-monitor', text: 'Monitor')
+
+ click_button('Monitor')
+
expect(page).to have_link('Incidents', href: project_incidents_path(project))
+
+ click_button('Operate')
+
expect(page).to have_link('Environments', href: project_environments_path(project))
- expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
- expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
+ expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project), visible: :all)
+ expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project), visible: :all)
+ expect(page).not_to have_link('Kubernetes clusters', href: project_clusters_path(project), visible: :all)
end
- it_behaves_like 'shows Monitor menu based on the access level'
+ it_behaves_like 'shows common Monitor menu item based on the access level'
end
context 'when user has reporter role' do
let(:role) { :reporter }
- it 'has the correct `Monitor` menu items' do
+ it 'has the correct `Monitor` and `Operate` menu items' do
visit project_issues_path(project)
+
+ click_button('Monitor')
+
expect(page).to have_link('Incidents', href: project_incidents_path(project))
- expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
- expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
+ click_button('Operate')
+
+ expect(page).to have_link('Environments', href: project_environments_path(project))
+
+ expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project), visible: :all)
+ expect(page).not_to have_link('Kubernetes clusters', href: project_clusters_path(project), visible: :all)
end
- it_behaves_like 'shows Monitor menu based on the access level'
+ it_behaves_like 'shows common Monitor menu item based on the access level'
end
context 'when user has developer role' do
let(:role) { :developer }
- it 'has the correct `Monitor` menu items' do
+ it 'has the correct `Monitor` and `Operate` menu items' do
visit project_issues_path(project)
+
+ click_button('Monitor')
+
expect(page).to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).to have_link('Incidents', href: project_incidents_path(project))
- expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).to have_link('Kubernetes', href: project_clusters_path(project))
+
+ click_button('Operate')
+
+ expect(page).to have_link('Environments', href: project_environments_path(project))
+ expect(page).to have_link('Kubernetes clusters', href: project_clusters_path(project))
end
- it_behaves_like 'shows Monitor menu based on the access level'
+ it_behaves_like 'shows common Monitor menu item based on the access level'
end
context 'when user has maintainer role' do
let(:role) { :maintainer }
- it 'has the correct `Monitor` menu items' do
+ it 'has the correct `Monitor` and `Operate` menu items' do
visit project_issues_path(project)
+
+ click_button('Monitor')
+
expect(page).to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).to have_link('Incidents', href: project_incidents_path(project))
- expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).to have_link('Kubernetes', href: project_clusters_path(project))
+
+ click_button('Operate')
+
+ expect(page).to have_link('Environments', href: project_environments_path(project))
+ expect(page).to have_link('Kubernetes clusters', href: project_clusters_path(project))
end
- it_behaves_like 'shows Monitor menu based on the access level'
+ it_behaves_like 'shows common Monitor menu item based on the access level'
end
end
diff --git a/spec/features/profiles/two_factor_auths_spec.rb b/spec/features/profiles/two_factor_auths_spec.rb
index b52f66cfcee..15ab79684d9 100644
--- a/spec/features/profiles/two_factor_auths_spec.rb
+++ b/spec/features/profiles/two_factor_auths_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe 'Two factor auths', feature_category: :user_profile do
fill_in 'pin_code', with: '123'
click_button 'Register with two-factor app'
- expect(page).to have_link('Try the troubleshooting steps here.', href: help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'))
+ expect(page).to have_link('Try the troubleshooting steps here.', href: help_page_path('user/profile/account/two_factor_authentication', anchor: 'troubleshooting'))
end
end
diff --git a/spec/features/projects/files/user_find_file_spec.rb b/spec/features/projects/files/user_find_file_spec.rb
index 005a870bea0..b6e739e8082 100644
--- a/spec/features/projects/files/user_find_file_spec.rb
+++ b/spec/features/projects/files/user_find_file_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User find project file', feature_category: :groups_and_projects do
include ListboxHelpers
- let(:user) { create :user, :no_super_sidebar }
+ let(:user) { create :user }
let(:project) { create :project, :repository }
before do
@@ -15,29 +15,25 @@ RSpec.describe 'User find project file', feature_category: :groups_and_projects
visit project_tree_path(project, project.repository.root_ref)
end
- def active_main_tab
- find('.sidebar-top-level-items > li.active')
- end
-
def find_file(text)
fill_in 'file_find', with: text
end
def ref_selector_dropdown
- find('.gl-button-text')
+ find('.ref-selector .gl-button-text')
end
it 'navigates to find file by shortcut', :js do
find('body').native.send_key('t')
- expect(active_main_tab).to have_content('Repository')
+ expect(page).to have_active_sub_navigation('Repository')
expect(page).to have_selector('.file-finder-holder', count: 1)
end
- it 'navigates to find file' do
+ it 'navigates to find file', :js do
click_link 'Find file'
- expect(active_main_tab).to have_content('Repository')
+ expect(page).to have_active_sub_navigation('Repository')
expect(page).to have_selector('.file-finder-holder', count: 1)
end
diff --git a/spec/features/projects/forks/fork_list_spec.rb b/spec/features/projects/forks/fork_list_spec.rb
index 86e4e03259e..966147637f5 100644
--- a/spec/features/projects/forks/fork_list_spec.rb
+++ b/spec/features/projects/forks/fork_list_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'listing forks of a project', feature_category: :groups_and_proje
let(:source) { create(:project, :public, :repository) }
let!(:fork) { fork_project(source, nil, repository: true) }
- let(:user) { create(:user, :no_super_sidebar) }
+ let(:user) { create(:user) }
before do
source.add_maintainer(user)
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index be9e99be36f..30d3303dfbb 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
let(:expected_detached_mr_tag) { 'merge request' }
context 'when user is logged in' do
- let(:user) { create(:user, :no_super_sidebar) }
+ let(:user) { create(:user) }
before do
sign_in(user)
@@ -650,7 +650,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
# header
expect(page).to have_text("##{pipeline.id}")
- expect(page).to have_link(pipeline.user.name, href: user_path(pipeline.user))
+ expect(page).to have_link(pipeline.user.name, href: /#{user_path(pipeline.user)}$/)
# stages
expect(page).to have_text('build')
diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb
index 12018b4b9d7..e5836739c57 100644
--- a/spec/features/projects/snippets/show_spec.rb
+++ b/spec/features/projects/snippets/show_spec.rb
@@ -3,35 +3,62 @@
require 'spec_helper'
RSpec.describe 'Projects > Snippets > Project snippet', :js, feature_category: :source_code_management do
- let_it_be(:user) { create(:user) }
+ let_it_be(:author) { create(:author) }
let_it_be(:project) do
- create(:project, creator: user).tap do |p|
- p.add_maintainer(user)
+ create(:project, :public, creator: author).tap do |p|
+ p.add_maintainer(author)
end
end
- let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) }
+ let_it_be(:snippet) { create(:project_snippet, :public, :repository, project: project, author: author) }
+ let(:anchor) { nil }
+ let(:file_path) { 'files/ruby/popen.rb' }
+
+ def visit_page
+ visit project_snippet_path(project, snippet, anchor: anchor)
+ end
before do
- sign_in(user)
+ # rubocop: disable RSpec/AnyInstanceOf -- TODO: The usage of let_it_be forces us
+ allow_any_instance_of(Snippet).to receive(:blobs)
+ .and_return([snippet.repository.blob_at('master', file_path)])
+ # rubocop: enable RSpec/AnyInstanceOf
end
- it_behaves_like 'show and render proper snippet blob' do
- let(:anchor) { nil }
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ visit_page
+ end
- subject do
- visit project_snippet_path(project, snippet, anchor: anchor)
+ context 'as project member' do
+ let(:user) { author }
- wait_for_requests
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does show New Snippet button'
end
- end
- # it_behaves_like 'showing user status' do
- # This will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/262394
+ context 'as external user' do
+ let_it_be(:user) { create(:user, :external) }
+
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does not show New Snippet button'
+ end
- it_behaves_like 'does not show New Snippet button' do
- let(:file_path) { 'files/ruby/popen.rb' }
+ context 'as another user' do
+ let_it_be(:user) { create(:user) }
+
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does not show New Snippet button'
+ end
+ end
+
+ context 'when unauthenticated' do
+ before do
+ visit_page
+ end
- subject { visit project_snippet_path(project, snippet) }
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does not show New Snippet button'
end
end
diff --git a/spec/features/projects/work_items/work_item_spec.rb b/spec/features/projects/work_items/work_item_spec.rb
index 876444e451a..33153d21575 100644
--- a/spec/features/projects/work_items/work_item_spec.rb
+++ b/spec/features/projects/work_items/work_item_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'Work item', :js, feature_category: :team_planning do
include ListboxHelpers
- let_it_be_with_reload(:user) { create(:user, :no_super_sidebar) }
- let_it_be_with_reload(:user2) { create(:user, :no_super_sidebar, name: 'John') }
+ let_it_be_with_reload(:user) { create(:user) }
+ let_it_be_with_reload(:user2) { create(:user, name: 'John') }
let_it_be(:project) { create(:project, :public) }
let_it_be(:work_item) { create(:work_item, project: project) }
diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb
index 3f2a71b63dc..8381642cd4d 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
include FilteredSearchHelpers
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:reporter) { create(:user, :no_super_sidebar) }
- let_it_be(:developer) { create(:user, :no_super_sidebar) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:developer) { create(:user) }
let(:user) { reporter }
@@ -46,31 +46,34 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
context 'when using the keyboard shortcut' do
before do
- find('#search')
find('body').native.send_keys('s')
- wait_for_all_requests
end
- it 'shows the category search dropdown', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/250285' do
- expect(page).to have_selector('.dropdown-header', text: /#{scope_name}/i)
+ it 'shows the search modal' do
+ expect(page).to have_selector(search_modal_results, visible: :visible)
end
end
- context 'when clicking the search field' do
+ context 'when clicking the search button' do
before do
- page.find('#search').click
+ within_testid('super-sidebar') do
+ click_button "Search or go to…"
+ end
wait_for_all_requests
end
- it 'shows category search dropdown', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/250285' do
- expect(page).to have_selector('.dropdown-header', text: /#{scope_name}/i)
+ it 'shows search scope badge' do
+ fill_in 'search', with: 'text'
+ within('#super-sidebar-search-modal') do
+ expect(page).to have_selector('.search-scope-help', text: scope_name)
+ end
end
context 'when clicking issues', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/332317' do
let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
it 'shows assigned issues' do
- find('[data-testid="header-search-dropdown-menu"]').click_link('Issues assigned to me')
+ find(search_modal_results).click_link('Issues assigned to me')
expect(page).to have_selector('.issues-list .issue')
expect_tokens([assignee_token(user.name)])
@@ -78,7 +81,7 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
end
it 'shows created issues' do
- find('[data-testid="header-search-dropdown-menu"]').click_link("Issues I've created")
+ find(search_modal_results).click_link("Issues I've created")
expect(page).to have_selector('.issues-list .issue')
expect_tokens([author_token(user.name)])
@@ -90,7 +93,7 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignees: [user]) }
it 'shows assigned merge requests' do
- find('[data-testid="header-search-dropdown-menu"]').click_link('Merge requests assigned to me')
+ find(search_modal_results).click_link('Merge requests assigned to me')
expect(page).to have_selector('.mr-list .merge-request')
expect_tokens([assignee_token(user.name)])
@@ -98,7 +101,7 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
end
it 'shows created merge requests' do
- find('[data-testid="header-search-dropdown-menu"]').click_link("Merge requests I've created")
+ find(search_modal_results).click_link("Merge requests I've created")
expect(page).to have_selector('.mr-list .merge-request')
expect_tokens([author_token(user.name)])
@@ -119,7 +122,7 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
context 'when user is in a global scope' do
include_examples 'search field examples' do
let(:url) { root_path }
- let(:scope_name) { 'All GitLab' }
+ let(:scope_name) { 'in all GitLab' }
end
it 'displays search options', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/251076' do
@@ -136,11 +139,13 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
end
it 'displays result counts for all categories' do
- expect(page).to have_content('Projects 1')
- expect(page).to have_content('Issues 1')
- expect(page).to have_content('Merge requests 0')
- expect(page).to have_content('Milestones 0')
- expect(page).to have_content('Users 0')
+ within_testid('super-sidebar') do
+ expect(page).to have_link('Projects 1')
+ expect(page).to have_link('Issues 1')
+ expect(page).to have_link('Merge requests 0')
+ expect(page).to have_link('Milestones 0')
+ expect(page).to have_link('Users 0')
+ end
end
end
end
@@ -162,9 +167,8 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
it 'displays search options' do
fill_in_search('test')
- expect(page).to have_selector(scoped_search_link('test', search_code: true))
expect(page).to have_selector(scoped_search_link('test', group_id: group.id, search_code: true))
- expect(page).to have_selector(scoped_search_link('test', project_id: project.id, group_id: group.id, search_code: true))
+ expect(page).to have_selector(scoped_search_link('test', search_code: true))
end
end
@@ -176,26 +180,25 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
it 'displays search options' do
fill_in_search('test')
- sleep 0.5
- expect(page).to have_selector(scoped_search_link('test', search_code: true, repository_ref: 'master'))
+
expect(page).not_to have_selector(scoped_search_link('test', search_code: true, group_id: project.namespace_id, repository_ref: 'master'))
- expect(page).to have_selector(scoped_search_link('test', search_code: true, project_id: project.id, repository_ref: 'master'))
+ expect(page).to have_selector(scoped_search_link('test', search_code: true, repository_ref: 'master'))
end
it 'displays a link to project merge requests' do
fill_in_search('Merge')
- within(dashboard_search_options_popup_menu) do
- expect(page).to have_text('Merge requests')
+ within(search_modal_results) do
+ expect(page).to have_link('Merge requests')
end
end
it 'does not display a link to project feature flags' do
fill_in_search('Feature')
- within(dashboard_search_options_popup_menu) do
- expect(page).to have_text('Feature in all GitLab')
- expect(page).to have_no_text('Feature Flags')
+ within(search_modal_results) do
+ expect(page).to have_link('in all GitLab Feature')
+ expect(page).not_to have_link('Feature Flags')
end
end
@@ -205,8 +208,8 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
it 'displays a link to project feature flags' do
fill_in_search('Feature')
- within(dashboard_search_options_popup_menu) do
- expect(page).to have_text('Feature Flags')
+ within(search_modal_results) do
+ expect(page).to have_link('Feature Flags')
end
end
end
@@ -228,8 +231,8 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
it 'displays search options' do
fill_in_search('test')
+
expect(page).to have_selector(scoped_search_link('test'))
- expect(page).to have_selector(scoped_search_link('test', group_id: group.id))
expect(page).not_to have_selector(scoped_search_link('test', project_id: project.id))
end
end
@@ -253,7 +256,6 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
fill_in_search('test')
expect(page).to have_selector(scoped_search_link('test'))
- expect(page).to have_selector(scoped_search_link('test', group_id: subgroup.id))
expect(page).not_to have_selector(scoped_search_link('test', project_id: project.id))
end
end
@@ -268,10 +270,10 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
href.concat("&search_code=true") if search_code
href.concat("&repository_ref=#{repository_ref}") if repository_ref
- "[data-testid='header-search-dropdown-menu'] a[href='#{href}']"
+ ".global-search-results a[href='#{href}']"
end
- def dashboard_search_options_popup_menu
- "[data-testid='header-search-dropdown-menu'] .header-search-dropdown-content"
+ def search_modal_results
+ ".global-search-results"
end
end
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index ac0682d9e06..03f46ea0122 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -3,45 +3,63 @@
require 'spec_helper'
RSpec.describe 'Snippet', :js, feature_category: :source_code_management do
- let_it_be(:user) { create(:user) }
- let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) }
+ let_it_be(:owner) { create(:user) }
+ let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: owner) }
+ let(:anchor) { nil }
+ let(:file_path) { 'files/ruby/popen.rb' }
- it_behaves_like 'show and render proper snippet blob' do
- let(:anchor) { nil }
+ before do
+ # rubocop: disable RSpec/AnyInstanceOf -- TODO: The usage of let_it_be forces us
+ allow_any_instance_of(Snippet).to receive(:blobs)
+ .and_return([snippet.repository.blob_at('master', file_path)])
+ # rubocop: enable RSpec/AnyInstanceOf
+ end
- subject do
- visit snippet_path(snippet, anchor: anchor)
+ def visit_page
+ visit snippet_path(snippet, anchor: anchor)
+ end
- wait_for_requests
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ visit_page
end
- end
- # it_behaves_like 'showing user status' do
- # This will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/262394
+ context 'as the snippet owner' do
+ let(:user) { owner }
- it_behaves_like 'does not show New Snippet button' do
- let(:file_path) { 'files/ruby/popen.rb' }
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does show New Snippet button'
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
+ end
- subject { visit snippet_path(snippet) }
- end
+ context 'as external user' do
+ let_it_be(:user) { create(:user, :external) }
- it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does not show New Snippet button'
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
+ end
- context 'when unauthenticated' do
- it 'shows the "Explore" sidebar' do
- visit snippet_path(snippet)
+ context 'as another user' do
+ let_it_be(:user) { create(:user) }
- expect(page).to have_css('#super-sidebar-context-header', text: 'Explore')
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does show New Snippet button'
+ it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
end
end
- context 'when authenticated as a different user' do
- let_it_be(:different_user) { create(:user, :no_super_sidebar) }
-
+ context 'when unauthenticated' do
before do
- sign_in(different_user)
+ visit_page
end
- it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
+ it_behaves_like 'show and render proper snippet blob'
+ it_behaves_like 'does not show New Snippet button'
+
+ it 'shows the "Explore" sidebar' do
+ expect(page).to have_css('#super-sidebar-context-header', text: 'Explore')
+ end
end
end
diff --git a/spec/frontend/environments/graphql/resolvers/flux_spec.js b/spec/frontend/environments/graphql/resolvers/flux_spec.js
index aa6f9e120f0..ea733c6e0e8 100644
--- a/spec/frontend/environments/graphql/resolvers/flux_spec.js
+++ b/spec/frontend/environments/graphql/resolvers/flux_spec.js
@@ -1,4 +1,5 @@
import MockAdapter from 'axios-mock-adapter';
+import { WatchApi } from '@gitlab/cluster-client';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_OK, HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status';
import { resolvers } from '~/environments/graphql/resolvers';
@@ -27,114 +28,306 @@ describe('~/frontend/environments/graphql/resolvers', () => {
});
describe('fluxKustomizationStatus', () => {
+ const client = { writeQuery: jest.fn() };
const endpoint = `${configuration.basePath}/apis/kustomize.toolkit.fluxcd.io/v1beta1/namespaces/${namespace}/kustomizations/${environmentName}`;
const fluxResourcePath =
'kustomize.toolkit.fluxcd.io/v1beta1/namespaces/my-namespace/kustomizations/app';
const endpointWithFluxResourcePath = `${configuration.basePath}/apis/${fluxResourcePath}`;
- it('should request Flux Kustomizations for the provided namespace via the Kubernetes API if the fluxResourcePath is not specified', async () => {
- mock
- .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
- .reply(HTTP_STATUS_OK, {
- status: { conditions: fluxKustomizationsMock },
- });
+ describe('when k8sWatchApi feature is disabled', () => {
+ it('should request Flux Kustomizations for the provided namespace via the Kubernetes API if the fluxResourcePath is not specified', async () => {
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
+ .reply(HTTP_STATUS_OK, {
+ status: { conditions: fluxKustomizationsMock },
+ });
+
+ const fluxKustomizationStatus = await mockResolvers.Query.fluxKustomizationStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
- const fluxKustomizationStatus = await mockResolvers.Query.fluxKustomizationStatus(null, {
- configuration,
- namespace,
- environmentName,
+ expect(fluxKustomizationStatus).toEqual(fluxKustomizationsMock);
});
+ it('should request Flux Kustomization for the provided fluxResourcePath via the Kubernetes API', async () => {
+ mock
+ .onGet(endpointWithFluxResourcePath, {
+ withCredentials: true,
+ headers: configuration.baseOptions.headers,
+ })
+ .reply(HTTP_STATUS_OK, {
+ status: { conditions: fluxKustomizationsMock },
+ });
- expect(fluxKustomizationStatus).toEqual(fluxKustomizationsMock);
- });
- it('should request Flux Kustomization for the provided fluxResourcePath via the Kubernetes API', async () => {
- mock
- .onGet(endpointWithFluxResourcePath, {
- withCredentials: true,
- headers: configuration.baseOptions.headers,
- })
- .reply(HTTP_STATUS_OK, {
- status: { conditions: fluxKustomizationsMock },
- });
+ const fluxKustomizationStatus = await mockResolvers.Query.fluxKustomizationStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ fluxResourcePath,
+ },
+ { client },
+ );
- const fluxKustomizationStatus = await mockResolvers.Query.fluxKustomizationStatus(null, {
- configuration,
- namespace,
- environmentName,
- fluxResourcePath,
+ expect(fluxKustomizationStatus).toEqual(fluxKustomizationsMock);
});
+ it('should throw an error if the API call fails', async () => {
+ const apiError = 'Invalid credentials';
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.base })
+ .reply(HTTP_STATUS_UNAUTHORIZED, { message: apiError });
+
+ const fluxKustomizationsError = mockResolvers.Query.fluxKustomizationStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
- expect(fluxKustomizationStatus).toEqual(fluxKustomizationsMock);
+ await expect(fluxKustomizationsError).rejects.toThrow(apiError);
+ });
});
- it('should throw an error if the API call fails', async () => {
- const apiError = 'Invalid credentials';
- mock
- .onGet(endpoint, { withCredentials: true, headers: configuration.base })
- .reply(HTTP_STATUS_UNAUTHORIZED, { message: apiError });
- const fluxKustomizationsError = mockResolvers.Query.fluxKustomizationStatus(null, {
- configuration,
- namespace,
- environmentName,
+ describe('when k8sWatchApi feature is enabled', () => {
+ const mockWatcher = WatchApi.prototype;
+ const mockKustomizationStatusFn = jest.fn().mockImplementation(() => {
+ return Promise.resolve(mockWatcher);
+ });
+ const mockOnDataFn = jest.fn().mockImplementation((eventName, callback) => {
+ if (eventName === 'data') {
+ callback(fluxKustomizationsMock);
+ }
+ });
+ const resourceName = 'custom-resource';
+
+ beforeEach(() => {
+ gon.features = { k8sWatchApi: true };
+ jest.spyOn(mockWatcher, 'subscribeToStream').mockImplementation(mockKustomizationStatusFn);
+ jest.spyOn(mockWatcher, 'on').mockImplementation(mockOnDataFn);
+ });
+
+ describe('when the Kustomization data is present', () => {
+ beforeEach(() => {
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
+ .reply(HTTP_STATUS_OK, {
+ metadata: { name: resourceName },
+ status: { conditions: fluxKustomizationsMock },
+ });
+ });
+ it('should watch Kustomization by the metadata name from the cluster_client library when the data is present', async () => {
+ await mockResolvers.Query.fluxKustomizationStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
+
+ expect(mockKustomizationStatusFn).toHaveBeenCalledWith(
+ `/apis/kustomize.toolkit.fluxcd.io/v1beta1/namespaces/${namespace}/kustomizations`,
+ {
+ watch: true,
+ fieldSelector: `metadata.name=${decodeURIComponent(resourceName)}`,
+ },
+ );
+ });
+
+ it('should return data when received from the library', async () => {
+ const kustomizationStatus = await mockResolvers.Query.fluxKustomizationStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
+
+ expect(kustomizationStatus).toEqual(fluxKustomizationsMock);
+ });
});
- await expect(fluxKustomizationsError).rejects.toThrow(apiError);
+ it('should not watch Kustomization by the metadata name from the cluster_client library when the data is not present', async () => {
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
+ .reply(HTTP_STATUS_OK, {});
+
+ await mockResolvers.Query.fluxKustomizationStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
+
+ expect(mockKustomizationStatusFn).not.toHaveBeenCalled();
+ });
});
});
describe('fluxHelmReleaseStatus', () => {
+ const client = { writeQuery: jest.fn() };
const endpoint = `${configuration.basePath}/apis/helm.toolkit.fluxcd.io/v2beta1/namespaces/${namespace}/helmreleases/${environmentName}`;
const fluxResourcePath =
'helm.toolkit.fluxcd.io/v2beta1/namespaces/my-namespace/helmreleases/app';
const endpointWithFluxResourcePath = `${configuration.basePath}/apis/${fluxResourcePath}`;
- it('should request Flux Helm Releases via the Kubernetes API', async () => {
- mock
- .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
- .reply(HTTP_STATUS_OK, {
- status: { conditions: fluxKustomizationsMock },
- });
+ describe('when k8sWatchApi feature is disabled', () => {
+ it('should request Flux Helm Releases via the Kubernetes API', async () => {
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
+ .reply(HTTP_STATUS_OK, {
+ status: { conditions: fluxKustomizationsMock },
+ });
+
+ const fluxHelmReleaseStatus = await mockResolvers.Query.fluxHelmReleaseStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
- const fluxHelmReleaseStatus = await mockResolvers.Query.fluxHelmReleaseStatus(null, {
- configuration,
- namespace,
- environmentName,
+ expect(fluxHelmReleaseStatus).toEqual(fluxKustomizationsMock);
});
+ it('should request Flux HelmRelease for the provided fluxResourcePath via the Kubernetes API', async () => {
+ mock
+ .onGet(endpointWithFluxResourcePath, {
+ withCredentials: true,
+ headers: configuration.baseOptions.headers,
+ })
+ .reply(HTTP_STATUS_OK, {
+ status: { conditions: fluxKustomizationsMock },
+ });
- expect(fluxHelmReleaseStatus).toEqual(fluxKustomizationsMock);
- });
- it('should request Flux HelmRelease for the provided fluxResourcePath via the Kubernetes API', async () => {
- mock
- .onGet(endpointWithFluxResourcePath, {
- withCredentials: true,
- headers: configuration.baseOptions.headers,
- })
- .reply(HTTP_STATUS_OK, {
- status: { conditions: fluxKustomizationsMock },
- });
+ const fluxHelmReleaseStatus = await mockResolvers.Query.fluxHelmReleaseStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ fluxResourcePath,
+ },
+ { client },
+ );
- const fluxHelmReleaseStatus = await mockResolvers.Query.fluxHelmReleaseStatus(null, {
- configuration,
- namespace,
- environmentName,
- fluxResourcePath,
+ expect(fluxHelmReleaseStatus).toEqual(fluxKustomizationsMock);
});
+ it('should throw an error if the API call fails', async () => {
+ const apiError = 'Invalid credentials';
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.base })
+ .reply(HTTP_STATUS_UNAUTHORIZED, { message: apiError });
+
+ const fluxHelmReleasesError = mockResolvers.Query.fluxHelmReleaseStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
- expect(fluxHelmReleaseStatus).toEqual(fluxKustomizationsMock);
+ await expect(fluxHelmReleasesError).rejects.toThrow(apiError);
+ });
});
- it('should throw an error if the API call fails', async () => {
- const apiError = 'Invalid credentials';
- mock
- .onGet(endpoint, { withCredentials: true, headers: configuration.base })
- .reply(HTTP_STATUS_UNAUTHORIZED, { message: apiError });
- const fluxHelmReleasesError = mockResolvers.Query.fluxHelmReleaseStatus(null, {
- configuration,
- namespace,
- environmentName,
+ describe('when k8sWatchApi feature is enabled', () => {
+ const mockWatcher = WatchApi.prototype;
+ const mockHelmReleaseStatusFn = jest.fn().mockImplementation(() => {
+ return Promise.resolve(mockWatcher);
+ });
+ const mockOnDataFn = jest.fn().mockImplementation((eventName, callback) => {
+ if (eventName === 'data') {
+ callback(fluxKustomizationsMock);
+ }
+ });
+ const resourceName = 'custom-resource';
+
+ beforeEach(() => {
+ gon.features = { k8sWatchApi: true };
+ jest.spyOn(mockWatcher, 'subscribeToStream').mockImplementation(mockHelmReleaseStatusFn);
+ jest.spyOn(mockWatcher, 'on').mockImplementation(mockOnDataFn);
+ });
+
+ describe('when the HelmRelease data is present', () => {
+ beforeEach(() => {
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
+ .reply(HTTP_STATUS_OK, {
+ metadata: { name: resourceName },
+ status: { conditions: fluxKustomizationsMock },
+ });
+ });
+ it('should watch HelmRelease by the metadata name from the cluster_client library when the data is present', async () => {
+ await mockResolvers.Query.fluxHelmReleaseStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
+
+ expect(mockHelmReleaseStatusFn).toHaveBeenCalledWith(
+ `/apis/helm.toolkit.fluxcd.io/v2beta1/namespaces/${namespace}/helmreleases`,
+ {
+ watch: true,
+ fieldSelector: `metadata.name=${decodeURIComponent(resourceName)}`,
+ },
+ );
+ });
+
+ it('should return data when received from the library', async () => {
+ const fluxHelmReleaseStatus = await mockResolvers.Query.fluxHelmReleaseStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
+
+ expect(fluxHelmReleaseStatus).toEqual(fluxKustomizationsMock);
+ });
});
- await expect(fluxHelmReleasesError).rejects.toThrow(apiError);
+ it('should not watch Kustomization by the metadata name from the cluster_client library when the data is not present', async () => {
+ mock
+ .onGet(endpoint, { withCredentials: true, headers: configuration.baseOptions.headers })
+ .reply(HTTP_STATUS_OK, {});
+
+ await mockResolvers.Query.fluxHelmReleaseStatus(
+ null,
+ {
+ configuration,
+ namespace,
+ environmentName,
+ },
+ { client },
+ );
+
+ expect(mockHelmReleaseStatusFn).not.toHaveBeenCalled();
+ });
});
});
});
diff --git a/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js b/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js
index da86d5443bf..ee7164515f6 100644
--- a/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js
@@ -133,6 +133,8 @@ describe('Source Viewer component', () => {
expect(blameDataQueryHandlerSuccess).toHaveBeenCalledWith(
expect.objectContaining({ fromLine: 1, toLine: 70 }),
);
+
+ expect(findChunks().at(0).props('isHighlighted')).toBe(true);
});
it('does not render a Blame component when `showBlame: false`', async () => {
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 3e95cb25b12..bbbb2dd4d71 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -755,14 +755,6 @@ RSpec.describe ApplicationHelper do
it { is_expected.not_to include('with-top-bar') }
end
end
-
- describe 'logged-out-marketing-header' do
- before do
- allow(helper).to receive(:current_user).and_return(nil)
- end
-
- it { is_expected.not_to include('logged-out-marketing-header') }
- end
end
describe '#dispensable_render' do
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
index 18a978f6921..3e0fc1ffcb7 100644
--- a/spec/helpers/nav_helper_spec.rb
+++ b/spec/helpers/nav_helper_spec.rb
@@ -160,24 +160,6 @@ RSpec.describe NavHelper, feature_category: :navigation do
end
end
- shared_examples 'anonymous show_super_sidebar is supposed to' do
- before do
- stub_feature_flags(super_sidebar_logged_out: feature_flag)
- end
-
- context 'when super_sidebar_logged_out feature flag is disabled' do
- let(:feature_flag) { false }
-
- specify { expect(subject).to eq false }
- end
-
- context 'when super_sidebar_logged_out feature flag is enabled' do
- let(:feature_flag) { true }
-
- specify { expect(subject).to eq true }
- end
- end
-
context 'without a user' do
context 'with current_user (nil) as a default' do
before do
@@ -186,13 +168,13 @@ RSpec.describe NavHelper, feature_category: :navigation do
subject { helper.show_super_sidebar? }
- it_behaves_like 'anonymous show_super_sidebar is supposed to'
+ specify { expect(subject).to eq true }
end
context 'with nil provided as an argument' do
subject { helper.show_super_sidebar?(nil) }
- it_behaves_like 'anonymous show_super_sidebar is supposed to'
+ specify { expect(subject).to eq true }
end
end
diff --git a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
index 1c2d159950a..108a98e28a4 100644
--- a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Sidebars::Projects::Menus::ScopeMenu, feature_category: :navigati
describe '#container_html_options' do
subject { described_class.new(context).container_html_options }
- specify { is_expected.to match(hash_including(class: 'shortcuts-project rspec-project-link')) }
+ specify { is_expected.to match(hash_including(class: 'shortcuts-project')) }
end
describe '#extra_nav_link_html_options' do
diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb
index 66da0ab2eec..dd5ce63876e 100644
--- a/spec/support/helpers/search_helpers.rb
+++ b/spec/support/helpers/search_helpers.rb
@@ -2,10 +2,10 @@
module SearchHelpers
def fill_in_search(text)
- page.within('.header-search') do
- find('#search').click
- fill_in 'search', with: text
+ within_testid('super-sidebar') do
+ click_button "Search or go to…"
end
+ fill_in 'search', with: text
wait_for_all_requests
end
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index b36f67be55e..6f34bee3bea 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -4011,7 +4011,6 @@
- './spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb'
- './spec/features/projects/show/user_uploads_files_spec.rb'
- './spec/features/projects/snippets/create_snippet_spec.rb'
-- './spec/features/projects/snippets/show_spec.rb'
- './spec/features/projects/snippets/user_comments_on_snippet_spec.rb'
- './spec/features/projects/snippets/user_deletes_snippet_spec.rb'
- './spec/features/projects/snippets/user_updates_snippet_spec.rb'
@@ -4082,7 +4081,6 @@
- './spec/features/snippets/private_snippets_spec.rb'
- './spec/features/snippets/public_snippets_spec.rb'
- './spec/features/snippets/search_snippets_spec.rb'
-- './spec/features/snippets/show_spec.rb'
- './spec/features/snippets/spam_snippets_spec.rb'
- './spec/features/snippets_spec.rb'
- './spec/features/snippets/user_creates_snippet_spec.rb'
diff --git a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
index 58bf461c733..d410653ca43 100644
--- a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
+++ b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
@@ -4,8 +4,8 @@ RSpec.shared_examples 'project features apply to issuables' do |klass|
let(:described_class) { klass }
let(:group) { create(:group) }
- let(:user_in_group) { create(:group_member, :developer, user: create(:user, :no_super_sidebar), group: group ).user }
- let(:user_outside_group) { create(:user, :no_super_sidebar) }
+ let(:user_in_group) { create(:group_member, :developer, user: create(:user), group: group ).user }
+ let(:user_outside_group) { create(:user) }
let(:project) { create(:project, :public, project_args) }
diff --git a/spec/support/shared_examples/features/snippets_shared_examples.rb b/spec/support/shared_examples/features/snippets_shared_examples.rb
index 383f81d048f..0f830fa125a 100644
--- a/spec/support/shared_examples/features/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/features/snippets_shared_examples.rb
@@ -52,30 +52,24 @@ RSpec.shared_examples 'tabs with counts' do
end
RSpec.shared_examples 'does not show New Snippet button' do
- let(:user) { create(:user, :external, :no_super_sidebar) }
-
specify do
- sign_in(user)
-
- subject
-
- wait_for_requests
-
+ expect(page).to have_link(text: "$#{snippet.id}")
expect(page).not_to have_link('New snippet')
end
end
-RSpec.shared_examples 'show and render proper snippet blob' do
- before do
- allow_any_instance_of(Snippet).to receive(:blobs).and_return([snippet.repository.blob_at('master', file_path)])
+RSpec.shared_examples 'does show New Snippet button' do
+ specify do
+ expect(page).to have_link(text: "$#{snippet.id}")
+ expect(page).to have_link('New snippet')
end
+end
+RSpec.shared_examples 'show and render proper snippet blob' do
context 'Ruby file' do
let(:file_path) { 'files/ruby/popen.rb' }
it 'displays the blob' do
- subject
-
aggregate_failures do
# shows highlighted Ruby code
expect(page).to have_content("require 'fileutils'")
@@ -99,10 +93,6 @@ RSpec.shared_examples 'show and render proper snippet blob' do
let(:file_path) { 'files/markdown/ruby-style-guide.md' }
context 'visiting directly' do
- before do
- subject
- end
-
it 'displays the blob using the rich viewer' do
aggregate_failures do
# hides the simple viewer
@@ -171,8 +161,6 @@ RSpec.shared_examples 'show and render proper snippet blob' do
let(:anchor) { 'LC1' }
it 'displays the blob using the simple viewer' do
- subject
-
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index 94db1c55a90..01674e941d5 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -416,7 +416,7 @@ RSpec.shared_examples 'work items todos' do
expect(page).to have_button s_('WorkItem|Mark as done')
- page.within ".header-content span[aria-label='#{_('Todos count')}']" do
+ within_testid('todos-shortcut-button') do
expect(page).to have_content '1'
end
end
@@ -426,7 +426,9 @@ RSpec.shared_examples 'work items todos' do
click_button s_('WorkItem|Mark as done')
expect(page).to have_button s_('WorkItem|Add a to do')
- expect(page).to have_selector(".header-content span[aria-label='#{_('Todos count')}']", visible: :hidden)
+ within_testid('todos-shortcut-button') do
+ expect(page).to have_content("")
+ end
end
end
diff --git a/spec/views/layouts/application.html.haml_spec.rb b/spec/views/layouts/application.html.haml_spec.rb
index 825e295b73d..20bef2a3685 100644
--- a/spec/views/layouts/application.html.haml_spec.rb
+++ b/spec/views/layouts/application.html.haml_spec.rb
@@ -80,7 +80,6 @@ RSpec.describe 'layouts/application' do
before do
allow(view).to receive(:current_user).and_return(nil)
allow(view).to receive(:current_user_mode).and_return(Gitlab::Auth::CurrentUserMode.new(nil))
- Feature.enable(:super_sidebar_logged_out)
end
it 'renders the new marketing header for logged-out users' do
diff --git a/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb b/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb
index f81e8c5badf..7f49f96de03 100644
--- a/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb
+++ b/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb
@@ -5,7 +5,6 @@ require 'spec_helper'
RSpec.describe 'layouts/header/_super_sidebar_logged_out', feature_category: :navigation do
before do
allow(view).to receive(:current_user_mode).and_return(Gitlab::Auth::CurrentUserMode.new(nil))
- Feature.enable(:super_sidebar_logged_out)
end
context 'on gitlab.com' do
diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index 3ec731c8eb7..005283f66da 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do
it 'has a link to the project path' do
render
- expect(rendered).to have_link(project.name, href: project_path(project), class: %w(shortcuts-project rspec-project-link))
+ expect(rendered).to have_link(project.name, href: project_path(project), class: 'shortcuts-project')
expect(rendered).to have_selector("[aria-label=\"#{project.name}\"]")
end
end