summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/admin/admin_builds_spec.rb6
-rw-r--r--spec/features/admin/admin_dev_ops_report_spec.rb70
-rw-r--r--spec/features/admin/admin_groups_spec.rb5
-rw-r--r--spec/features/admin/admin_settings_spec.rb30
-rw-r--r--spec/features/admin/admin_users_spec.rb68
-rw-r--r--spec/features/admin/admin_uses_repository_checks_spec.rb2
-rw-r--r--spec/features/alert_management_spec.rb15
-rw-r--r--spec/features/alerts_settings/user_views_alerts_settings_spec.rb64
-rw-r--r--spec/features/boards/add_issues_modal_spec.rb7
-rw-r--r--spec/features/breadcrumbs_schema_markup_spec.rb106
-rw-r--r--spec/features/calendar_spec.rb2
-rw-r--r--spec/features/callouts/registration_enabled_spec.rb49
-rw-r--r--spec/features/canonical_link_spec.rb70
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb2
-rw-r--r--spec/features/dashboard/shortcuts_spec.rb2
-rw-r--r--spec/features/discussion_comments/merge_request_spec.rb2
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb2
-rw-r--r--spec/features/explore/user_explores_projects_spec.rb107
-rw-r--r--spec/features/file_uploads/multipart_invalid_uploads_spec.rb6
-rw-r--r--spec/features/frequently_visited_projects_and_groups_spec.rb47
-rw-r--r--spec/features/global_search_spec.rb8
-rw-r--r--spec/features/group_variables_spec.rb2
-rw-r--r--spec/features/groups/container_registry_spec.rb14
-rw-r--r--spec/features/groups/dependency_proxy_spec.rb111
-rw-r--r--spec/features/groups/members/filter_members_spec.rb37
-rw-r--r--spec/features/groups/members/leave_group_spec.rb10
-rw-r--r--spec/features/groups/members/list_members_spec.rb15
-rw-r--r--spec/features/groups/members/manage_groups_spec.rb39
-rw-r--r--spec/features/groups/members/manage_members_spec.rb26
-rw-r--r--spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb34
-rw-r--r--spec/features/groups/members/master_manages_access_requests_spec.rb4
-rw-r--r--spec/features/groups/members/search_members_spec.rb13
-rw-r--r--spec/features/groups/members/sort_members_spec.rb70
-rw-r--r--spec/features/groups/milestone_spec.rb1
-rw-r--r--spec/features/groups/navbar_spec.rb14
-rw-r--r--spec/features/groups/settings/repository_spec.rb17
-rw-r--r--spec/features/groups/show_spec.rb10
-rw-r--r--spec/features/groups_spec.rb48
-rw-r--r--spec/features/ide/user_sees_editor_info_spec.rb93
-rw-r--r--spec/features/incidents/user_views_incident_spec.rb82
-rw-r--r--spec/features/invites_spec.rb19
-rw-r--r--spec/features/issuables/close_reopen_report_toggle_spec.rb56
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb4
-rw-r--r--spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb4
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb43
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb4
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb27
-rw-r--r--spec/features/issues/user_interacts_with_awards_spec.rb4
-rw-r--r--spec/features/issues/user_sees_live_update_spec.rb2
-rw-r--r--spec/features/issues/user_views_issue_spec.rb2
-rw-r--r--spec/features/merge_request/user_comments_on_diff_spec.rb6
-rw-r--r--spec/features/merge_request/user_comments_on_merge_request_spec.rb21
-rw-r--r--spec/features/merge_request/user_expands_diff_spec.rb6
-rw-r--r--spec/features/merge_request/user_merges_immediately_spec.rb2
-rw-r--r--spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb13
-rw-r--r--spec/features/merge_request/user_resolves_conflicts_spec.rb8
-rw-r--r--spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb4
-rw-r--r--spec/features/merge_request/user_resolves_wip_mr_spec.rb4
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb5
-rw-r--r--spec/features/merge_request/user_sees_suggest_pipeline_spec.rb38
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb2
-rw-r--r--spec/features/merge_request/user_views_diffs_spec.rb2
-rw-r--r--spec/features/merge_requests/user_exports_as_csv_spec.rb31
-rw-r--r--spec/features/merge_requests/user_filters_by_draft_spec.rb31
-rw-r--r--spec/features/merge_requests/user_filters_by_target_branch_spec.rb10
-rw-r--r--spec/features/milestone_spec.rb4
-rw-r--r--spec/features/profile_spec.rb7
-rw-r--r--spec/features/profiles/account_spec.rb6
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb8
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb77
-rw-r--r--spec/features/project_group_variables_spec.rb9
-rw-r--r--spec/features/project_variables_spec.rb27
-rw-r--r--spec/features/projects/blobs/edit_spec.rb12
-rw-r--r--spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb2
-rw-r--r--spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb1
-rw-r--r--spec/features/projects/ci/editor_spec.rb21
-rw-r--r--spec/features/projects/ci/lint_spec.rb12
-rw-r--r--spec/features/projects/container_registry_spec.rb18
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb4
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb49
-rw-r--r--spec/features/projects/issues/design_management/user_uploads_designs_spec.rb2
-rw-r--r--spec/features/projects/jobs_spec.rb29
-rw-r--r--spec/features/projects/navbar_spec.rb19
-rw-r--r--spec/features/projects/pages_spec.rb2
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb5
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb1
-rw-r--r--spec/features/projects/releases/user_views_edit_release_spec.rb2
-rw-r--r--spec/features/projects/releases/user_views_releases_spec.rb102
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb12
-rw-r--r--spec/features/projects/settings/service_desk_setting_spec.rb2
-rw-r--r--spec/features/projects/settings/webhooks_settings_spec.rb1
-rw-r--r--spec/features/projects/show/schema_markup_spec.rb23
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb2
-rw-r--r--spec/features/projects/terraform_spec.rb48
-rw-r--r--spec/features/projects_spec.rb2
-rw-r--r--spec/features/read_only_spec.rb20
-rw-r--r--spec/features/runners_spec.rb13
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_issues_spec.rb25
-rw-r--r--spec/features/search/user_searches_for_merge_requests_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_milestones_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_wiki_pages_spec.rb5
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb56
-rw-r--r--spec/features/search/user_uses_search_filters_spec.rb21
-rw-r--r--spec/features/static_site_editor_spec.rb40
-rw-r--r--spec/features/uploads/user_uploads_file_to_note_spec.rb6
-rw-r--r--spec/features/users/login_spec.rb74
-rw-r--r--spec/features/users/show_spec.rb68
-rw-r--r--spec/features/users/signup_spec.rb117
110 files changed, 1994 insertions, 635 deletions
diff --git a/spec/features/admin/admin_builds_spec.rb b/spec/features/admin/admin_builds_spec.rb
index 85f0c44ed9c..166fde0f37a 100644
--- a/spec/features/admin/admin_builds_spec.rb
+++ b/spec/features/admin/admin_builds_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Admin Builds' do
context 'All tab' do
context 'when have jobs' do
- it 'shows all jobs' do
+ it 'shows all jobs', :js do
create(:ci_build, pipeline: pipeline, status: :pending)
create(:ci_build, pipeline: pipeline, status: :running)
create(:ci_build, pipeline: pipeline, status: :success)
@@ -24,6 +24,10 @@ RSpec.describe 'Admin Builds' do
expect(page).to have_selector('.row-content-block', text: 'All jobs')
expect(page.all('.build-link').size).to eq(4)
expect(page).to have_button 'Stop all jobs'
+
+ click_button 'Stop all jobs'
+ expect(page).to have_button 'Stop jobs'
+ expect(page).to have_content 'Stop all jobs?'
end
end
diff --git a/spec/features/admin/admin_dev_ops_report_spec.rb b/spec/features/admin/admin_dev_ops_report_spec.rb
index c201011cbea..3b2c9d75870 100644
--- a/spec/features/admin/admin_dev_ops_report_spec.rb
+++ b/spec/features/admin/admin_dev_ops_report_spec.rb
@@ -2,59 +2,65 @@
require 'spec_helper'
-RSpec.describe 'DevOps Report page' do
+RSpec.describe 'DevOps Report page', :js do
before do
sign_in(create(:admin))
end
- it 'has dismissable intro callout', :js do
- visit admin_dev_ops_report_path
+ context 'with devops_adoption feature flag disabled' do
+ before do
+ stub_feature_flags(devops_adoption: false)
+ end
- expect(page).to have_content 'Introducing Your DevOps Report'
+ it 'has dismissable intro callout' do
+ visit admin_dev_ops_report_path
- find('.js-close-callout').click
+ expect(page).to have_content 'Introducing Your DevOps Report'
- expect(page).not_to have_content 'Introducing Your DevOps Report'
- end
+ find('.js-close-callout').click
- context 'when usage ping is disabled' do
- before do
- stub_application_setting(usage_ping_enabled: false)
+ expect(page).not_to have_content 'Introducing Your DevOps Report'
end
- it 'shows empty state', :js do
- visit admin_dev_ops_report_path
+ context 'when usage ping is disabled' do
+ before do
+ stub_application_setting(usage_ping_enabled: false)
+ end
- expect(page).to have_selector(".js-empty-state")
- end
+ it 'shows empty state' do
+ visit admin_dev_ops_report_path
- it 'hides the intro callout' do
- visit admin_dev_ops_report_path
+ expect(page).to have_selector(".js-empty-state")
+ end
- expect(page).not_to have_content 'Introducing Your DevOps Report'
+ it 'hides the intro callout' do
+ visit admin_dev_ops_report_path
+
+ expect(page).not_to have_content 'Introducing Your DevOps Report'
+ end
end
- end
- context 'when there is no data to display' do
- it 'shows empty state' do
- stub_application_setting(usage_ping_enabled: true)
+ context 'when there is no data to display' do
+ it 'shows empty state' do
+ stub_application_setting(usage_ping_enabled: true)
- visit admin_dev_ops_report_path
+ visit admin_dev_ops_report_path
- expect(page).to have_content('Data is still calculating')
+ expect(page).to have_content('Data is still calculating')
+ end
end
- end
- context 'when there is data to display' do
- it 'shows numbers for each metric' do
- stub_application_setting(usage_ping_enabled: true)
- create(:dev_ops_report_metric)
+ context 'when there is data to display' do
+ it 'shows numbers for each metric' do
+ stub_application_setting(usage_ping_enabled: true)
+ create(:dev_ops_report_metric)
- visit admin_dev_ops_report_path
+ visit admin_dev_ops_report_path
- expect(page).to have_content(
- 'Issues created per active user 1.2 You 9.3 Lead 13.3%'
- )
+ expect(page).to have_content(
+ 'Issues created per active user 1.2 You 9.3 Lead 13.3%'
+ )
+ end
end
end
end
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index 653a45a4bb8..96709cf8a12 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Admin Groups' do
include Select2Helper
+ include Spec::Support::Helpers::Features::MembersHelpers
let(:internal) { Gitlab::VisibilityLevel::INTERNAL }
let(:user) { create :user }
@@ -11,8 +12,6 @@ RSpec.describe 'Admin Groups' do
let!(:current_user) { create(:admin) }
before do
- stub_feature_flags(vue_group_members_list: false)
-
sign_in(current_user)
stub_application_setting(default_group_visibility: internal)
end
@@ -176,7 +175,7 @@ RSpec.describe 'Admin Groups' do
click_button 'Invite'
- page.within '[data-qa-selector="members_list"]' do
+ page.within members_table do
expect(page).to have_content(current_user.name)
expect(page).to have_content('Developer')
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 528dfad606e..8929abc7edc 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -132,32 +132,14 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n
context 'Change Sign-up restrictions' do
context 'Require Admin approval for new signup setting' do
- context 'when feature is enabled' do
- before do
- stub_feature_flags(admin_approval_for_new_user_signups: true)
- end
-
- it 'changes the setting' do
- page.within('.as-signup') do
- check 'Require admin approval for new sign-ups'
- click_button 'Save changes'
- end
-
- expect(current_settings.require_admin_approval_after_user_signup).to be_truthy
- expect(page).to have_content "Application settings saved successfully"
- end
- end
-
- context 'when feature is disabled' do
- before do
- stub_feature_flags(admin_approval_for_new_user_signups: false)
+ it 'changes the setting' do
+ page.within('.as-signup') do
+ check 'Require admin approval for new sign-ups'
+ click_button 'Save changes'
end
- it 'does not show the the setting' do
- page.within('.as-signup') do
- expect(page).not_to have_selector('.application_setting_require_admin_approval_after_user_signup')
- end
- end
+ expect(current_settings.require_admin_approval_after_user_signup).to be_truthy
+ expect(page).to have_content "Application settings saved successfully"
end
end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index e06e2d14f3c..97a30143a59 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -75,26 +75,12 @@ RSpec.describe "Admin::Users" do
end
context '`Pending approval` tab' do
- context 'feature is enabled' do
- before do
- stub_feature_flags(admin_approval_for_new_user_signups: true)
- visit admin_users_path
- end
-
- it 'shows the `Pending approval` tab' do
- expect(page).to have_link('Pending approval', href: admin_users_path(filter: 'blocked_pending_approval'))
- end
+ before do
+ visit admin_users_path
end
- context 'feature is disabled' do
- before do
- stub_feature_flags(admin_approval_for_new_user_signups: false)
- visit admin_users_path
- end
-
- it 'does not show the `Pending approval` tab' do
- expect(page).not_to have_link('Pending approval', href: admin_users_path(filter: 'blocked_pending_approval'))
- end
+ it 'shows the `Pending approval` tab' do
+ expect(page).to have_link('Pending approval', href: admin_users_path(filter: 'blocked_pending_approval'))
end
end
end
@@ -218,6 +204,32 @@ RSpec.describe "Admin::Users" do
expect(page).to have_content(user.email)
end
end
+
+ context 'when blocking a user' do
+ it 'shows confirmation and allows blocking', :js do
+ expect(page).to have_content(user.email)
+
+ find("[data-testid='user-action-button-#{user.id}']").click
+
+ within find("[data-testid='user-action-dropdown-#{user.id}']") do
+ find('li button', text: 'Block').click
+ end
+
+ wait_for_requests
+
+ expect(page).to have_content('Block user')
+ expect(page).to have_content('Blocking user has the following effects')
+ expect(page).to have_content('User will not be able to login')
+ expect(page).to have_content('Owned groups will be left')
+
+ find('.modal-footer button', text: 'Block').click
+
+ wait_for_requests
+
+ expect(page).to have_content('Successfully blocked')
+ expect(page).not_to have_content(user.email)
+ end
+ end
end
describe "GET /admin/users/new" do
@@ -376,6 +388,26 @@ RSpec.describe "Admin::Users" do
end
end
+ context 'when blocking the user' do
+ it 'shows confirmation and allows blocking', :js do
+ visit admin_user_path(user)
+
+ find('button', text: 'Block user').click
+
+ wait_for_requests
+
+ expect(page).to have_content('Block user')
+ expect(page).to have_content('You can always unblock their account, their data will remain intact.')
+
+ find('.modal-footer button', text: 'Block').click
+
+ wait_for_requests
+
+ expect(page).to have_content('Successfully blocked')
+ expect(page).to have_content('This user is blocked')
+ end
+ end
+
describe 'Impersonation' do
let(:another_user) { create(:user) }
diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb
index 44642983a36..0fb5124f673 100644
--- a/spec/features/admin/admin_uses_repository_checks_spec.rb
+++ b/spec/features/admin/admin_uses_repository_checks_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe 'Admin uses repository checks', :request_store, :clean_gitlab_red
)
visit_admin_project_page(project)
- page.within('.gl-alert') do
+ page.within('[data-testid="last-repository-check-failed-alert"]') do
expect(page.text).to match(/Last repository check \(just now\) failed/)
end
end
diff --git a/spec/features/alert_management_spec.rb b/spec/features/alert_management_spec.rb
index 2989f72e356..3322c9c574f 100644
--- a/spec/features/alert_management_spec.rb
+++ b/spec/features/alert_management_spec.rb
@@ -41,21 +41,6 @@ RSpec.describe 'Alert management', :js do
expect(page).to have_content(environment.name)
end
end
-
- context 'when expose_environment_path_in_alert_details feature flag is disabled' do
- before do
- stub_feature_flags(expose_environment_path_in_alert_details: false)
- end
-
- it 'does not show the environment name' do
- visit(details_project_alert_management_path(project, alert))
-
- within('.alert-management-details-table') do
- expect(page).to have_content(alert.title)
- expect(page).not_to have_content(environment.name)
- end
- end
- end
end
end
end
diff --git a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
new file mode 100644
index 00000000000..0ded13ae607
--- /dev/null
+++ b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Alert integrations settings form', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+
+ before_all do
+ project.add_maintainer(maintainer)
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(maintainer)
+ end
+
+ describe 'when viewing alert integrations as a maintainer' do
+ context 'with feature flag enabled' do
+ before do
+ visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
+ wait_for_requests
+ end
+
+ it 'shows the alerts setting form title' do
+ page.within('#js-alert-management-settings') do
+ expect(find('h3')).to have_content('Alerts')
+ end
+ end
+
+ it 'shows the new alerts setting form' do
+ expect(page).to have_content('1. Select integration type')
+ end
+ end
+
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(http_integrations_list: false)
+
+ visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
+ wait_for_requests
+ end
+
+ it 'shows the old alerts setting form' do
+ expect(page).to have_content('Webhook URL')
+ end
+ end
+ end
+
+ describe 'when viewing alert integrations as a developer' do
+ before do
+ sign_in(developer)
+
+ visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
+ wait_for_requests
+ end
+
+ it 'shows the old alerts setting form' do
+ expect(page).not_to have_selector('.incident-management-list')
+ expect(page).not_to have_selector('#js-alert-management-settings')
+ end
+ end
+end
diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb
index 00efca5d3a8..f941adca233 100644
--- a/spec/features/boards/add_issues_modal_spec.rb
+++ b/spec/features/boards/add_issues_modal_spec.rb
@@ -87,11 +87,12 @@ RSpec.describe 'Issue Boards add issue modal', :js do
end
end
- it 'shows selected issues' do
+ it 'shows selected issues tab and empty state message' do
page.within('.add-issues-modal') do
click_link 'Selected issues'
expect(page).not_to have_selector('.board-card')
+ expect(page).to have_content("Go back to Open issues and select some issues to add to your board.")
end
end
@@ -147,7 +148,7 @@ RSpec.describe 'Issue Boards add issue modal', :js do
end
end
- context 'selecing issues' do
+ context 'selecting issues' do
it 'selects single issue' do
page.within('.add-issues-modal') do
first('.board-card .board-card-number').click
@@ -206,7 +207,7 @@ RSpec.describe 'Issue Boards add issue modal', :js do
end
end
- it 'selects all that arent already selected' do
+ it "selects all that aren't already selected" do
page.within('.add-issues-modal') do
first('.board-card .board-card-number').click
diff --git a/spec/features/breadcrumbs_schema_markup_spec.rb b/spec/features/breadcrumbs_schema_markup_spec.rb
new file mode 100644
index 00000000000..30d5f40fea8
--- /dev/null
+++ b/spec/features/breadcrumbs_schema_markup_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public, namespace: user.namespace) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:subgroup) { create(:group, :public, parent: group) }
+ let_it_be(:group_project) { create(:project, :public, namespace: subgroup) }
+
+ it 'generates the breadcrumb schema for user projects' do
+ visit project_url(project)
+
+ item_list = get_schema_content
+
+ expect(item_list.size).to eq 3
+ expect(item_list[0]['name']).to eq project.namespace.name
+ expect(item_list[0]['item']).to eq user_url(project.owner)
+
+ expect(item_list[1]['name']).to eq project.name
+ expect(item_list[1]['item']).to eq project_url(project)
+
+ expect(item_list[2]['name']).to eq 'Details'
+ expect(item_list[2]['item']).to eq project_url(project)
+ end
+
+ it 'generates the breadcrumb schema for group projects' do
+ visit project_url(group_project)
+
+ item_list = get_schema_content
+
+ expect(item_list.size).to eq 4
+ expect(item_list[0]['name']).to eq group.name
+ expect(item_list[0]['item']).to eq group_url(group)
+
+ expect(item_list[1]['name']).to eq subgroup.name
+ expect(item_list[1]['item']).to eq group_url(subgroup)
+
+ expect(item_list[2]['name']).to eq group_project.name
+ expect(item_list[2]['item']).to eq project_url(group_project)
+
+ expect(item_list[3]['name']).to eq 'Details'
+ expect(item_list[3]['item']).to eq project_url(group_project)
+ end
+
+ it 'generates the breadcrumb schema for group' do
+ visit group_url(subgroup)
+
+ item_list = get_schema_content
+
+ expect(item_list.size).to eq 3
+ expect(item_list[0]['name']).to eq group.name
+ expect(item_list[0]['item']).to eq group_url(group)
+
+ expect(item_list[1]['name']).to eq subgroup.name
+ expect(item_list[1]['item']).to eq group_url(subgroup)
+
+ expect(item_list[2]['name']).to eq 'Details'
+ expect(item_list[2]['item']).to eq group_url(subgroup)
+ end
+
+ it 'generates the breadcrumb schema for issues' do
+ visit project_issues_url(project)
+
+ item_list = get_schema_content
+
+ expect(item_list.size).to eq 3
+ expect(item_list[0]['name']).to eq project.namespace.name
+ expect(item_list[0]['item']).to eq user_url(project.owner)
+
+ expect(item_list[1]['name']).to eq project.name
+ expect(item_list[1]['item']).to eq project_url(project)
+
+ expect(item_list[2]['name']).to eq 'Issues'
+ expect(item_list[2]['item']).to eq project_issues_url(project)
+ end
+
+ it 'generates the breadcrumb schema for specific issue' do
+ visit project_issue_url(project, issue)
+
+ item_list = get_schema_content
+
+ expect(item_list.size).to eq 4
+ expect(item_list[0]['name']).to eq project.namespace.name
+ expect(item_list[0]['item']).to eq user_url(project.owner)
+
+ expect(item_list[1]['name']).to eq project.name
+ expect(item_list[1]['item']).to eq project_url(project)
+
+ expect(item_list[2]['name']).to eq 'Issues'
+ expect(item_list[2]['item']).to eq project_issues_url(project)
+
+ expect(item_list[3]['name']).to eq issue.to_reference
+ expect(item_list[3]['item']).to eq project_issue_url(project, issue)
+ end
+
+ def get_schema_content
+ content = find('script[type="application/ld+json"]', visible: false).text(:all)
+
+ expect(content).not_to be_nil
+
+ Gitlab::Json.parse(content)['itemListElement']
+ end
+end
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index 5f58fa420fb..60d485d4558 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe 'Contributions Calendar', :js do
"#{contributions} #{'contribution'.pluralize(contributions)}"
end
- "#{get_cell_color_selector(contributions)}[data-original-title='#{contribution_text}<br />#{date}']"
+ "#{get_cell_color_selector(contributions)}[title='#{contribution_text}<br />#{date}']"
end
def push_code_contribution
diff --git a/spec/features/callouts/registration_enabled_spec.rb b/spec/features/callouts/registration_enabled_spec.rb
new file mode 100644
index 00000000000..4055965273f
--- /dev/null
+++ b/spec/features/callouts/registration_enabled_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Registration enabled callout' do
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:non_admin) { create(:user) }
+
+ context 'when "Sign-up enabled" setting is `true`' do
+ before do
+ stub_application_setting(signup_enabled: true)
+ end
+
+ context 'when an admin is logged in' do
+ before do
+ sign_in(admin)
+ visit root_dashboard_path
+ end
+
+ it 'displays callout' do
+ expect(page).to have_content 'Open registration is enabled on your instance.'
+ expect(page).to have_link 'View setting', href: general_admin_application_settings_path(anchor: 'js-signup-settings')
+ end
+
+ context 'when callout is dismissed', :js do
+ before do
+ find('[data-testid="close-registration-enabled-callout"]').click
+
+ visit root_dashboard_path
+ end
+
+ it 'does not display callout' do
+ expect(page).not_to have_content 'Open registration is enabled on your instance.'
+ end
+ end
+ end
+
+ context 'when a non-admin is logged in' do
+ before do
+ sign_in(non_admin)
+ visit root_dashboard_path
+ end
+
+ it 'does not display callout' do
+ expect(page).not_to have_content 'Open registration is enabled on your instance.'
+ end
+ end
+ end
+end
diff --git a/spec/features/canonical_link_spec.rb b/spec/features/canonical_link_spec.rb
new file mode 100644
index 00000000000..8b64e9a5b9d
--- /dev/null
+++ b/spec/features/canonical_link_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Canonical link' do
+ include Spec::Support::Helpers::Features::CanonicalLinkHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public, namespace: user.namespace) }
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ let_it_be(:issue_request) { issue_url(issue) }
+ let_it_be(:project_request) { project_url(project) }
+
+ before do
+ sign_in(user)
+ end
+
+ shared_examples 'shows canonical link' do
+ specify do
+ visit request_url
+
+ expect(page).to have_canonical_link(expected_url)
+ end
+ end
+
+ shared_examples 'does not show canonical link' do
+ specify do
+ visit request_url
+
+ expect(page).not_to have_any_canonical_links
+ end
+ end
+
+ it_behaves_like 'does not show canonical link' do
+ let(:request_url) { issue_request }
+ end
+
+ it_behaves_like 'shows canonical link' do
+ let(:request_url) { issue_request + '/' }
+ let(:expected_url) { issue_request }
+ end
+
+ it_behaves_like 'shows canonical link' do
+ let(:request_url) { project_issues_url(project) + "/?state=opened" }
+ let(:expected_url) { project_issues_url(project, state: 'opened') }
+ end
+
+ it_behaves_like 'does not show canonical link' do
+ let(:request_url) { project_request }
+ end
+
+ it_behaves_like 'shows canonical link' do
+ let(:request_url) { project_request + '/' }
+ let(:expected_url) { project_request }
+ end
+
+ it_behaves_like 'shows canonical link' do
+ let(:query_params) { '?foo=bar' }
+ let(:request_url) { project_request + "/#{query_params}" }
+ let(:expected_url) { project_request + query_params }
+ end
+
+ # Hard-coded canonical links
+
+ it_behaves_like 'shows canonical link' do
+ let(:request_url) { explore_root_path }
+ let(:expected_url) { explore_projects_url }
+ end
+end
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
index a3eacd6147c..c14a6001a3e 100644
--- a/spec/features/dashboard/datetime_on_tooltips_spec.rb
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe 'Tooltips on .timeago dates', :js do
end
def datetime_in_tooltip
- datetime_text = page.find('.local-timeago').text
+ datetime_text = page.find('.tooltip').text
DateTime.parse(datetime_text)
end
end
diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb
index 04bbc3059de..58352518d43 100644
--- a/spec/features/dashboard/shortcuts_spec.rb
+++ b/spec/features/dashboard/shortcuts_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe 'Dashboard shortcuts', :js do
find('body').send_keys([:shift, 'P'])
find('.nothing-here-block')
- expect(page).to have_content("This user doesn't have any personal projects")
+ expect(page).to have_content('Explore public groups to find projects to contribute to.')
end
end
diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb
index 43801b30608..761cc7ae796 100644
--- a/spec/features/discussion_comments/merge_request_spec.rb
+++ b/spec/features/discussion_comments/merge_request_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'Thread Comments Merge Request', :js do
let(:merge_request) { create(:merge_request, source_project: project) }
before do
+ stub_feature_flags(remove_resolve_note: false)
+
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 49343cc7a57..0912df22924 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'Expand and collapse diffs', :js do
before do
stub_feature_flags(increased_diff_limits: false)
+ allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.kilobytes)
+
sign_in(create(:admin))
# Ensure that undiffable.md is in .gitattributes
diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb
index e217638f62b..bf4d6c946e1 100644
--- a/spec/features/explore/user_explores_projects_spec.rb
+++ b/spec/features/explore/user_explores_projects_spec.rb
@@ -3,65 +3,112 @@
require 'spec_helper'
RSpec.describe 'User explores projects' do
- let_it_be(:archived_project) { create(:project, :archived) }
- let_it_be(:internal_project) { create(:project, :internal) }
- let_it_be(:private_project) { create(:project, :private) }
- let_it_be(:public_project) { create(:project, :public) }
-
- context 'when not signed in' do
- context 'when viewing public projects' do
- before do
- visit(explore_projects_path)
+ context 'when some projects exist' do
+ let_it_be(:archived_project) { create(:project, :archived) }
+ let_it_be(:internal_project) { create(:project, :internal) }
+ let_it_be(:private_project) { create(:project, :private) }
+ let_it_be(:public_project) { create(:project, :public) }
+
+ context 'when not signed in' do
+ context 'when viewing public projects' do
+ before do
+ visit(explore_projects_path)
+ end
+
+ include_examples 'shows public projects'
end
- include_examples 'shows public projects'
+ context 'when visibility is restricted to public' do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ visit(explore_projects_path)
+ end
+
+ it 'redirects to login page' do
+ expect(page).to have_current_path(new_user_session_path)
+ end
+ end
end
- context 'when visibility is restricted to public' do
+ context 'when signed in' do
+ let_it_be(:user) { create(:user) }
+
before do
- stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
- visit(explore_projects_path)
+ sign_in(user)
+
+ stub_feature_flags(project_list_filter_bar: false)
+ end
+
+ shared_examples 'empty search results' do
+ it 'shows correct empty state message', :js do
+ fill_in 'name', with: 'zzzzzzzzzzzzzzzzzzz'
+
+ expect(page).to have_content('Explore public groups to find projects to contribute to.')
+ end
end
- it 'redirects to login page' do
- expect(page).to have_current_path(new_user_session_path)
+ context 'when viewing public projects' do
+ before do
+ visit(explore_projects_path)
+ end
+
+ include_examples 'shows public and internal projects'
+ include_examples 'empty search results'
+ end
+
+ context 'when viewing most starred projects' do
+ before do
+ visit(starred_explore_projects_path)
+ end
+
+ include_examples 'shows public and internal projects'
+ include_examples 'empty search results'
+ end
+
+ context 'when viewing trending projects' do
+ before do
+ [archived_project, public_project].each { |project| create(:note_on_issue, project: project) }
+
+ TrendingProject.refresh!
+
+ visit(trending_explore_projects_path)
+ end
+
+ include_examples 'shows public projects'
+ include_examples 'empty search results'
end
end
end
- context 'when signed in' do
- let_it_be(:user) { create(:user) }
-
- before do
- sign_in(user)
+ context 'when there are no projects' do
+ shared_examples 'explore page empty state' do
+ it 'shows correct empty state message' do
+ expect(page).to have_content('Explore public groups to find projects to contribute to.')
+ end
end
context 'when viewing public projects' do
before do
- visit(explore_projects_path)
+ visit explore_projects_path
end
- include_examples 'shows public and internal projects'
+ it_behaves_like 'explore page empty state'
end
context 'when viewing most starred projects' do
before do
- visit(starred_explore_projects_path)
+ visit starred_explore_projects_path
end
- include_examples 'shows public and internal projects'
+ it_behaves_like 'explore page empty state'
end
context 'when viewing trending projects' do
before do
- [archived_project, public_project].each { |project| create(:note_on_issue, project: project) }
-
- TrendingProject.refresh!
-
- visit(trending_explore_projects_path)
+ visit trending_explore_projects_path
end
- include_examples 'shows public projects'
+ it_behaves_like 'explore page empty state'
end
end
end
diff --git a/spec/features/file_uploads/multipart_invalid_uploads_spec.rb b/spec/features/file_uploads/multipart_invalid_uploads_spec.rb
index e9e24c12af1..b3ace2e30ff 100644
--- a/spec/features/file_uploads/multipart_invalid_uploads_spec.rb
+++ b/spec/features/file_uploads/multipart_invalid_uploads_spec.rb
@@ -22,13 +22,13 @@ RSpec.describe 'Invalid uploads that must be rejected', :api, :js do
)
end
- RSpec.shared_examples 'rejecting invalid keys' do |key_name:, message: nil|
+ RSpec.shared_examples 'rejecting invalid keys' do |key_name:, message: nil, status: 500|
context "with invalid key #{key_name}" do
let(:body) { { key_name => file, 'package[test][name]' => 'test' } }
it { expect { subject }.not_to change { Packages::Package.nuget.count } }
- it { expect(subject.code).to eq(500) }
+ it { expect(subject.code).to eq(status) }
it { expect(subject.body).to include(message.presence || "invalid field: \"#{key_name}\"") }
end
@@ -45,7 +45,7 @@ RSpec.describe 'Invalid uploads that must be rejected', :api, :js do
# These keys are rejected directly by rack itself.
# The request will not be received by multipart.rb (can't use the 'handling file uploads' shared example)
it_behaves_like 'rejecting invalid keys', key_name: 'x' * 11000, message: 'Puma caught this error: exceeded available parameter key space (RangeError)'
- it_behaves_like 'rejecting invalid keys', key_name: 'package[]test', message: 'Puma caught this error: expected Hash (got Array)'
+ it_behaves_like 'rejecting invalid keys', key_name: 'package[]test', status: 400, message: 'Bad Request'
it_behaves_like 'handling file uploads', 'by rejecting uploads with an invalid key'
end
diff --git a/spec/features/frequently_visited_projects_and_groups_spec.rb b/spec/features/frequently_visited_projects_and_groups_spec.rb
new file mode 100644
index 00000000000..b8797d9c139
--- /dev/null
+++ b/spec/features/frequently_visited_projects_and_groups_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Frequently visited items', :js do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'for projects' do
+ let_it_be(:project) { create(:project, :public) }
+
+ it 'increments localStorage counter when visiting the project' do
+ visit project_path(project)
+
+ frequent_projects = nil
+
+ wait_for('localStorage frequent-projects') do
+ frequent_projects = page.evaluate_script("localStorage['#{user.username}/frequent-projects']")
+
+ frequent_projects.present?
+ end
+
+ expect(Gitlab::Json.parse(frequent_projects)).to contain_exactly(a_hash_including('id' => project.id, 'frequency' => 1))
+ end
+ end
+
+ context 'for groups' do
+ let_it_be(:group) { create(:group, :public) }
+
+ it 'increments localStorage counter when visiting the group' do
+ visit group_path(group)
+
+ frequent_groups = nil
+
+ wait_for('localStorage frequent-groups') do
+ frequent_groups = page.evaluate_script("localStorage['#{user.username}/frequent-groups']")
+
+ frequent_groups.present?
+ end
+
+ expect(Gitlab::Json.parse(frequent_groups)).to contain_exactly(a_hash_including('id' => group.id, 'frequency' => 1))
+ end
+ end
+end
diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb
index 0ca626381d4..e6e4a55c1bb 100644
--- a/spec/features/global_search_spec.rb
+++ b/spec/features/global_search_spec.rb
@@ -36,15 +36,15 @@ RSpec.describe 'Global search' do
end
end
- it 'closes the dropdown on blur', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/201841' do
+ it 'closes the dropdown on blur', :js do
+ find('#search').click
fill_in 'search', with: "a"
- dropdown = find('.js-dashboard-search-options')
- expect(dropdown[:class]).to include 'show'
+ expect(page).to have_selector("div[data-testid='dashboard-search-options'].show")
find('#search').send_keys(:backspace)
find('body').click
- expect(dropdown[:class]).not_to include 'show'
+ expect(page).to have_no_selector("div[data-testid='dashboard-search-options'].show")
end
end
diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb
index 9a3dca61680..c7d37205b71 100644
--- a/spec/features/group_variables_spec.rb
+++ b/spec/features/group_variables_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Group variables', :js do
before do
group.add_owner(user)
gitlab_sign_in(user)
- stub_feature_flags(new_variables_ui: false)
+ wait_for_requests
visit page_path
end
diff --git a/spec/features/groups/container_registry_spec.rb b/spec/features/groups/container_registry_spec.rb
index acac8724edf..1b23b8b4bf9 100644
--- a/spec/features/groups/container_registry_spec.rb
+++ b/spec/features/groups/container_registry_spec.rb
@@ -89,6 +89,20 @@ RSpec.describe 'Container Registry', :js do
end
end
+ context 'when an image has the same name as the subgroup' do
+ before do
+ stub_container_registry_tags(tags: %w[latest], with_manifest: true)
+ project.container_repositories << create(:container_repository, name: group.name)
+ visit_container_registry
+ end
+
+ it 'details page loads properly' do
+ find('a[data-testid="details-link"]').click
+
+ expect(page).to have_content 'latest'
+ end
+ end
+
def visit_container_registry
visit group_container_registries_path(group)
end
diff --git a/spec/features/groups/dependency_proxy_spec.rb b/spec/features/groups/dependency_proxy_spec.rb
new file mode 100644
index 00000000000..9bbfdc488fb
--- /dev/null
+++ b/spec/features/groups/dependency_proxy_spec.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Group Dependency Proxy' do
+ let(:developer) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:group) { create(:group) }
+ let(:path) { group_dependency_proxy_path(group) }
+
+ before do
+ group.add_developer(developer)
+ group.add_reporter(reporter)
+
+ enable_feature
+ end
+
+ describe 'feature settings' do
+ context 'when not logged in and feature disabled' do
+ it 'does not show the feature settings' do
+ group.create_dependency_proxy_setting(enabled: false)
+
+ visit path
+
+ expect(page).not_to have_css('.js-dependency-proxy-toggle-area')
+ expect(page).not_to have_css('.js-dependency-proxy-url')
+ end
+ end
+
+ context 'feature is available', :js do
+ context 'when logged in as group developer' do
+ before do
+ sign_in(developer)
+ visit path
+ end
+
+ it 'sidebar menu is open' do
+ sidebar = find('.nav-sidebar')
+ expect(sidebar).to have_link _('Dependency Proxy')
+ end
+
+ it 'toggles defaults to enabled' do
+ page.within('.js-dependency-proxy-toggle-area') do
+ expect(find('.js-project-feature-toggle-input', visible: false).value).to eq('true')
+ end
+ end
+
+ it 'shows the proxy URL' do
+ page.within('.edit_dependency_proxy_group_setting') do
+ expect(find('.js-dependency-proxy-url').value).to have_content('/dependency_proxy/containers')
+ end
+ end
+
+ it 'hides the proxy URL when feature is disabled' do
+ page.within('.edit_dependency_proxy_group_setting') do
+ find('.js-project-feature-toggle').click
+ end
+
+ expect(page).not_to have_css('.js-dependency-proxy-url')
+ expect(find('.js-project-feature-toggle-input', visible: false).value).to eq('false')
+ end
+ end
+
+ context 'when logged in as group reporter' do
+ before do
+ sign_in(reporter)
+ visit path
+ end
+
+ it 'does not show the feature toggle but shows the proxy URL' do
+ expect(page).not_to have_css('.js-dependency-proxy-toggle-area')
+ expect(find('.js-dependency-proxy-url').value).to have_content('/dependency_proxy/containers')
+ end
+ end
+ end
+
+ context 'feature is not avaible' do
+ before do
+ sign_in(developer)
+ end
+
+ context 'group is private' do
+ let(:group) { create(:group, :private) }
+
+ it 'informs user that feature is only available for public groups' do
+ visit path
+
+ expect(page).to have_content('Dependency proxy feature is limited to public groups for now.')
+ end
+ end
+
+ context 'feature is disabled globally' do
+ it 'renders 404 page' do
+ disable_feature
+
+ visit path
+
+ expect(page).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
+ def enable_feature
+ stub_config(dependency_proxy: { enabled: true })
+ end
+
+ def disable_feature
+ stub_config(dependency_proxy: { enabled: false })
+ end
+end
diff --git a/spec/features/groups/members/filter_members_spec.rb b/spec/features/groups/members/filter_members_spec.rb
index d667690af29..b6d33b3f4aa 100644
--- a/spec/features/groups/members/filter_members_spec.rb
+++ b/spec/features/groups/members/filter_members_spec.rb
@@ -2,16 +2,19 @@
require 'spec_helper'
-RSpec.describe 'Groups > Members > Filter members' do
+RSpec.describe 'Groups > Members > Filter members', :js do
+ include Spec::Support::Helpers::Features::MembersHelpers
+
let(:user) { create(:user) }
let(:nested_group_user) { create(:user) }
let(:user_with_2fa) { create(:user, :two_factor_via_otp) }
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
- before do
- stub_feature_flags(vue_group_members_list: false)
+ two_factor_auth_dropdown_toggle_selector = '[data-testid="member-filter-2fa-dropdown"] [data-testid="dropdown-toggle"]'
+ active_inherited_members_filter_selector = '[data-testid="filter-members-with-inherited-permissions"] a.is-active'
+ before do
group.add_owner(user)
group.add_maintainer(user_with_2fa)
nested_group.add_maintainer(nested_group_user)
@@ -24,23 +27,23 @@ RSpec.describe 'Groups > Members > Filter members' do
expect(member(0)).to include(user.name)
expect(member(1)).to include(user_with_2fa.name)
- expect(page).to have_css('.member-filter-2fa-dropdown .dropdown-toggle-text', text: 'Everyone')
+ expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Everyone')
end
it 'shows only 2FA members' do
visit_members_list(group, two_factor: 'enabled')
expect(member(0)).to include(user_with_2fa.name)
- expect(members_list.size).to eq(1)
- expect(page).to have_css('.member-filter-2fa-dropdown .dropdown-toggle-text', text: 'Enabled')
+ expect(all_rows.size).to eq(1)
+ expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Enabled')
end
it 'shows only non 2FA members' do
visit_members_list(group, two_factor: 'disabled')
expect(member(0)).to include(user.name)
- expect(members_list.size).to eq(1)
- expect(page).to have_css('.member-filter-2fa-dropdown .dropdown-toggle-text', text: 'Disabled')
+ expect(all_rows.size).to eq(1)
+ expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Disabled')
end
it 'shows inherited members by default' do
@@ -49,35 +52,31 @@ RSpec.describe 'Groups > Members > Filter members' do
expect(member(0)).to include(user.name)
expect(member(1)).to include(user_with_2fa.name)
expect(member(2)).to include(nested_group_user.name)
- expect(members_list.size).to eq(3)
+ expect(all_rows.size).to eq(3)
- expect(page).to have_css('[data-qa-selector="filter-members-with-inherited-permissions"] a.is-active', text: 'Show all members')
+ expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show all members', visible: false)
end
it 'shows only group members' do
visit_members_list(nested_group, with_inherited_permissions: 'exclude')
expect(member(0)).to include(nested_group_user.name)
- expect(members_list.size).to eq(1)
- expect(page).to have_css('[data-qa-selector="filter-members-with-inherited-permissions"] a.is-active', text: 'Show only direct members')
+ expect(all_rows.size).to eq(1)
+ expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show only direct members', visible: false)
end
it 'shows only inherited members' do
visit_members_list(nested_group, with_inherited_permissions: 'only')
expect(member(0)).to include(user.name)
expect(member(1)).to include(user_with_2fa.name)
- expect(members_list.size).to eq(2)
- expect(page).to have_css('[data-qa-selector="filter-members-with-inherited-permissions"] a.is-active', text: 'Show only inherited members')
+ expect(all_rows.size).to eq(2)
+ expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show only inherited members', visible: false)
end
def visit_members_list(group, options = {})
visit group_group_members_path(group.to_param, options)
end
- def members_list
- page.all('ul.content-list > li')
- end
-
def member(number)
- members_list[number].text
+ all_rows[number].text
end
end
diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb
index 32acf7edd2a..b73313745e9 100644
--- a/spec/features/groups/members/leave_group_spec.rb
+++ b/spec/features/groups/members/leave_group_spec.rb
@@ -3,14 +3,14 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Leave group' do
+ include Spec::Support::Helpers::Features::MembersHelpers
+
let(:user) { create(:user) }
let(:other_user) { create(:user) }
let(:group) { create(:group) }
before do
- stub_feature_flags(vue_group_members_list: false)
-
- gitlab_sign_in(user)
+ sign_in(user)
end
it 'guest leaves the group' do
@@ -61,7 +61,7 @@ RSpec.describe 'Groups > Members > Leave group' do
expect(group.users).not_to include(user)
end
- it 'owner can not leave the group if they are the last owner' do
+ it 'owner can not leave the group if they are the last owner', :js do
group.add_owner(user)
visit group_path(group)
@@ -70,7 +70,7 @@ RSpec.describe 'Groups > Members > Leave group' do
visit group_group_members_path(group)
- expect(find(:css, '.project-members-page li', text: user.name)).to have_no_selector(:css, 'a.btn-danger')
+ expect(members_table).not_to have_selector 'button[title="Leave"]'
end
it 'owner can not leave the group by url param if they are the last owner', :js do
diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb
index bcec2b50a24..b0a896ec8cb 100644
--- a/spec/features/groups/members/list_members_spec.rb
+++ b/spec/features/groups/members/list_members_spec.rb
@@ -2,9 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Groups > Members > List members' do
- include Select2Helper
- include Spec::Support::Helpers::Features::ListRowsHelpers
+RSpec.describe 'Groups > Members > List members', :js do
+ include Spec::Support::Helpers::Features::MembersHelpers
let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') }
@@ -12,8 +11,6 @@ RSpec.describe 'Groups > Members > List members' do
let(:nested_group) { create(:group, parent: group) }
before do
- stub_feature_flags(vue_group_members_list: false)
-
sign_in(user1)
end
@@ -42,10 +39,12 @@ RSpec.describe 'Groups > Members > List members' do
group.add_developer(user2)
end
- subject { visit group_group_members_path(group) }
+ it 'shows the status' do
+ create(:user_status, user: user2, emoji: 'smirk', message: 'Authoring this object')
+
+ visit group_group_members_path(nested_group)
- it_behaves_like 'showing user status' do
- let(:user_with_status) { user2 }
+ expect(first_row).to have_selector('gl-emoji[data-name="smirk"]')
end
end
end
diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb
index 33caa3af36d..31a2c868cac 100644
--- a/spec/features/groups/members/manage_groups_spec.rb
+++ b/spec/features/groups/members/manage_groups_spec.rb
@@ -4,13 +4,11 @@ require 'spec_helper'
RSpec.describe 'Groups > Members > Manage groups', :js do
include Select2Helper
- include Spec::Support::Helpers::Features::ListRowsHelpers
+ include Spec::Support::Helpers::Features::MembersHelpers
let_it_be(:user) { create(:user) }
before do
- stub_feature_flags(vue_group_members_list: false)
-
sign_in(user)
end
@@ -51,7 +49,6 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
end
before do
- travel_to Time.now.utc.beginning_of_day
group_link.update!(additional_link_attrs)
shared_group.add_owner(user)
@@ -63,8 +60,12 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
expect(page).to have_content(shared_with_group.name)
- accept_confirm do
- find(:css, '#tab-groups li', text: shared_with_group.name).find(:css, 'a.btn-danger').click
+ page.within(first_row) do
+ click_button 'Remove group'
+ end
+
+ page.within('[role="dialog"]') do
+ click_button('Remove group')
end
expect(page).not_to have_content(shared_with_group.name)
@@ -75,7 +76,7 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
page.within(first_row) do
click_button('Developer')
- click_link('Maintainer')
+ click_button('Maintainer')
wait_for_requests
@@ -86,33 +87,30 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
it 'updates expiry date' do
click_groups_tab
- expires_at_field = "member_expires_at_#{shared_with_group.id}"
- fill_in "member_expires_at_#{shared_with_group.id}", with: 3.days.from_now.to_date
+ page.within first_row do
+ fill_in 'Expiration date', with: 5.days.from_now.to_date
+ find_field('Expiration date').native.send_keys :enter
- find_field(expires_at_field).native.send_keys :enter
- wait_for_requests
+ wait_for_requests
- page.within(find('li.group_member')) do
- expect(page).to have_content('Expires in 3 days')
+ expect(page).to have_content(/in \d days/)
end
end
context 'when expiry date is set' do
- let(:additional_link_attrs) { { expires_at: 3.days.from_now.to_date } }
+ let(:additional_link_attrs) { { expires_at: 5.days.from_now.to_date } }
it 'clears expiry date' do
click_groups_tab
- page.within(find('li.group_member')) do
- expect(page).to have_content('Expires in 3 days')
+ page.within first_row do
+ expect(page).to have_content(/in \d days/)
- page.within(find('.js-edit-member-form')) do
- find('.js-clear-input').click
- end
+ find('[data-testid="clear-button"]').click
wait_for_requests
- expect(page).not_to have_content('Expires in')
+ expect(page).to have_content('No expiration set')
end
end
end
@@ -128,6 +126,7 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
end
def click_groups_tab
+ expect(page).to have_link 'Groups'
click_link "Groups"
end
end
diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb
index aedb7c170f8..e6da05c4873 100644
--- a/spec/features/groups/members/manage_members_spec.rb
+++ b/spec/features/groups/members/manage_members_spec.rb
@@ -4,15 +4,13 @@ require 'spec_helper'
RSpec.describe 'Groups > Members > Manage members' do
include Select2Helper
- include Spec::Support::Helpers::Features::ListRowsHelpers
+ include Spec::Support::Helpers::Features::MembersHelpers
let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') }
let(:group) { create(:group) }
before do
- stub_feature_flags(vue_group_members_list: false)
-
sign_in(user1)
end
@@ -24,7 +22,7 @@ RSpec.describe 'Groups > Members > Manage members' do
page.within(second_row) do
click_button('Developer')
- click_link('Owner')
+ click_button('Owner')
expect(page).to have_button('Owner')
end
@@ -71,11 +69,14 @@ RSpec.describe 'Groups > Members > Manage members' do
visit group_group_members_path(group)
# Open modal
- find(:css, '.project-members-page li', text: user2.name).find(:css, 'button.btn-danger').click
-
- expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
+ page.within(second_row) do
+ click_button 'Remove member'
+ end
- click_on('Remove member')
+ page.within('[role="dialog"]') do
+ expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
+ click_button('Remove member')
+ end
wait_for_requests
@@ -103,16 +104,17 @@ RSpec.describe 'Groups > Members > Manage members' do
add_user('test@example.com', 'Reporter')
- click_link('Invited')
+ expect(page).to have_link 'Invited'
+ click_link 'Invited'
- page.within('.content-list.members-list') do
+ page.within(members_table) do
expect(page).to have_content('test@example.com')
expect(page).to have_content('Invited')
expect(page).to have_button('Reporter')
end
end
- it 'guest can not manage other users' do
+ it 'guest can not manage other users', :js do
group.add_guest(user1)
group.add_developer(user2)
@@ -126,7 +128,7 @@ RSpec.describe 'Groups > Members > Manage members' do
expect(page).not_to have_button 'Developer'
# Can not remove user2
- expect(page).not_to have_css('a.btn-danger')
+ expect(page).not_to have_selector 'button[title="Remove member"]'
end
end
diff --git a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
index dd708c243a8..de9b32e00aa 100644
--- a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
+++ b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
@@ -4,17 +4,13 @@ require 'spec_helper'
RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js do
include Select2Helper
- include ActiveSupport::Testing::TimeHelpers
+ include Spec::Support::Helpers::Features::MembersHelpers
let_it_be(:user1) { create(:user, name: 'John Doe') }
let_it_be(:group) { create(:group) }
let(:new_member) { create(:user, name: 'Mary Jane') }
before do
- stub_feature_flags(vue_group_members_list: false)
-
- travel_to Time.now.utc.beginning_of_day
-
group.add_owner(user1)
sign_in(user1)
end
@@ -22,17 +18,17 @@ RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js
it 'expiration date is displayed in the members list' do
visit group_group_members_path(group)
- page.within '.invite-users-form' do
+ page.within invite_users_form do
select2(new_member.id, from: '#user_ids', multiple: true)
- fill_in 'expires_at', with: 3.days.from_now.to_date
+ fill_in 'expires_at', with: 5.days.from_now.to_date
find_field('expires_at').native.send_keys :enter
click_on 'Invite'
end
- page.within "#group_member_#{group_member_id}" do
- expect(page).to have_content('Expires in 3 days')
+ page.within second_row do
+ expect(page).to have_content(/in \d days/)
end
end
@@ -40,32 +36,28 @@ RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js
group.add_developer(new_member)
visit group_group_members_path(group)
- page.within "#group_member_#{group_member_id}" do
- fill_in 'Expiration date', with: 3.days.from_now.to_date
+ page.within second_row do
+ fill_in 'Expiration date', with: 5.days.from_now.to_date
find_field('Expiration date').native.send_keys :enter
wait_for_requests
- expect(page).to have_content('Expires in 3 days')
+ expect(page).to have_content(/in \d days/)
end
end
it 'clears expiration date' do
- create(:group_member, :developer, user: new_member, group: group, expires_at: 3.days.from_now.to_date)
+ create(:group_member, :developer, user: new_member, group: group, expires_at: 5.days.from_now.to_date)
visit group_group_members_path(group)
- page.within "#group_member_#{group_member_id}" do
- expect(page).to have_content('Expires in 3 days')
+ page.within second_row do
+ expect(page).to have_content(/in \d days/)
- find('.js-clear-input').click
+ find('[data-testid="clear-button"]').click
wait_for_requests
- expect(page).not_to have_content('Expires in')
+ expect(page).to have_content('No expiration set')
end
end
-
- def group_member_id
- group.members.find_by(user_id: new_member).id
- end
end
diff --git a/spec/features/groups/members/master_manages_access_requests_spec.rb b/spec/features/groups/members/master_manages_access_requests_spec.rb
index 44fd7380b79..71c9b280ebe 100644
--- a/spec/features/groups/members/master_manages_access_requests_spec.rb
+++ b/spec/features/groups/members/master_manages_access_requests_spec.rb
@@ -3,10 +3,6 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Maintainer manages access requests' do
- before do
- stub_feature_flags(vue_group_members_list: false)
- end
-
it_behaves_like 'Maintainer manages access requests' do
let(:has_tabs) { true }
let(:entity) { create(:group, :public) }
diff --git a/spec/features/groups/members/search_members_spec.rb b/spec/features/groups/members/search_members_spec.rb
index a95b59cece1..0b2d2fd478d 100644
--- a/spec/features/groups/members/search_members_spec.rb
+++ b/spec/features/groups/members/search_members_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe 'Search group member' do
+RSpec.describe 'Search group member', :js do
+ include Spec::Support::Helpers::Features::MembersHelpers
+
let(:user) { create :user }
let(:member) { create :user }
@@ -14,8 +16,6 @@ RSpec.describe 'Search group member' do
end
before do
- stub_feature_flags(vue_group_members_list: false)
-
sign_in(user)
visit group_group_members_path(guest_group)
end
@@ -23,11 +23,10 @@ RSpec.describe 'Search group member' do
it 'renders member users' do
page.within '[data-testid="user-search-form"]' do
fill_in 'search', with: member.name
- find('.user-search-btn').click
+ find('[data-testid="user-search-submit"]').click
end
- group_members_list = find('[data-qa-selector="members_list"]')
- expect(group_members_list).to have_content(member.name)
- expect(group_members_list).not_to have_content(user.name)
+ expect(members_table).to have_content(member.name)
+ expect(members_table).not_to have_content(user.name)
end
end
diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb
index d940550b18a..f03cc36df18 100644
--- a/spec/features/groups/members/sort_members_spec.rb
+++ b/spec/features/groups/members/sort_members_spec.rb
@@ -2,14 +2,16 @@
require 'spec_helper'
-RSpec.describe 'Groups > Members > Sort members' do
+RSpec.describe 'Groups > Members > Sort members', :js do
+ include Spec::Support::Helpers::Features::MembersHelpers
+
let(:owner) { create(:user, name: 'John Doe') }
let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) }
let(:group) { create(:group) }
- before do
- stub_feature_flags(vue_group_members_list: false)
+ dropdown_toggle_selector = '[data-testid="user-sort-dropdown"] [data-testid="dropdown-toggle"]'
+ before do
create(:group_member, :owner, user: owner, group: group, created_at: 5.days.ago)
create(:group_member, :developer, user: developer, group: group, created_at: 3.days.ago)
@@ -19,84 +21,76 @@ RSpec.describe 'Groups > Members > Sort members' do
it 'sorts alphabetically by default' do
visit_members_list(sort: nil)
- expect(first_member).to include(owner.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending')
end
it 'sorts by access level ascending' do
visit_members_list(sort: :access_level_asc)
- expect(first_member).to include(developer.name)
- expect(second_member).to include(owner.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, ascending')
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, ascending')
end
it 'sorts by access level descending' do
visit_members_list(sort: :access_level_desc)
- expect(first_member).to include(owner.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, descending')
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, descending')
end
it 'sorts by last joined' do
visit_members_list(sort: :last_joined)
- expect(first_member).to include(developer.name)
- expect(second_member).to include(owner.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Last joined')
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Last joined')
end
it 'sorts by oldest joined' do
visit_members_list(sort: :oldest_joined)
- expect(first_member).to include(owner.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest joined')
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest joined')
end
it 'sorts by name ascending' do
visit_members_list(sort: :name_asc)
- expect(first_member).to include(owner.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending')
end
it 'sorts by name descending' do
visit_members_list(sort: :name_desc)
- expect(first_member).to include(developer.name)
- expect(second_member).to include(owner.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, descending')
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Name, descending')
end
it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :recent_sign_in)
- expect(first_member).to include(owner.name)
- expect(second_member).to include(developer.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Recent sign in')
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Recent sign in')
end
it 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :oldest_sign_in)
- expect(first_member).to include(developer.name)
- expect(second_member).to include(owner.name)
- expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest sign in')
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
+ expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest sign in')
end
def visit_members_list(sort:)
visit group_group_members_path(group.to_param, sort: sort)
end
-
- def first_member
- page.all('ul.content-list > li').first.text
- end
-
- def second_member
- page.all('ul.content-list > li').last.text
- end
end
diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb
index 3ae9a2b7555..8d1008b98a6 100644
--- a/spec/features/groups/milestone_spec.rb
+++ b/spec/features/groups/milestone_spec.rb
@@ -83,6 +83,7 @@ RSpec.describe 'Group milestones' do
description: 'Lorem Ipsum is simply dummy text'
)
end
+
let_it_be(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.1') }
let_it_be(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') }
let_it_be(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') }
diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb
index e81f2370d10..dec07eb3783 100644
--- a/spec/features/groups/navbar_spec.rb
+++ b/spec/features/groups/navbar_spec.rb
@@ -50,6 +50,8 @@ RSpec.describe 'Group navbar' do
insert_package_nav(_('Kubernetes'))
stub_feature_flags(group_iterations: false)
+ stub_config(dependency_proxy: { enabled: false })
+ stub_config(registry: { enabled: false })
stub_group_wikis(false)
group.add_maintainer(user)
sign_in(user)
@@ -73,6 +75,18 @@ RSpec.describe 'Group navbar' do
it_behaves_like 'verified navigation bar'
end
+ context 'when dependency proxy is available' do
+ before do
+ stub_config(dependency_proxy: { enabled: true })
+
+ insert_dependency_proxy_nav(_('Dependency Proxy'))
+
+ visit group_path(group)
+ end
+
+ it_behaves_like 'verified navigation bar'
+ end
+
context 'when invite team members is not available' do
it 'does not display the js-invite-members-trigger' do
visit group_path(group)
diff --git a/spec/features/groups/settings/repository_spec.rb b/spec/features/groups/settings/repository_spec.rb
index d20303027e5..3c1609a2605 100644
--- a/spec/features/groups/settings/repository_spec.rb
+++ b/spec/features/groups/settings/repository_spec.rb
@@ -25,4 +25,21 @@ RSpec.describe 'Group Repository settings' do
let(:entity_type) { 'group' }
end
end
+
+ context 'Default initial branch name' do
+ before do
+ visit group_settings_repository_path(group)
+ end
+
+ it 'has the setting section' do
+ expect(page).to have_css("#js-default-branch-name")
+ end
+
+ it 'renders the correct setting section content' do
+ within("#js-default-branch-name") do
+ expect(page).to have_content("Default initial branch name")
+ expect(page).to have_content("Set the default name of the initial branch when creating new repositories through the user interface.")
+ end
+ end
+ end
end
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb
index 304573ecd6e..97732374eb9 100644
--- a/spec/features/groups/show_spec.rb
+++ b/spec/features/groups/show_spec.rb
@@ -81,8 +81,7 @@ RSpec.describe 'Group show page' do
it 'allows creating subgroups' do
visit path
- expect(page)
- .to have_css("li[data-text='New subgroup']", visible: false)
+ expect(page).to have_link('New subgroup')
end
end
end
@@ -102,8 +101,7 @@ RSpec.describe 'Group show page' do
path = group_path(relaxed_group)
visit path
- expect(page)
- .to have_css("li[data-text='New subgroup']", visible: false)
+ expect(page).to have_link('New subgroup')
end
end
@@ -116,9 +114,7 @@ RSpec.describe 'Group show page' do
path = group_path(restricted_group)
visit path
- expect(page)
- .not_to have_selector("li[data-text='New subgroup']",
- visible: false)
+ expect(page).not_to have_link('New subgroup')
end
end
end
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 8264ec2eddd..b9fd3a1a5cc 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -294,35 +294,43 @@ RSpec.describe 'Group' do
describe 'new subgroup / project button' do
let(:group) { create(:group, project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS, subgroup_creation_level: Gitlab::Access::OWNER_SUBGROUP_ACCESS) }
- it 'new subgroup button is displayed without project creation permission' do
- visit group_path(group)
+ context 'when user has subgroup creation permissions but not project creation permissions' do
+ it 'only displays "New subgroup" button' do
+ visit group_path(group)
- page.within '.group-buttons' do
- expect(page).to have_link('New subgroup')
+ page.within '[data-testid="group-buttons"]' do
+ expect(page).to have_link('New subgroup')
+ expect(page).not_to have_link('New project')
+ end
end
end
- it 'new subgroup button is displayed together with new project button when having project creation permission' do
- group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
- visit group_path(group)
+ context 'when user has project creation permissions but not subgroup creation permissions' do
+ it 'only displays "New project" button' do
+ group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
+ user = create(:user)
- page.within '.group-buttons' do
- expect(page).to have_css("li[data-text='New subgroup']", visible: false)
- expect(page).to have_css("li[data-text='New project']", visible: false)
+ group.add_maintainer(user)
+ sign_out(:user)
+ sign_in(user)
+
+ visit group_path(group)
+ page.within '[data-testid="group-buttons"]' do
+ expect(page).to have_link('New project')
+ expect(page).not_to have_link('New subgroup')
+ end
end
end
- it 'new project button is displayed without subgroup creation permission' do
- group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
- user = create(:user)
-
- group.add_maintainer(user)
- sign_out(:user)
- sign_in(user)
+ context 'when user has project and subgroup creation permissions' do
+ it 'displays "New subgroup" and "New project" buttons' do
+ group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
+ visit group_path(group)
- visit group_path(group)
- page.within '.group-buttons' do
- expect(page).to have_link('New project')
+ page.within '[data-testid="group-buttons"]' do
+ expect(page).to have_link('New subgroup')
+ expect(page).to have_link('New project')
+ end
end
end
end
diff --git a/spec/features/ide/user_sees_editor_info_spec.rb b/spec/features/ide/user_sees_editor_info_spec.rb
new file mode 100644
index 00000000000..3760d6bd435
--- /dev/null
+++ b/spec/features/ide/user_sees_editor_info_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'IDE user sees editor info', :js do
+ include WebIdeSpecHelpers
+
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:user) { project.owner }
+
+ before do
+ sign_in(user)
+
+ ide_visit(project)
+ end
+
+ it 'shows line position' do
+ ide_open_file('README.md')
+
+ within find('.ide-status-bar') do
+ expect(page).to have_content('1:1')
+ end
+
+ ide_set_editor_position(4, 10)
+
+ within find('.ide-status-bar') do
+ expect(page).not_to have_content('1:1')
+ expect(page).to have_content('4:10')
+ end
+ end
+
+ it 'updates after rename' do
+ ide_open_file('README.md')
+ ide_set_editor_position(4, 10)
+
+ within find('.ide-status-bar') do
+ expect(page).to have_content('markdown')
+ expect(page).to have_content('4:10')
+ end
+
+ ide_rename_file('README.md', 'READMEZ.txt')
+
+ within find('.ide-status-bar') do
+ expect(page).to have_content('plaintext')
+ expect(page).to have_content('1:1')
+ end
+ end
+
+ it 'persists position after rename' do
+ ide_open_file('README.md')
+ ide_set_editor_position(4, 10)
+
+ ide_open_file('files/js/application.js')
+ ide_rename_file('README.md', 'READING_RAINBOW.md')
+
+ ide_open_file('READING_RAINBOW.md')
+
+ within find('.ide-status-bar') do
+ expect(page).to have_content('4:10')
+ end
+ end
+
+ it 'persists position' do
+ ide_open_file('README.md')
+ ide_set_editor_position(4, 10)
+
+ ide_close_file('README.md')
+ ide_open_file('README.md')
+
+ within find('.ide-status-bar') do
+ expect(page).to have_content('markdown')
+ expect(page).to have_content('4:10')
+ end
+ end
+
+ it 'persists viewer' do
+ ide_open_file('README.md')
+ click_link('Preview Markdown')
+
+ within find('.md-previewer') do
+ expect(page).to have_content('testme')
+ end
+
+ # Switch away from and back to the file
+ ide_open_file('.gitignore')
+ ide_open_file('README.md')
+
+ # Preview is still enabled
+ within find('.md-previewer') do
+ expect(page).to have_content('testme')
+ end
+ end
+end
diff --git a/spec/features/incidents/user_views_incident_spec.rb b/spec/features/incidents/user_views_incident_spec.rb
new file mode 100644
index 00000000000..3595f5c03ec
--- /dev/null
+++ b/spec/features/incidents/user_views_incident_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe "User views incident" do
+ let_it_be(:project) { create(:project_empty_repo, :public) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:incident) { create(:incident, project: project, description: "# Description header\n\n**Lorem** _ipsum_ dolor sit [amet](https://example.com)", author: user) }
+ let_it_be(:note) { create(:note, noteable: incident, project: project, author: user) }
+
+ before_all do
+ project.add_developer(user)
+ end
+
+ before do
+ stub_feature_flags(vue_issue_header: false)
+
+ sign_in(user)
+
+ visit(project_issues_incident_path(project, incident))
+ end
+
+ it { expect(page).to have_header_with_correct_id_and_link(1, "Description header", "description-header") }
+
+ it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet'
+
+ it 'shows the merge request and incident actions', :aggregate_failures do
+ expect(page).to have_link('New incident')
+ expect(page).to have_button('Create merge request')
+ expect(page).to have_link('Close incident')
+ end
+
+ context 'when the project is archived' do
+ before do
+ project.update!(archived: true)
+ visit(project_issues_incident_path(project, incident))
+ end
+
+ it 'hides the merge request and incident actions', :aggregate_failures do
+ expect(page).not_to have_link('New incident')
+ expect(page).not_to have_button('Create merge request')
+ expect(page).not_to have_link('Close incident')
+ end
+ end
+
+ describe 'user status' do
+ subject { visit(project_issues_incident_path(project, incident)) }
+
+ context 'when showing status of the author of the incident' do
+ it_behaves_like 'showing user status' do
+ let(:user_with_status) { user }
+ end
+ end
+
+ context 'when showing status of a user who commented on an incident', :js do
+ it_behaves_like 'showing user status' do
+ let(:user_with_status) { user }
+ end
+ end
+
+ context 'when status message has an emoji', :js do
+ let_it_be(:message) { 'My status with an emoji' }
+ let_it_be(:message_emoji) { 'basketball' }
+ let_it_be(:status) { create(:user_status, user: user, emoji: 'smirk', message: "#{message} :#{message_emoji}:") }
+
+ it 'correctly renders the emoji' do
+ wait_for_requests
+
+ tooltip_span = page.first(".user-status-emoji[title^='#{message}']")
+ tooltip_span.hover
+
+ wait_for_requests
+
+ tooltip = page.find('.tooltip .tooltip-inner')
+
+ page.within(tooltip) do
+ expect(page).to have_emoji(message_emoji)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 8ccaf82536a..2ceffa896eb 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
let(:group_invite) { group.group_members.invite.last }
before do
+ stub_application_setting(require_admin_approval_after_user_signup: false)
project.add_maintainer(owner)
group.add_owner(owner)
group.add_developer('user@example.com', owner)
@@ -58,6 +59,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
end
it 'pre-fills the Email field on the sign up box with the invite_email from the invite' do
+ click_link 'Register now'
+
expect(find_field('Email').value).to eq(group_invite.invite_email)
end
@@ -92,6 +95,22 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
before do
stub_application_setting(send_user_confirmation_email: send_email_confirmation)
visit invite_path(group_invite.raw_invite_token)
+ click_link 'Register now'
+ end
+
+ context 'with admin appoval required enabled' do
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: true)
+ end
+
+ let(:send_email_confirmation) { true }
+
+ it 'does not sign the user in' do
+ fill_in_sign_up_form(new_user)
+
+ expect(current_path).to eq(new_user_session_path)
+ expect(page).to have_content('You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator')
+ end
end
context 'email confirmation disabled' do
diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb
index 6e99cfb3293..867d2ff7aae 100644
--- a/spec/features/issuables/close_reopen_report_toggle_spec.rb
+++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
let(:user) { create(:user) }
+ before do
+ stub_feature_flags(vue_issue_header: false)
+ end
+
shared_examples 'an issuable close/reopen/report toggle' do
let(:container) { find('.issuable-close-dropdown') }
let(:human_model_name) { issuable.model_name.human.downcase }
@@ -95,12 +99,13 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
expect(page).to have_link('New issue')
expect(page).not_to have_button('Close issue')
expect(page).not_to have_button('Reopen issue')
- expect(page).not_to have_link('Edit')
+ expect(page).not_to have_link(title: 'Edit title and description')
end
end
end
context 'on a merge request' do
+ let(:container) { find('.detail-page-header-actions') }
let(:project) { create(:project, :repository) }
let(:issuable) { create(:merge_request, source_project: project) }
@@ -116,24 +121,47 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
it_behaves_like 'an issuable close/reopen/report toggle'
+ context 'when the merge request is closed' do
+ let(:issuable) { create(:merge_request, :closed, source_project: project) }
+
+ it 'shows both the `Edit` and `Reopen` button' do
+ expect(container).to have_link('Edit')
+ expect(container).not_to have_button('Report abuse')
+ expect(container).not_to have_button('Close merge request')
+ expect(container).to have_link('Reopen merge request')
+ end
+
+ context 'when the merge request author is the current user' do
+ let(:issuable) { create(:merge_request, :closed, source_project: project, author: user) }
+
+ it 'shows both the `Edit` and `Reopen` button' do
+ expect(container).to have_link('Edit')
+ expect(container).not_to have_link('Report abuse')
+ expect(container).not_to have_selector('button.dropdown-toggle')
+ expect(container).not_to have_button('Close merge request')
+ expect(container).to have_link('Reopen merge request')
+ end
+ end
+ end
+
context 'when the merge request is merged' do
let(:issuable) { create(:merge_request, :merged, source_project: project) }
- it 'shows only the `Report abuse` and `Edit` button' do
- expect(page).to have_link('Report abuse')
- expect(page).to have_link('Edit')
- expect(page).not_to have_button('Close merge request')
- expect(page).not_to have_button('Reopen merge request')
+ it 'shows only the `Edit` button' do
+ expect(container).to have_link(exact_text: 'Edit')
+ expect(container).not_to have_link('Report abuse')
+ expect(container).not_to have_button('Close merge request')
+ expect(container).not_to have_button('Reopen merge request')
end
context 'when the merge request author is the current user' do
let(:issuable) { create(:merge_request, :merged, source_project: project, author: user) }
it 'shows only the `Edit` button' do
- expect(page).to have_link('Edit')
- expect(page).to have_link('Report abuse')
- expect(page).not_to have_button('Close merge request')
- expect(page).not_to have_button('Reopen merge request')
+ expect(container).to have_link(exact_text: 'Edit')
+ expect(container).not_to have_link('Report abuse')
+ expect(container).not_to have_button('Close merge request')
+ expect(container).not_to have_button('Reopen merge request')
end
end
end
@@ -150,10 +178,10 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
end
it 'only shows a `Report abuse` button' do
- expect(page).to have_link('Report abuse')
- expect(page).not_to have_button('Close merge request')
- expect(page).not_to have_button('Reopen merge request')
- expect(page).not_to have_link('Edit')
+ expect(container).to have_link('Report abuse')
+ expect(container).not_to have_button('Close merge request')
+ expect(container).not_to have_button('Reopen merge request')
+ expect(container).not_to have_link(exact_text: 'Edit')
end
end
end
diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
index 12682905559..0f0146a26a2 100644
--- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
@@ -18,6 +18,10 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
end
end
+ before do
+ stub_feature_flags(remove_resolve_note: false)
+ end
+
describe 'as a user with access to the project' do
before do
project.add_maintainer(user)
diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
index 55a02dc4255..b449939a70c 100644
--- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
@@ -14,6 +14,10 @@ RSpec.describe 'Resolve an open thread in a merge request by creating an issue',
"a[title=\"#{title}\"][href=\"#{url}\"]"
end
+ before do
+ stub_feature_flags(remove_resolve_note: false)
+ end
+
describe 'As a user with access to the project' do
before do
project.add_maintainer(user)
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index ff78b9e608f..06f79f94e8d 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -535,6 +535,21 @@ RSpec.describe 'GFM autocomplete', :js do
expect(find('.tribute-container ul', visible: true)).to have_text(user_xss.username)
end
+ it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
+ milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
+ create(:milestone, project: project, title: milestone_xss_title)
+
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('%')
+ end
+
+ wait_for_requests
+
+ expect(page).to have_selector('.tribute-container', visible: true)
+
+ expect(find('.tribute-container ul', visible: true)).to have_text('alert milestone')
+ end
+
it 'selects the first item for assignee dropdowns' do
page.within '.timeline-content-form' do
find('#note-body').native.send_keys('@')
@@ -799,6 +814,13 @@ RSpec.describe 'GFM autocomplete', :js do
end
end
+ context 'issues' do
+ let(:object) { issue }
+ let(:expected_body) { object.to_reference }
+
+ it_behaves_like 'autocomplete suggestions'
+ end
+
context 'merge requests' do
let(:object) { create(:merge_request, source_project: project) }
let(:expected_body) { object.to_reference }
@@ -806,6 +828,27 @@ RSpec.describe 'GFM autocomplete', :js do
it_behaves_like 'autocomplete suggestions'
end
+ context 'project snippets' do
+ let!(:object) { create(:project_snippet, project: project, title: 'code snippet') }
+ let(:expected_body) { object.to_reference }
+
+ it_behaves_like 'autocomplete suggestions'
+ end
+
+ context 'label' do
+ let!(:object) { label }
+ let(:expected_body) { object.title }
+
+ it_behaves_like 'autocomplete suggestions'
+ end
+
+ context 'milestone' do
+ let!(:object) { create(:milestone, project: project) }
+ let(:expected_body) { object.to_reference }
+
+ it_behaves_like 'autocomplete suggestions'
+ end
+
context 'when other notes are destroyed' do
let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
index 617eac88973..e225a45481d 100644
--- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
@@ -250,7 +250,7 @@ RSpec.describe 'User creates branch and merge request on issue page', :js do
def test_selection_mark(li_create_branch, li_create_merge_request, button_create_target, button_create_merge_request)
page.within(li_create_merge_request) do
- expect(page).to have_css('i.fa.fa-check')
+ expect(page).to have_selector('[data-testid="check-icon"]')
expect(button_create_target).to have_text('Create merge request')
expect(button_create_merge_request).to have_text('Create merge request')
end
@@ -258,7 +258,7 @@ RSpec.describe 'User creates branch and merge request on issue page', :js do
li_create_branch.click
page.within(li_create_branch) do
- expect(page).to have_css('i.fa.fa-check')
+ expect(page).to have_selector('[data-testid="check-icon"]')
expect(button_create_target).to have_text('Create branch')
expect(button_create_merge_request).to have_text('Create branch')
end
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index de746415205..11b905735de 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -138,6 +138,33 @@ RSpec.describe "Issues > User edits issue", :js do
expect(page).not_to have_text('verisimilitude')
end
end
+
+ it 'can remove label without removing label added via quick action', :aggregate_failures do
+ # Add `syzygy` label with a quick action
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('/label ~syzygy')
+ end
+ click_button 'Comment'
+
+ wait_for_requests
+
+ page.within '.block.labels' do
+ # Remove `verisimilitude` label
+ within '.gl-label' do
+ click_button
+ end
+
+ wait_for_requests
+
+ expect(page).to have_text('syzygy')
+ expect(page).not_to have_text('verisimilitude')
+ end
+
+ expect(page).to have_text('removed verisimilitude label')
+ expect(page).not_to have_text('removed syzygy verisimilitude labels')
+ expect(issue.reload.labels.map(&:title)).to contain_exactly('syzygy')
+ end
end
describe 'update assignee' do
diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb
index 7db72f2cd05..fec603e466a 100644
--- a/spec/features/issues/user_interacts_with_awards_spec.rb
+++ b/spec/features/issues/user_interacts_with_awards_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe 'User interacts with awards' do
page.within('.awards') do
expect(page).to have_selector('.js-emoji-btn')
expect(page.find('.js-emoji-btn.active .js-counter')).to have_content('1')
- expect(page).to have_css(".js-emoji-btn.active[data-original-title='You']")
+ expect(page).to have_css(".js-emoji-btn.active[title='You']")
expect do
page.find('.js-emoji-btn.active').click
@@ -294,7 +294,7 @@ RSpec.describe 'User interacts with awards' do
end
end
- it 'toggles the smiley emoji on a note', :js do
+ it 'toggles the smiley emoji on a note', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/267525' do
toggle_smiley_emoji(true)
within('.note-body') do
diff --git a/spec/features/issues/user_sees_live_update_spec.rb b/spec/features/issues/user_sees_live_update_spec.rb
index d27cdb774a5..79c6978cbc0 100644
--- a/spec/features/issues/user_sees_live_update_spec.rb
+++ b/spec/features/issues/user_sees_live_update_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe 'Issues > User sees live update', :js do
end
describe 'confidential issue#show' do
- it 'shows confidential sibebar information as confidential and can be turned off' do
+ it 'shows confidential sibebar information as confidential and can be turned off', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/254644' do
issue = create(:issue, :confidential, project: project)
visit project_issue_path(project, issue)
diff --git a/spec/features/issues/user_views_issue_spec.rb b/spec/features/issues/user_views_issue_spec.rb
index 9b1c8be1513..4128f3478bb 100644
--- a/spec/features/issues/user_views_issue_spec.rb
+++ b/spec/features/issues/user_views_issue_spec.rb
@@ -13,6 +13,8 @@ RSpec.describe "User views issue" do
end
before do
+ stub_feature_flags(vue_issue_header: false)
+
sign_in(user)
visit(project_issue_path(project, issue))
diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb
index ad1ad067935..c452408cff2 100644
--- a/spec/features/merge_request/user_comments_on_diff_spec.rb
+++ b/spec/features/merge_request/user_comments_on_diff_spec.rb
@@ -136,12 +136,6 @@ RSpec.describe 'User comments on a diff', :js do
add_comment('-13', '+15')
end
- it 'allows comments to start above hidden lines and end below' do
- # click +28, select 21 add and verify comment
- click_diff_line(find('div[data-path="files/ruby/popen.rb"] .new_line a[data-linenumber="28"]').find(:xpath, '../..'), 'right')
- add_comment('21', '+28')
- end
-
it 'allows comments on previously hidden lines at the top of a file' do
# Click -9, expand up, select 1 add and verify comment
page.within('[data-path="files/ruby/popen.rb"]') do
diff --git a/spec/features/merge_request/user_comments_on_merge_request_spec.rb b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
index 73f2b1a25ce..43096f8e7f9 100644
--- a/spec/features/merge_request/user_comments_on_merge_request_spec.rb
+++ b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
@@ -30,6 +30,27 @@ RSpec.describe 'User comments on a merge request', :js do
end
end
+ it 'replys to a new comment' do
+ page.within('.js-main-target-form') do
+ fill_in('note[note]', with: 'comment 1')
+ click_button('Comment')
+ end
+
+ wait_for_requests
+
+ page.within('.note') do
+ click_button('Reply to comment')
+
+ fill_in('note[note]', with: 'comment 2')
+ click_button('Add comment now')
+ end
+
+ wait_for_requests
+
+ # Test that the discussion doesn't get auto-resolved
+ expect(page).to have_button('Resolve thread')
+ end
+
it 'loads new comment' do
# Add new comment in background in order to check
# if it's going to be loaded automatically for current user.
diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb
index 0cdc87de761..09c5897f102 100644
--- a/spec/features/merge_request/user_expands_diff_spec.rb
+++ b/spec/features/merge_request/user_expands_diff_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'User expands diff', :js do
before do
stub_feature_flags(increased_diff_limits: false)
+ allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.kilobytes)
+
visit(diffs_project_merge_request_path(project, merge_request))
wait_for_requests
@@ -15,11 +17,11 @@ RSpec.describe 'User expands diff', :js do
it 'allows user to expand diff' do
page.within find('[id="19763941ab80e8c09871c0a425f0560d9053bcb3"]') do
- click_link 'Click to expand it.'
+ find('[data-testid="expand-button"]').click
wait_for_requests
- expect(page).not_to have_content('Click to expand it.')
+ expect(page).not_to have_content('Expand file')
expect(page).to have_selector('.code')
end
end
diff --git a/spec/features/merge_request/user_merges_immediately_spec.rb b/spec/features/merge_request/user_merges_immediately_spec.rb
index 0fb081ec507..64a357de1f7 100644
--- a/spec/features/merge_request/user_merges_immediately_spec.rb
+++ b/spec/features/merge_request/user_merges_immediately_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe 'Merge requests > User merges immediately', :js do
find('.dropdown-toggle').click
Sidekiq::Testing.fake! do
- click_link 'Merge immediately'
+ click_button 'Merge immediately'
expect(find('.accept-merge-request.btn-info')).to have_content('Merge in progress')
diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
index 444d5371e7a..5e99383e4a1 100644
--- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
@@ -93,19 +93,6 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do
it_behaves_like 'Merge when pipeline succeeds activator'
end
end
-
- describe 'enabling Merge when pipeline succeeds via dropdown' do
- it 'activates the Merge when pipeline succeeds feature' do
- wait_for_requests
-
- find('.js-merge-moment').click
- click_link 'Merge when pipeline succeeds'
-
- expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds"
- expect(page).to have_content "The source branch will not be deleted"
- expect(page).to have_link "Cancel automatic merge"
- end
- end
end
context 'when merge when pipeline succeeds is enabled' do
diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb
index f96408fb10b..06405232462 100644
--- a/spec/features/merge_request/user_resolves_conflicts_spec.rb
+++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Merge request > User resolves conflicts', :js do
+ include Spec::Support::Helpers::Features::EditorLiteSpecHelpers
+
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
@@ -64,15 +66,13 @@ RSpec.describe 'Merge request > User resolves conflicts', :js do
within find('.files-wrapper .diff-file', text: 'files/ruby/popen.rb') do
click_button 'Edit inline'
wait_for_requests
- find('.files-wrapper .diff-file pre')
- execute_script('ace.edit($(".files-wrapper .diff-file pre")[0]).setValue("One morning");')
+ editor_set_value("One morning")
end
within find('.files-wrapper .diff-file', text: 'files/ruby/regex.rb') do
click_button 'Edit inline'
wait_for_requests
- find('.files-wrapper .diff-file pre')
- execute_script('ace.edit($(".files-wrapper .diff-file pre")[1]).setValue("Gregor Samsa woke from troubled dreams");')
+ editor_set_value("Gregor Samsa woke from troubled dreams")
end
find_button('Commit to source branch').send_keys(:return)
diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
index cd06886169d..00f0c88497b 100644
--- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
+++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
@@ -15,6 +15,10 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
diff_refs: merge_request.diff_refs)
end
+ before do
+ stub_feature_flags(remove_resolve_note: false)
+ end
+
context 'no threads' do
before do
project.add_maintainer(user)
diff --git a/spec/features/merge_request/user_resolves_wip_mr_spec.rb b/spec/features/merge_request/user_resolves_wip_mr_spec.rb
index b67167252e1..93b14279a06 100644
--- a/spec/features/merge_request/user_resolves_wip_mr_spec.rb
+++ b/spec/features/merge_request/user_resolves_wip_mr_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe 'Merge request > User resolves Work in Progress', :js do
it 'retains merge request data after clicking Resolve WIP status' do
expect(page.find('.ci-widget-content')).to have_content("Pipeline ##{pipeline.id}")
- expect(page).to have_content "This merge request is still a work in progress."
+ expect(page).to have_content "This merge request is still a draft."
page.within('.mr-state-widget') do
click_button('Mark as ready')
@@ -45,7 +45,7 @@ RSpec.describe 'Merge request > User resolves Work in Progress', :js do
# merge request widget refreshes, which masks missing elements
# that should already be present.
expect(page.find('.ci-widget-content', wait: 0)).to have_content("Pipeline ##{pipeline.id}")
- expect(page).not_to have_content('This merge request is still a work in progress.')
+ expect(page).not_to have_content('This merge request is still a draft.')
end
end
end
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index 93fea44707c..0e8012f161f 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -558,8 +558,9 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
before do
- allow_any_instance_of(TestSuiteComparerEntity)
- .to receive(:max_tests).and_return(2)
+ stub_const("Gitlab::Ci::Reports::TestSuiteComparer::DEFAULT_MAX_TESTS", 2)
+ stub_const("Gitlab::Ci::Reports::TestSuiteComparer::DEFAULT_MIN_TESTS", 1)
+
allow_any_instance_of(MergeRequest)
.to receive(:has_test_reports?).and_return(true)
allow_any_instance_of(MergeRequest)
diff --git a/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb b/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb
index 93807512d9c..4bb6c3265a4 100644
--- a/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb
+++ b/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb
@@ -9,8 +9,6 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do
before do
stub_application_setting(auto_devops_enabled: false)
- stub_experiment(suggest_pipeline: true)
- stub_experiment_for_user(suggest_pipeline: true)
project.add_maintainer(user)
sign_in(user)
visit project_merge_request_path(project, merge_request)
@@ -32,4 +30,40 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do
expect(page).not_to have_content('Are you adding technical debt or code vulnerabilities?')
end
+
+ it 'runs tour from start to finish ensuring all nudges are executed' do
+ # nudge 1
+ expect(page).to have_content('Are you adding technical debt or code vulnerabilities?')
+
+ page.within '.mr-pipeline-suggest' do
+ find('[data-testid="ok"]').click
+ end
+
+ wait_for_requests
+
+ # nudge 2
+ expect(page).to have_content('Choose Code Quality to add a pipeline that tests the quality of your code.')
+
+ find('.js-gitlab-ci-yml-selector').click
+
+ wait_for_requests
+
+ within '.gitlab-ci-yml-selector' do
+ find('.dropdown-input-field').set('Jekyll')
+ find('.dropdown-content li', text: 'Jekyll').click
+ end
+
+ wait_for_requests
+
+ expect(page).not_to have_content('Choose Code Quality to add a pipeline that tests the quality of your code.')
+ # nudge 3
+ expect(page).to have_content('The template is ready!')
+
+ find('#commit-changes').click
+
+ wait_for_requests
+
+ # nudge 4
+ expect(page).to have_content("That's it, well done!")
+ end
end
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index 9268190c7e0..1e1888cd826 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -304,7 +304,7 @@ RSpec.describe 'User comments on a diff', :js do
wait_for_requests
end
- it 'suggestion is presented' do
+ it 'suggestion is presented', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/268240' do
page.within('.diff-discussions') do
expect(page).to have_button('Apply suggestion')
expect(page).to have_content('Suggested change')
diff --git a/spec/features/merge_request/user_views_diffs_spec.rb b/spec/features/merge_request/user_views_diffs_spec.rb
index 928755bf5de..e1865fe2e14 100644
--- a/spec/features/merge_request/user_views_diffs_spec.rb
+++ b/spec/features/merge_request/user_views_diffs_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe 'User views diffs', :js do
end
it 'expands all diffs' do
- first('.js-file-title').click
+ first('.diff-toggle-caret').click
expect(page).to have_button('Expand all')
diff --git a/spec/features/merge_requests/user_exports_as_csv_spec.rb b/spec/features/merge_requests/user_exports_as_csv_spec.rb
new file mode 100644
index 00000000000..a86ff9d7335
--- /dev/null
+++ b/spec/features/merge_requests/user_exports_as_csv_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge Requests > Exports as CSV', :js do
+ let!(:project) { create(:project, :public, :repository) }
+ let!(:user) { project.creator }
+ let!(:open_mr) { create(:merge_request, title: 'Bugfix1', source_project: project, target_project: project, source_branch: 'bugfix1') }
+
+ before do
+ sign_in(user)
+ visit(project_merge_requests_path(project))
+ end
+
+ subject { page.find('.nav-controls') }
+
+ it { is_expected.to have_button('Export as CSV') }
+
+ context 'button is clicked' do
+ before do
+ click_button('Export as CSV')
+ end
+
+ it 'shows a success message' do
+ click_link('Export merge requests')
+
+ expect(page).to have_content 'Your CSV export has started.'
+ expect(page).to have_content "It will be emailed to #{user.email} when complete"
+ end
+ end
+end
diff --git a/spec/features/merge_requests/user_filters_by_draft_spec.rb b/spec/features/merge_requests/user_filters_by_draft_spec.rb
new file mode 100644
index 00000000000..de070805d96
--- /dev/null
+++ b/spec/features/merge_requests/user_filters_by_draft_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge Requests > User filters by draft', :js do
+ include FilteredSearchHelpers
+
+ let(:project) { create(:project, :public, :repository) }
+ let(:user) { project.creator }
+
+ before do
+ create(:merge_request, title: 'Draft: Bugfix', source_project: project, target_project: project, source_branch: 'bugfix2')
+
+ sign_in(user)
+ visit project_merge_requests_path(project)
+ end
+
+ it 'filters results' do
+ input_filtered_search_keys('draft:=yes')
+
+ expect(page).to have_content('Draft: Bugfix')
+ end
+
+ it 'does not allow filtering by is not equal' do
+ find('#filtered-search-merge_requests').click
+
+ click_button 'Draft'
+
+ expect(page).not_to have_content('!=')
+ end
+end
diff --git a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
index 540d87eb969..1d9c80238f5 100644
--- a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
@@ -44,4 +44,14 @@ RSpec.describe 'Merge Requests > User filters by target branch', :js do
expect(page).not_to have_content mr2.title
end
end
+
+ context 'filtering by target-branch:!=master' do
+ it 'applies the filter' do
+ input_filtered_search('target-branch:!=master')
+
+ expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
+ expect(page).not_to have_content mr1.title
+ expect(page).to have_content mr2.title
+ end
+ end
end
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index fefa2916c30..dce76e4df6d 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -76,7 +76,7 @@ RSpec.describe 'Milestone' do
wait_for_requests
- page.within('.time-tracking-no-tracking-pane') do
+ page.within('[data-testid="noTrackingPane"]') do
expect(page).to have_content 'No estimate or time spent'
end
end
@@ -94,7 +94,7 @@ RSpec.describe 'Milestone' do
wait_for_requests
- page.within('.time-tracking-spend-only-pane') do
+ page.within('[data-testid="spentOnlyPane"]') do
expect(page).to have_content 'Spent: 3h'
end
end
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index 4326700bab1..84ea9495f08 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -12,6 +12,9 @@ RSpec.describe 'Profile account page', :js do
describe 'when I delete my account' do
before do
visit profile_account_path
+
+ # Scroll page to the bottom to make Delete account button visible
+ execute_script('window.scrollTo(0, document.body.scrollHeight)')
end
it { expect(page).to have_content('Delete account') }
@@ -101,10 +104,10 @@ RSpec.describe 'Profile account page', :js do
it 'changes my username' do
fill_in 'username-change-input', with: 'new-username'
- page.find('[data-target="#username-change-confirmation-modal"]').click
+ page.find('[data-testid="username-change-confirmation-modal"]').click
page.within('.modal') do
- find('.js-modal-primary-action').click
+ find('.js-modal-action-primary').click
end
expect(page).to have_content('new-username')
diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb
index e8caa2159a4..62d8a96c1b2 100644
--- a/spec/features/profiles/account_spec.rb
+++ b/spec/features/profiles/account_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe 'Profile > Account', :js do
end
it 'allows the user to disconnect when there is an existing identity' do
- expect(page).to have_link('Disconnect Twitter', href: '/profile/account/unlink?provider=twitter')
+ expect(page).to have_link('Disconnect Twitter', href: '/-/profile/account/unlink?provider=twitter')
end
it 'shows active for a provider that is not allowed to unlink' do
@@ -128,10 +128,10 @@ def update_username(new_username)
fill_in 'username-change-input', with: new_username
- page.find('[data-target="#username-change-confirmation-modal"]').click
+ page.find('[data-testid="username-change-confirmation-modal"]').click
page.within('.modal') do
- find('.js-modal-primary-action').click
+ find('.js-modal-action-primary').click
end
wait_for_requests
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index 4438831fb76..de5a594aca6 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Profile > Personal Access Tokens', :js do
let(:user) { create(:user) }
+ let(:pat_create_service) { double('PersonalAccessTokens::CreateService', execute: ServiceResponse.error(message: 'error', payload: { personal_access_token: PersonalAccessToken.new })) }
def active_personal_access_tokens
find(".table.active-tokens")
@@ -18,7 +19,7 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
end
def disallow_personal_access_token_saves!
- allow_any_instance_of(PersonalAccessToken).to receive(:save).and_return(false)
+ allow(PersonalAccessTokens::CreateService).to receive(:new).and_return(pat_create_service)
errors = ActiveModel::Errors.new(PersonalAccessToken.new).tap { |e| e.add(:name, "cannot be nil") }
allow_any_instance_of(PersonalAccessToken).to receive(:errors).and_return(errors)
@@ -100,7 +101,10 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
context "when revocation fails" do
it "displays an error message" do
visit profile_personal_access_tokens_path
- allow_any_instance_of(PersonalAccessTokens::RevokeService).to receive(:revocation_permitted?).and_return(false)
+
+ allow_next_instance_of(PersonalAccessTokens::RevokeService) do |instance|
+ allow(instance).to receive(:revocation_permitted?).and_return(false)
+ end
accept_confirm { click_on "Revoke" }
expect(active_personal_access_tokens).to have_text(personal_access_token.name)
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 697fccaca34..d0340dfc880 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -20,6 +20,10 @@ RSpec.describe 'User edit profile' do
wait_for_requests
end
+ def toggle_busy_status
+ find('[data-testid="user-availability-checkbox"]').set(true)
+ end
+
it 'changes user profile' do
fill_in 'user_skype', with: 'testskype'
fill_in 'user_linkedin', with: 'testlinkedin'
@@ -180,20 +184,51 @@ RSpec.describe 'User edit profile' do
expect(page).to have_emoji('speech_balloon')
end
end
+
+ it 'sets the users status to busy' do
+ busy_status = find('[data-testid="user-availability-checkbox"]')
+
+ expect(busy_status.checked?).to eq(false)
+
+ toggle_busy_status
+ submit_settings
+ visit profile_path
+
+ expect(busy_status.checked?).to eq(true)
+ end
+
+ context 'with set_user_availability_status feature flag disabled' do
+ before do
+ stub_feature_flags(set_user_availability_status: false)
+ visit root_path(user)
+ end
+
+ it 'does not display the availability checkbox' do
+ expect(page).not_to have_css('[data-testid="user-availability-checkbox"]')
+ end
+ end
end
context 'user menu' do
let(:issue) { create(:issue, project: project)}
let(:project) { create(:project) }
- def open_user_status_modal
+ def open_modal(button_text)
find('.header-user-dropdown-toggle').click
page.within ".header-user" do
- click_button 'Set status'
+ click_button button_text
end
end
+ def open_user_status_modal
+ open_modal 'Set status'
+ end
+
+ def open_edit_status_modal
+ open_modal 'Edit status'
+ end
+
def set_user_status_in_modal
page.within "#set-user-status-modal" do
click_button 'Set status'
@@ -246,6 +281,19 @@ RSpec.describe 'User edit profile' do
end
end
+ it 'sets the users status to busy' do
+ open_user_status_modal
+ busy_status = find('[data-testid="user-availability-checkbox"]')
+
+ expect(busy_status.checked?).to eq(false)
+
+ toggle_busy_status
+ set_user_status_in_modal
+ open_edit_status_modal
+
+ expect(busy_status.checked?).to eq(true)
+ end
+
it 'opens the emoji modal again after closing it' do
open_user_status_modal
select_emoji('biohazard', true)
@@ -307,11 +355,7 @@ RSpec.describe 'User edit profile' do
expect(page).to have_content user_status.message
end
- find('.header-user-dropdown-toggle').click
-
- page.within ".header-user" do
- click_button 'Edit status'
- end
+ open_edit_status_modal
find('.js-clear-user-status-button').click
set_user_status_in_modal
@@ -333,11 +377,7 @@ RSpec.describe 'User edit profile' do
expect(page).to have_content user_status.message
end
- find('.header-user-dropdown-toggle').click
-
- page.within ".header-user" do
- click_button 'Edit status'
- end
+ open_edit_status_modal
page.within "#set-user-status-modal" do
click_button 'Remove status'
@@ -357,6 +397,19 @@ RSpec.describe 'User edit profile' do
expect(page).to have_emoji('speech_balloon')
end
end
+
+ context 'with set_user_availability_status feature flag disabled' do
+ before do
+ stub_feature_flags(set_user_availability_status: false)
+ visit root_path(user)
+ end
+
+ it 'does not display the availability checkbox' do
+ open_user_status_modal
+
+ expect(page).not_to have_css('[data-testid="user-availability-checkbox"]')
+ end
+ end
end
context 'User time preferences', :js do
diff --git a/spec/features/project_group_variables_spec.rb b/spec/features/project_group_variables_spec.rb
index e964a7def14..d8eba20ac18 100644
--- a/spec/features/project_group_variables_spec.rb
+++ b/spec/features/project_group_variables_spec.rb
@@ -24,7 +24,6 @@ RSpec.describe 'Project group variables', :js do
sign_in(user)
project.add_maintainer(user)
group.add_owner(user)
- stub_feature_flags(new_variables_ui: false)
end
it 'project in group shows inherited vars from ancestor group' do
@@ -53,9 +52,13 @@ RSpec.describe 'Project group variables', :js do
it 'project origin keys link to ancestor groups ci_cd settings' do
visit project_path
+
find('.group-origin-link').click
- page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
- expect(find('.js-ci-variable-input-key').value).to eq(key1)
+
+ wait_for_requests
+
+ page.within('.ci-variable-table') do
+ expect(find('.js-ci-variable-row:nth-child(1) [data-label="Key"]').text).to eq(key1)
end
end
end
diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb
index c67bcbf919b..a7f94f38d85 100644
--- a/spec/features/project_variables_spec.rb
+++ b/spec/features/project_variables_spec.rb
@@ -12,32 +12,29 @@ RSpec.describe 'Project variables', :js do
sign_in(user)
project.add_maintainer(user)
project.variables << variable
- stub_feature_flags(new_variables_ui: false)
visit page_path
end
it_behaves_like 'variable list'
- it 'adds new variable with a special environment scope' do
- page.within('.js-ci-variable-list-section .js-row:last-child') do
- find('.js-ci-variable-input-key').set('somekey')
- find('.js-ci-variable-input-value').set('somevalue')
+ it 'adds a new variable with an environment scope' do
+ click_button('Add Variable')
- find('.js-variable-environment-toggle').click
- find('.js-variable-environment-dropdown-wrapper .dropdown-input-field').set('review/*')
- find('.js-variable-environment-dropdown-wrapper .js-dropdown-create-new-item').click
+ page.within('#add-ci-variable') do
+ find('[data-qa-selector="ci_variable_key_field"] input').set('akey')
+ find('#ci-variable-value').set('akey_value')
+ find('[data-testid="environment-scope"]').click
+ find_button('clear').click
+ find('[data-testid="ci-environment-search"]').set('review/*')
+ find('[data-testid="create-wildcard-button"]').click
- expect(find('input[name="variables[variables_attributes][][environment_scope]"]', visible: false).value).to eq('review/*')
+ click_button('Add variable')
end
- click_button('Save variables')
wait_for_requests
- visit page_path
-
- page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
- expect(find('.js-ci-variable-input-key').value).to eq('somekey')
- expect(page).to have_content('review/*')
+ page.within('.ci-variable-table') do
+ expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*')
end
end
end
diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb
index c30c8dda852..3f1c10b3688 100644
--- a/spec/features/projects/blobs/edit_spec.rb
+++ b/spec/features/projects/blobs/edit_spec.rb
@@ -179,12 +179,14 @@ RSpec.describe 'Editing file blob', :js do
end
context 'with protected branch' do
- before do
- visit project_edit_blob_path(project, tree_join(protected_branch, file_path))
- end
-
it 'shows blob editor with patch branch' do
- expect(find('.js-branch-name').value).to eq('patch-1')
+ freeze_time do
+ visit project_edit_blob_path(project, tree_join(protected_branch, file_path))
+
+ epoch = Time.now.strftime('%s%L').last(5)
+
+ expect(find('.js-branch-name').value).to eq "#{user.username}-protected-branch-patch-#{epoch}"
+ end
end
end
end
diff --git a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb
index fda2992af8d..6b9fd41059d 100644
--- a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb
+++ b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb
@@ -23,8 +23,6 @@ RSpec.describe 'User creates new blob', :js do
ide_commit
- click_button('Commit')
-
expect(page).to have_content('All changes are committed')
expect(project.repository.blob_at('master', 'dummy-file').data).to eql("Hello world\n")
end
diff --git a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
index 023e00a3e02..3069405ba63 100644
--- a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
+++ b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
@@ -10,7 +10,6 @@ RSpec.describe 'User follows pipeline suggest nudge spec when feature is enabled
describe 'viewing the new blob page' do
before do
- stub_experiment_for_user(suggest_pipeline: true)
sign_in(user)
end
diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb
new file mode 100644
index 00000000000..7012cc6edaa
--- /dev/null
+++ b/spec/features/projects/ci/editor_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Pipeline Editor', :js do
+ include Spec::Support::Helpers::Features::EditorLiteSpecHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ project.add_developer(user)
+
+ visit project_ci_pipeline_editor_path(project)
+ end
+
+ it 'user sees the Pipeline Editor page' do
+ expect(page).to have_content('Pipeline Editor')
+ end
+end
diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb
index eb2efb4357d..466c7ba215e 100644
--- a/spec/features/projects/ci/lint_spec.rb
+++ b/spec/features/projects/ci/lint_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe 'CI Lint', :js do
let(:content_selector) { '.content .view-lines' }
before do
- stub_feature_flags(ci_lint_vue: false)
project.add_developer(user)
sign_in(user)
@@ -26,7 +25,6 @@ RSpec.describe 'CI Lint', :js do
describe 'YAML parsing' do
shared_examples 'validates the YAML' do
before do
- stub_feature_flags(ci_lint_vue: false)
click_on 'Validate'
end
@@ -68,14 +66,6 @@ RSpec.describe 'CI Lint', :js do
it_behaves_like 'validates the YAML'
end
-
- describe 'YAML revalidate' do
- let(:yaml_content) { 'my yaml content' }
-
- it 'loads previous YAML content after validation' do
- expect(page).to have_field('content', with: 'my yaml content', visible: false, type: 'textarea')
- end
- end
end
describe 'YAML clearing' do
@@ -89,7 +79,7 @@ RSpec.describe 'CI Lint', :js do
end
it 'YAML content is cleared' do
- expect(page).to have_field('content', with: '', visible: false, type: 'textarea')
+ expect(page).to have_field(class: 'inputarea', with: '', visible: false, type: 'textarea')
end
end
end
diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb
index 7514a26f020..45bf35a6aab 100644
--- a/spec/features/projects/container_registry_spec.rb
+++ b/spec/features/projects/container_registry_spec.rb
@@ -10,6 +10,10 @@ RSpec.describe 'Container Registry', :js do
create(:container_repository, name: 'my/image')
end
+ let(:nameless_container_repository) do
+ create(:container_repository, name: '')
+ end
+
before do
sign_in(user)
project.add_developer(user)
@@ -96,6 +100,20 @@ RSpec.describe 'Container Registry', :js do
end
end
+ describe 'image repo details when image has no name' do
+ before do
+ stub_container_registry_tags(tags: %w[latest], with_manifest: true)
+ project.container_repositories << nameless_container_repository
+ visit_container_registry
+ end
+
+ it 'renders correctly' do
+ find('a[data-testid="details-link"]').click
+
+ expect(page).to have_content 'latest'
+ end
+ end
+
context 'when there are more than 10 images' do
before do
create_list(:container_repository, 12, project: project)
diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
index d28e31c08dc..42f8daf9d5e 100644
--- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
+++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
@@ -27,9 +27,7 @@ RSpec.describe 'Projects > Files > Project owner sees a link to create a license
ide_commit
- click_button('Commit')
-
- expect(current_path).to eq("/-/ide/project/#{project.full_path}/tree/master/-/")
+ expect(current_path).to eq("/-/ide/project/#{project.full_path}/tree/master/-/LICENSE/")
expect(page).to have_content('All changes are committed')
diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb
index a6126fbcb33..4e9e129042c 100644
--- a/spec/features/projects/files/user_browses_files_spec.rb
+++ b/spec/features/projects/files/user_browses_files_spec.rb
@@ -87,26 +87,22 @@ RSpec.describe "User browses files" do
end
it "shows correct files and links" do
- # rubocop:disable Lint/Void
- # Test the full URLs of links instead of relative paths by `have_link(text: "...", href: "...")`.
- find("a", text: /^empty$/)["href"] == project_tree_url(project, "markdown")
- find("a", text: /^#id$/)["href"] == project_tree_url(project, "markdown", anchor: "#id")
- find("a", text: %r{^/#id$})["href"] == project_tree_url(project, "markdown", anchor: "#id")
- find("a", text: /^README.md#id$/)["href"] == project_blob_url(project, "markdown/README.md", anchor: "#id")
- find("a", text: %r{^d/README.md#id$})["href"] == project_blob_url(project, "d/markdown/README.md", anchor: "#id")
- # rubocop:enable Lint/Void
-
expect(current_path).to eq(project_tree_path(project, "markdown"))
expect(page).to have_content("README.md")
- .and have_content("CHANGELOG")
- .and have_content("Welcome to GitLab GitLab is a free project and repository management application")
- .and have_link("GitLab API doc")
- .and have_link("GitLab API website")
- .and have_link("Rake tasks")
- .and have_link("backup and restore procedure")
- .and have_link("GitLab API doc directory")
- .and have_link("Maintenance")
- .and have_header_with_correct_id_and_link(2, "Application details", "application-details")
+ .and have_content("CHANGELOG")
+ .and have_content("Welcome to GitLab GitLab is a free project and repository management application")
+ .and have_link("GitLab API doc")
+ .and have_link("GitLab API website")
+ .and have_link("Rake tasks")
+ .and have_link("backup and restore procedure")
+ .and have_link("GitLab API doc directory")
+ .and have_link("Maintenance")
+ .and have_header_with_correct_id_and_link(2, "Application details", "application-details")
+ .and have_link("empty", href: "")
+ .and have_link("#id", href: "#id")
+ .and have_link("/#id", href: project_blob_path(project, "markdown/README.md", anchor: "id"))
+ .and have_link("README.md#id", href: project_blob_path(project, "markdown/README.md", anchor: "id"))
+ .and have_link("d/README.md#id", href: project_blob_path(project, "markdown/db/README.md", anchor: "id"))
end
it "shows correct content of file" do
@@ -114,10 +110,10 @@ RSpec.describe "User browses files" do
expect(current_path).to eq(project_blob_path(project, "markdown/doc/api/README.md"))
expect(page).to have_content("All API requests require authentication")
- .and have_content("Contents")
- .and have_link("Users")
- .and have_link("Rake tasks")
- .and have_header_with_correct_id_and_link(1, "GitLab API", "gitlab-api")
+ .and have_content("Contents")
+ .and have_link("Users")
+ .and have_link("Rake tasks")
+ .and have_header_with_correct_id_and_link(1, "GitLab API", "gitlab-api")
click_link("Users")
@@ -148,16 +144,13 @@ RSpec.describe "User browses files" do
click_link("d")
end
- # rubocop:disable Lint/Void
- # Test the full URLs of links instead of relative paths by `have_link(text: "...", href: "...")`.
- find("a", text: "..")["href"] == project_tree_url(project, "markdown/d")
- # rubocop:enable Lint/Void
+ expect(page).to have_link("..", href: project_tree_path(project, "markdown/"))
page.within(".tree-table") do
click_link("README.md")
end
- # Test the full URLs of links instead of relative paths by `have_link(text: "...", href: "...")`.
- find("a", text: /^empty$/)["href"] == project_blob_url(project, "markdown/d/README.md")
+
+ expect(page).to have_link("empty", href: "")
end
it "shows correct content of directory" do
diff --git a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
index de1fcc9d787..b5d5527bbfe 100644
--- a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
+++ b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe 'User uploads new design', :js do
end
def upload_design(fixture, count:)
- attach_file(:design_file, fixture, match: :first, make_visible: true)
+ attach_file(:upload_file, fixture, match: :first, make_visible: true)
wait_for('designs uploaded') do
issue.reload.designs.count == count
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 404c3e93586..e19337e1ff5 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -1013,7 +1013,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
before do
job.run!
visit project_job_path(project, job)
- find('.js-cancel-job').click
+ find('[data-testid="cancel-button"]').click
end
it 'loads the page and shows all needed controls' do
@@ -1030,7 +1030,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job)
wait_for_requests
- find('.js-retry-button').click
+ find('[data-testid="retry-button"]').click
end
it 'shows the right status and buttons' do
@@ -1057,6 +1057,31 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
end
end
end
+
+ context "Job that failed because of a forward deployment failure" do
+ let(:job) { create(:ci_build, :forward_deployment_failure, pipeline: pipeline) }
+
+ before do
+ visit project_job_path(project, job)
+ wait_for_requests
+
+ find('[data-testid="retry-button"]').click
+ end
+
+ it 'shows a modal to warn the user' do
+ page.within('.modal-header') do
+ expect(page).to have_content 'Are you sure you want to retry this job?'
+ end
+ end
+
+ it 'retries the job' do
+ find('[data-testid="retry-button-modal"]').click
+
+ within '[data-testid="ci-header-content"]' do
+ expect(page).to have_content('pending')
+ end
+ end
+ end
end
describe "GET /:project/jobs/:id/download", :js do
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index 4ff3827b240..25791b393bc 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -67,4 +67,23 @@ RSpec.describe 'Project navbar' do
it_behaves_like 'verified navigation bar'
end
+
+ context 'when invite team members is not available' do
+ it 'does not display the js-invite-members-trigger' do
+ visit project_path(project)
+
+ expect(page).not_to have_selector('.js-invite-members-trigger')
+ end
+ end
+
+ context 'when invite team members is available' do
+ it 'includes the div for js-invite-members-trigger' do
+ stub_feature_flags(invite_members_group_modal: true)
+ allow_any_instance_of(InviteMembersHelper).to receive(:invite_members_allowed?).and_return(true)
+
+ visit project_path(project)
+
+ expect(page).to have_selector('.js-invite-members-trigger')
+ end
+ end
end
diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb
index c3eea0195a6..11f712fde81 100644
--- a/spec/features/projects/pages_spec.rb
+++ b/spec/features/projects/pages_spec.rb
@@ -365,7 +365,7 @@ RSpec.shared_examples 'pages settings editing' do
end
let!(:artifact) do
- create(:ci_job_artifact, :archive,
+ create(:ci_job_artifact, :archive, :correct_checksum,
file: fixture_file_upload(File.join('spec/fixtures/pages.zip')), job: ci_build)
end
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 1e2cd3c0a69..94e3331b173 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'Pipeline Schedules', :js do
it 'displays the required information description' do
page.within('.pipeline-schedule-table-row') do
expect(page).to have_content('pipeline schedule')
- expect(find(".next-run-cell time")['data-original-title'])
+ expect(find(".next-run-cell time")['title'])
.to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
expect(page).to have_link('master')
expect(page).to have_link("##{pipeline.id}")
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 51826d867cd..ac3566fbbdd 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe 'Pipeline', :js do
before do
sign_in(user)
project.add_role(user, role)
+ stub_feature_flags(graphql_pipeline_details: false)
end
shared_context 'pipeline builds' do
@@ -345,7 +346,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows Pipeline, Jobs, DAG and Failed Jobs tabs with link' do
expect(page).to have_link('Pipeline')
expect(page).to have_link('Jobs')
- expect(page).to have_link('DAG')
+ expect(page).to have_link('Needs')
expect(page).to have_link('Failed Jobs')
end
@@ -892,7 +893,7 @@ RSpec.describe 'Pipeline', :js do
it 'shows Pipeline, Jobs and DAG tabs with link' do
expect(page).to have_link('Pipeline')
expect(page).to have_link('Jobs')
- expect(page).to have_link('DAG')
+ expect(page).to have_link('Needs')
end
it 'shows counter in Jobs tab' do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 3e78dfc3bc7..450524b8d70 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe 'Pipelines', :js do
before do
sign_in(user)
+ stub_feature_flags(graphql_pipeline_details: false)
project.add_developer(user)
project.update!(auto_devops_attributes: { enabled: false })
end
diff --git a/spec/features/projects/releases/user_views_edit_release_spec.rb b/spec/features/projects/releases/user_views_edit_release_spec.rb
index 9115a135aeb..bb54b6be9c4 100644
--- a/spec/features/projects/releases/user_views_edit_release_spec.rb
+++ b/spec/features/projects/releases/user_views_edit_release_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'User edits Release', :js do
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:release) { create(:release, project: project, name: 'The first release' ) }
+ let_it_be(:release) { create(:release, :with_milestones, milestones_count: 1, project: project, name: 'The first release' ) }
let_it_be(:user) { create(:user) }
before do
diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb
index 323c57570c3..aabbc8cea7b 100644
--- a/spec/features/projects/releases/user_views_releases_spec.rb
+++ b/spec/features/projects/releases/user_views_releases_spec.rb
@@ -3,8 +3,14 @@
require 'spec_helper'
RSpec.describe 'User views releases', :js do
+ let_it_be(:today) { Time.zone.now }
+ let_it_be(:yesterday) { today - 1.day }
+ let_it_be(:tomorrow) { today + 1.day }
+
let_it_be(:project) { create(:project, :repository, :private) }
- let_it_be(:release) { create(:release, project: project, name: 'The first release' ) }
+ let_it_be(:release_v1) { create(:release, project: project, tag: 'v1', name: 'The first release', released_at: yesterday, created_at: today) }
+ let_it_be(:release_v2) { create(:release, project: project, tag: 'v2-with-a/slash', name: 'The second release', released_at: today, created_at: yesterday) }
+ let_it_be(:release_v3) { create(:release, project: project, tag: 'v3', name: 'The third release', released_at: tomorrow, created_at: tomorrow) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:guest) { create(:user) }
@@ -17,38 +23,36 @@ RSpec.describe 'User views releases', :js do
context('when the user is a maintainer') do
before do
sign_in(maintainer)
- end
- it 'sees the release' do
visit project_releases_path(project)
+ end
- expect(page).to have_content(release.name)
- expect(page).to have_content(release.tag)
- expect(page).not_to have_content('Upcoming Release')
+ it 'sees the release' do
+ page.within("##{release_v1.tag}") do
+ expect(page).to have_content(release_v1.name)
+ expect(page).to have_content(release_v1.tag)
+ expect(page).not_to have_content('Upcoming Release')
+ end
end
context 'when there is a link as an asset' do
- let!(:release_link) { create(:release_link, release: release, url: url ) }
+ let!(:release_link) { create(:release_link, release: release_v1, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
- let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath }
+ let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{release_link.filepath}" }
it 'sees the link' do
- visit project_releases_path(project)
-
- page.within('.js-assets-list') do
+ page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
end
end
context 'when there is a link redirect' do
- let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
+ let!(:release_link) { create(:release_link, release: release_v1, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
it 'sees the link' do
- visit project_releases_path(project)
-
- page.within('.js-assets-list') do
+ page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
end
@@ -59,9 +63,7 @@ RSpec.describe 'User views releases', :js do
let(:url) { 'http://google.com/download' }
it 'sees that the link is external resource' do
- visit project_releases_path(project)
-
- page.within('.js-assets-list') do
+ page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_css('[data-testid="external-link-indicator"]')
end
end
@@ -69,23 +71,57 @@ RSpec.describe 'User views releases', :js do
end
context 'with an upcoming release' do
- let(:tomorrow) { Time.zone.now + 1.day }
- let!(:release) { create(:release, project: project, released_at: tomorrow ) }
-
it 'sees the upcoming tag' do
- visit project_releases_path(project)
-
- expect(page).to have_content('Upcoming Release')
+ page.within("##{release_v3.tag}") do
+ expect(page).to have_content('Upcoming Release')
+ end
end
end
context 'with a tag containing a slash' do
it 'sees the release' do
- release = create :release, project: project, tag: 'debian/2.4.0-1'
- visit project_releases_path(project)
+ page.within("##{release_v2.tag.parameterize}") do
+ expect(page).to have_content(release_v2.name)
+ expect(page).to have_content(release_v2.tag)
+ end
+ end
+ end
+
+ context 'sorting' do
+ def sort_page(by:, direction:)
+ within '[data-testid="releases-sort"]' do
+ find('.dropdown-toggle').click
+
+ click_button(by, class: 'dropdown-item')
+
+ find('.sorting-direction-button').click if direction == :ascending
+ end
+ end
+
+ shared_examples 'releases sort order' do
+ it "sorts the releases #{description}" do
+ card_titles = page.all('.release-block .card-title', minimum: expected_releases.count)
+
+ card_titles.each_with_index do |title, index|
+ expect(title).to have_content(expected_releases[index].name)
+ end
+ end
+ end
+
+ context "when the page is sorted by the default sort order" do
+ let(:expected_releases) { [release_v3, release_v2, release_v1] }
+
+ it_behaves_like 'releases sort order'
+ end
+
+ context "when the page is sorted by created_at ascending " do
+ let(:expected_releases) { [release_v2, release_v1, release_v3] }
+
+ before do
+ sort_page by: 'Created date', direction: :ascending
+ end
- expect(page).to have_content(release.name)
- expect(page).to have_content(release.tag)
+ it_behaves_like 'releases sort order'
end
end
end
@@ -98,14 +134,14 @@ RSpec.describe 'User views releases', :js do
it 'renders release info except for Git-related data' do
visit project_releases_path(project)
- within('.release-block') do
- expect(page).to have_content(release.description)
+ within('.release-block', match: :first) do
+ expect(page).to have_content(release_v3.description)
# The following properties (sometimes) include Git info,
# so they are not rendered for Guest users
- expect(page).not_to have_content(release.name)
- expect(page).not_to have_content(release.tag)
- expect(page).not_to have_content(release.commit.short_id)
+ expect(page).not_to have_content(release_v3.name)
+ expect(page).not_to have_content(release_v3.tag)
+ expect(page).not_to have_content(release_v3.commit.short_id)
end
end
end
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 4e1b53ffc87..cb333bdb428 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -15,10 +15,10 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
before do
project.update!(container_registry_enabled: container_registry_enabled_on_project)
+ project.container_expiration_policy.update!(enabled: true)
sign_in(user)
stub_container_registry_config(enabled: container_registry_enabled)
- stub_feature_flags(new_variables_ui: false)
end
context 'as owner' do
@@ -33,13 +33,13 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
subject
within '#js-registry-policies' do
- within '.card-body' do
+ within '.gl-card-body' do
select('7 days until tags are automatically removed', from: 'Expiration interval:')
select('Every day', from: 'Expiration schedule:')
select('50 tags per image name', from: 'Number of tags to retain:')
fill_in('Tags with names matching this regex pattern will expire:', with: '.*-production')
end
- submit_button = find('.card-footer .btn.btn-success')
+ submit_button = find('.gl-card-footer .btn.btn-success')
expect(submit_button).not_to be_disabled
submit_button.click
end
@@ -51,10 +51,10 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
subject
within '#js-registry-policies' do
- within '.card-body' do
+ within '.gl-card-body' do
fill_in('Tags with names matching this regex pattern will expire:', with: '*-production')
end
- submit_button = find('.card-footer .btn.btn-success')
+ submit_button = find('.gl-card-footer .btn.btn-success')
expect(submit_button).not_to be_disabled
submit_button.click
end
@@ -85,7 +85,7 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
within '#js-registry-policies' do
case result
when :available_section
- expect(find('.card-header')).to have_content('Tag expiration policy')
+ expect(find('.gl-card-header')).to have_content('Tag expiration policy')
when :disabled_message
expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled')
end
diff --git a/spec/features/projects/settings/service_desk_setting_spec.rb b/spec/features/projects/settings/service_desk_setting_spec.rb
index 7856ab1fb4e..59e6f54da2f 100644
--- a/spec/features/projects/settings/service_desk_setting_spec.rb
+++ b/spec/features/projects/settings/service_desk_setting_spec.rb
@@ -28,6 +28,6 @@ RSpec.describe 'Service Desk Setting', :js do
project.reload
expect(project.service_desk_enabled).to be_truthy
expect(project.service_desk_address).to be_present
- expect(find('.incoming-email').value).to eq(project.service_desk_address)
+ expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_address)
end
end
diff --git a/spec/features/projects/settings/webhooks_settings_spec.rb b/spec/features/projects/settings/webhooks_settings_spec.rb
index d184f08bd89..528fd58cbe6 100644
--- a/spec/features/projects/settings/webhooks_settings_spec.rb
+++ b/spec/features/projects/settings/webhooks_settings_spec.rb
@@ -45,6 +45,7 @@ RSpec.describe 'Projects > Settings > Webhook Settings' do
expect(page).to have_content('Merge requests events')
expect(page).to have_content('Pipeline events')
expect(page).to have_content('Wiki page events')
+ expect(page).to have_content('Releases events')
end
it 'create webhook' do
diff --git a/spec/features/projects/show/schema_markup_spec.rb b/spec/features/projects/show/schema_markup_spec.rb
new file mode 100644
index 00000000000..e651798af23
--- /dev/null
+++ b/spec/features/projects/show/schema_markup_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Projects > Show > Schema Markup' do
+ let_it_be(:project) { create(:project, :repository, :public, :with_avatar, description: 'foobar', tag_list: 'tag1, tag2') }
+
+ it 'shows SoftwareSourceCode structured markup', :js do
+ visit project_path(project)
+ wait_for_all_requests
+
+ aggregate_failures do
+ expect(page).to have_selector('[itemscope][itemtype="http://schema.org/SoftwareSourceCode"]')
+ expect(page).to have_selector('img[itemprop="image"]')
+ expect(page).to have_selector('[itemprop="name"]', text: project.name)
+ expect(page).to have_selector('[itemprop="identifier"]', text: "Project ID: #{project.id}")
+ expect(page).to have_selector('[itemprop="abstract"]', text: project.description)
+ expect(page).to have_selector('[itemprop="license"]', text: project.repository.license.name)
+ expect(find_all('[itemprop="keywords"]').map(&:text)).to match_array(project.tag_list.map(&:capitalize))
+ expect(page).to have_selector('[itemprop="about"]')
+ end
+ end
+end
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index 28fe0a0b7e1..0ed9e23c7f8 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe 'Projects > Snippets > Create Snippet', :js do
click_button('Create snippet')
wait_for_requests
- link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
+ link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
end
diff --git a/spec/features/projects/terraform_spec.rb b/spec/features/projects/terraform_spec.rb
new file mode 100644
index 00000000000..2680dfb2b13
--- /dev/null
+++ b/spec/features/projects/terraform_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Terraform', :js do
+ let_it_be(:project) { create(:project) }
+
+ let(:user) { project.creator }
+
+ before do
+ gitlab_sign_in(user)
+ end
+
+ context 'when user does not have any terraform states and visits index page' do
+ before do
+ visit project_terraform_index_path(project)
+ end
+
+ it 'sees an empty state' do
+ expect(page).to have_content('Get started with Terraform')
+ end
+ end
+
+ context 'when user has a terraform state' do
+ let_it_be(:terraform_state) { create(:terraform_state, :locked, project: project) }
+
+ context 'when user visits the index page' do
+ before do
+ visit project_terraform_index_path(project)
+ end
+
+ it 'displays a tab with states count' do
+ expect(page).to have_content("States #{project.terraform_states.size}")
+ end
+
+ it 'displays a table with terraform states' do
+ expect(page).to have_selector(
+ '[data-testid="terraform-states-table"] tbody tr',
+ count: project.terraform_states.size
+ )
+ end
+
+ it 'displays terraform information' do
+ expect(page).to have_content(terraform_state.name)
+ end
+ end
+ end
+end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 6baeb4ce368..9b5f4ca6d48 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -279,7 +279,7 @@ RSpec.describe 'Project' do
end
it 'deletes a project', :sidekiq_might_not_need_inline do
- expect { remove_with_confirm('Delete project', "Delete #{project.full_name}", 'Yes, delete project') }.to change { Project.count }.by(-1)
+ expect { remove_with_confirm('Delete project', project.path, 'Yes, delete project') }.to change { Project.count }.by(-1)
expect(page).to have_content "Project '#{project.full_name}' is in the process of being deleted."
expect(Project.all.count).to be_zero
expect(project.issues).to be_empty
diff --git a/spec/features/read_only_spec.rb b/spec/features/read_only_spec.rb
index eb043d2193a..11686552062 100644
--- a/spec/features/read_only_spec.rb
+++ b/spec/features/read_only_spec.rb
@@ -9,19 +9,19 @@ RSpec.describe 'read-only message' do
sign_in(user)
end
- it 'shows read-only banner when database is read-only' do
- allow(Gitlab::Database).to receive(:read_only?).and_return(true)
+ context 'when database is read-only' do
+ before do
+ allow(Gitlab::Database).to receive(:read_only?).and_return(true)
+ end
- visit root_dashboard_path
-
- expect(page).to have_content('You are on a read-only GitLab instance.')
+ it_behaves_like 'Read-only instance', /You are on a read\-only GitLab instance./
end
- it 'does not show read-only banner when database is able to read-write' do
- allow(Gitlab::Database).to receive(:read_only?).and_return(false)
-
- visit root_dashboard_path
+ context 'when database is in read-write mode' do
+ before do
+ allow(Gitlab::Database).to receive(:read_only?).and_return(false)
+ end
- expect(page).not_to have_content('You are on a read-only GitLab instance.')
+ it_behaves_like 'Read-write instance', /You are on a read\-only GitLab instance./
end
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 6e18de3be7b..9697e10c3d1 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -122,6 +122,19 @@ RSpec.describe 'Runners' do
end
end
+ context 'when multiple runners are configured' do
+ let!(:specific_runner) { create(:ci_runner, :project, projects: [project]) }
+ let!(:specific_runner_2) { create(:ci_runner, :project, projects: [project]) }
+
+ it 'adds pagination to the runner list' do
+ stub_const('Projects::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE', 1)
+
+ visit project_runners_path(project)
+
+ expect(find('.pagination')).not_to be_nil
+ end
+ end
+
context 'when a specific runner exists in another project' do
let(:another_project) { create(:project) }
let!(:specific_runner) { create(:ci_runner, :project, projects: [another_project]) }
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index a88043c98ac..f761bd30baf 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -28,10 +28,7 @@ RSpec.describe 'User searches for code' do
before do
visit(search_path)
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
end
include_examples 'top right search form'
diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb
index 900ed35adea..e2ae2738d2f 100644
--- a/spec/features/search/user_searches_for_issues_spec.rb
+++ b/spec/features/search/user_searches_for_issues_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'User searches for issues', :js do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
- let!(:issue1) { create(:issue, title: 'Foo', project: project) }
- let!(:issue2) { create(:issue, :closed, :confidential, title: 'Bar', project: project) }
+ let!(:issue1) { create(:issue, title: 'issue Foo', project: project, created_at: 1.hour.ago) }
+ let!(:issue2) { create(:issue, :closed, :confidential, title: 'issue Bar', project: project) }
def search_for_issue(search)
fill_in('dashboard_search', with: search)
@@ -67,13 +67,26 @@ RSpec.describe 'User searches for issues', :js do
end
end
+ it 'sorts by created date' do
+ search_for_issue('issue')
+
+ page.within('.results') do
+ expect(page.all('.search-result-row').first).to have_link(issue2.title)
+ expect(page.all('.search-result-row').last).to have_link(issue1.title)
+ end
+
+ find('.reverse-sort-btn').click
+
+ page.within('.results') do
+ expect(page.all('.search-result-row').first).to have_link(issue1.title)
+ expect(page.all('.search-result-row').last).to have_link(issue2.title)
+ end
+ end
+
context 'when on a project page' do
it 'finds an issue' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
search_for_issue(issue1.title)
diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb
index 40583664958..6f8f6303b66 100644
--- a/spec/features/search/user_searches_for_merge_requests_spec.rb
+++ b/spec/features/search/user_searches_for_merge_requests_spec.rb
@@ -31,10 +31,7 @@ RSpec.describe 'User searches for merge requests', :js do
context 'when on a project page' do
it 'finds a merge request' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
fill_in('dashboard_search', with: merge_request1.title)
find('.btn-search').click
diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb
index 64e756db180..1a2227db214 100644
--- a/spec/features/search/user_searches_for_milestones_spec.rb
+++ b/spec/features/search/user_searches_for_milestones_spec.rb
@@ -31,10 +31,7 @@ RSpec.describe 'User searches for milestones', :js do
context 'when on a project page' do
it 'finds a milestone' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
fill_in('dashboard_search', with: milestone1.title)
find('.btn-search').click
diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb
index fc60b6244d9..6bf1407fd4f 100644
--- a/spec/features/search/user_searches_for_wiki_pages_spec.rb
+++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb
@@ -19,10 +19,7 @@ RSpec.describe 'User searches for wiki pages', :js do
shared_examples 'search wiki blobs' do
it 'finds a page' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
fill_in('dashboard_search', with: search_term)
find('.btn-search').click
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 5cbfacf4e48..9296a3f33d4 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -5,11 +5,18 @@ require 'spec_helper'
RSpec.describe 'User uses header search field', :js do
include FilteredSearchHelpers
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+
+ let(:user) { reporter }
+
+ before_all do
+ project.add_reporter(reporter)
+ project.add_developer(developer)
+ end
before do
- project.add_reporter(user)
sign_in(user)
end
@@ -34,7 +41,7 @@ RSpec.describe 'User uses header search field', :js do
wait_for_all_requests
end
- it 'shows the category search dropdown' do
+ 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)
end
end
@@ -44,7 +51,7 @@ RSpec.describe 'User uses header search field', :js do
page.find('#search').click
end
- it 'shows category search dropdown' do
+ 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)
end
@@ -104,7 +111,7 @@ RSpec.describe 'User uses header search field', :js do
let(:scope_name) { 'All GitLab' }
end
- it 'displays search options' do
+ it 'displays search options', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/251076' do
fill_in_search('test')
expect(page).to have_selector(scoped_search_link('test'))
@@ -132,6 +139,10 @@ RSpec.describe 'User uses header search field', :js do
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
+ before do
+ project.add_reporter(user)
+ end
+
include_examples 'search field examples' do
let(:url) { project_path(project) }
let(:scope_name) { project.name }
@@ -159,6 +170,35 @@ RSpec.describe 'User uses header search field', :js do
expect(page).not_to have_selector(scoped_search_link('test', group_id: project.namespace_id))
expect(page).to have_selector(scoped_search_link('test', project_id: project.id))
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')
+ 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')
+ end
+ end
+
+ context 'and user is a developer' do
+ let(:user) { developer }
+
+ 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')
+ end
+ end
+ end
end
end
@@ -217,4 +257,8 @@ RSpec.describe 'User uses header search field', :js do
".dropdown a[href='#{href}']"
end
+
+ def dashboard_search_options_popup_menu
+ "div[data-testid='dashboard-search-options']"
+ end
end
diff --git a/spec/features/search/user_uses_search_filters_spec.rb b/spec/features/search/user_uses_search_filters_spec.rb
index 080cced21c3..bd77e6003e3 100644
--- a/spec/features/search/user_uses_search_filters_spec.rb
+++ b/spec/features/search/user_uses_search_filters_spec.rb
@@ -18,17 +18,17 @@ RSpec.describe 'User uses search filters', :js do
it 'shows group projects' do
visit search_path
- find('.js-search-group-dropdown').click
+ find('[data-testid="group-filter"]').click
wait_for_requests
- page.within('.search-page-form') do
- click_link(group.name)
+ page.within('[data-testid="group-filter"]') do
+ click_on(group.name)
end
- expect(find('.js-search-group-dropdown')).to have_content(group.name)
+ expect(find('[data-testid="group-filter"]')).to have_content(group.name)
- page.within('.project-filter') do
+ page.within('[data-testid="project-filter"]') do
find('.js-search-project-dropdown').click
wait_for_requests
@@ -44,10 +44,11 @@ RSpec.describe 'User uses search filters', :js do
describe 'clear filter button' do
it 'removes Group and Project filters' do
- link = find('[data-testid="group-filter"] .js-search-clear')
- params = CGI.parse(URI.parse(link[:href]).query)
+ find('[data-testid="group-filter"] [data-testid="clear-icon"]').click
+
+ wait_for_requests
- expect(params).not_to include(:group_id, :project_id)
+ expect(page).to have_current_path(search_path(search: "test"))
end
end
end
@@ -57,7 +58,7 @@ RSpec.describe 'User uses search filters', :js do
it 'shows a project' do
visit search_path
- page.within('.project-filter') do
+ page.within('[data-testid="project-filter"]') do
find('.js-search-project-dropdown').click
wait_for_requests
@@ -77,7 +78,7 @@ RSpec.describe 'User uses search filters', :js do
describe 'clear filter button' do
it 'removes Project filters' do
- link = find('.project-filter .js-search-clear')
+ link = find('[data-testid="project-filter"] .js-search-clear')
params = CGI.parse(URI.parse(link[:href]).query)
expect(params).not_to include(:project_id)
diff --git a/spec/features/static_site_editor_spec.rb b/spec/features/static_site_editor_spec.rb
index 03085917d67..a47579582e2 100644
--- a/spec/features/static_site_editor_spec.rb
+++ b/spec/features/static_site_editor_spec.rb
@@ -73,4 +73,44 @@ RSpec.describe 'Static Site Editor' do
expect(node['data-static-site-generator']).to eq('middleman')
end
end
+
+ describe 'Static Site Editor Content Security Policy' do
+ subject { response_headers['Content-Security-Policy'] }
+
+ context 'when no global CSP config exists' do
+ before do
+ expect_next_instance_of(Projects::StaticSiteEditorController) do |controller|
+ expect(controller).to receive(:current_content_security_policy)
+ .and_return(ActionDispatch::ContentSecurityPolicy.new)
+ end
+ end
+
+ it 'does not add CSP directives' do
+ visit sse_path
+
+ is_expected.to be_blank
+ end
+ end
+
+ context 'when a global CSP config exists' do
+ let_it_be(:cdn_url) { 'https://some-cdn.test' }
+ let_it_be(:youtube_url) { 'https://www.youtube.com' }
+
+ before do
+ csp = ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.frame_src :self, cdn_url
+ end
+
+ expect_next_instance_of(Projects::StaticSiteEditorController) do |controller|
+ expect(controller).to receive(:current_content_security_policy).and_return(csp)
+ end
+ end
+
+ it 'appends youtube to the CSP frame-src policy' do
+ visit sse_path
+
+ is_expected.to eql("frame-src 'self' #{cdn_url} #{youtube_url}")
+ end
+ end
+ end
end
diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb
index 7f55ddc1d64..589cc9f9b02 100644
--- a/spec/features/uploads/user_uploads_file_to_note_spec.rb
+++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb
@@ -58,8 +58,8 @@ RSpec.describe 'User uploads file to note' do
error_text = 'File is too big (0.06MiB). Max filesize: 0.01MiB.'
expect(page).to have_selector('.uploading-error-message', visible: true, text: error_text)
- expect(page).to have_selector('.retry-uploading-link', visible: true, text: 'Try again')
- expect(page).to have_selector('.attach-new-file', visible: true, text: 'attach a new file')
+ expect(page).to have_button('Try again', visible: true)
+ expect(page).to have_button('attach a new file', visible: true)
expect(page).not_to have_button('Attach a file')
end
end
@@ -78,7 +78,7 @@ RSpec.describe 'User uploads file to note' do
click_button 'Comment'
wait_for_requests
- expect(find('a.no-attachment-icon img[alt="dk"]')['src'])
+ expect(find('a.no-attachment-icon img.js-lazy-loaded[alt="dk"]')['src'])
.to match(%r{/#{project.full_path}/uploads/\h{32}/dk\.png$})
end
end
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 853c381fe6b..0761c1871d3 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -26,7 +26,6 @@ RSpec.describe 'Login' do
user.reload
expect(user.reset_password_token).not_to be_nil
- find('a[href="#login-pane"]').click
gitlab_sign_in(user)
expect(current_path).to eq root_path
@@ -593,42 +592,95 @@ RSpec.describe 'Login' do
describe 'UI tabs and panes' do
context 'when no defaults are changed' do
- it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness
+ it 'does not render any tabs' do
+ visit new_user_session_path
+
+ ensure_no_tabs
+ end
+
+ it 'renders link to sign up path' do
+ visit new_user_session_path
+
+ expect(page.body).to have_link('Register now', href: new_user_registration_path)
end
end
context 'when signup is disabled' do
before do
stub_application_setting(signup_enabled: false)
+
+ visit new_user_session_path
end
- it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness
+ it 'does not render any tabs' do
+ ensure_no_tabs
+ end
+
+ it 'does not render link to sign up path' do
+ visit new_user_session_path
+
+ expect(page.body).not_to have_link('Register now', href: new_user_registration_path)
end
end
context 'when ldap is enabled' do
+ include LdapHelpers
+
+ let(:provider) { 'ldapmain' }
+ let(:ldap_server_config) do
+ {
+ 'label' => 'Main LDAP',
+ 'provider_name' => provider,
+ 'attributes' => {},
+ 'encryption' => 'plain',
+ 'uid' => 'uid',
+ 'base' => 'dc=example,dc=com'
+ }
+ end
+
before do
+ stub_ldap_setting(enabled: true)
+ allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config])
+ allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym])
+
+ Ldap::OmniauthCallbacksController.define_providers!
+ Rails.application.reload_routes!
+
+ allow_next_instance_of(ActionDispatch::Routing::RoutesProxy) do |instance|
+ allow(instance).to receive(:"user_#{provider}_omniauth_callback_path")
+ .and_return("/users/auth/#{provider}/callback")
+ end
+
visit new_user_session_path
- allow(page).to receive(:form_based_providers).and_return([:ldapmain])
- allow(page).to receive(:ldap_enabled).and_return(true)
end
it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness(false)
+ ensure_tab_pane_correctness(['Main LDAP', 'Standard'])
+ end
+
+ it 'renders link to sign up path' do
+ expect(page.body).to have_link('Register now', href: new_user_registration_path)
end
end
context 'when crowd is enabled' do
before do
+ allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [:crowd])
+ stub_application_setting(crowd_enabled: true)
+
+ Ldap::OmniauthCallbacksController.define_providers!
+ Rails.application.reload_routes!
+
+ allow_next_instance_of(ActionDispatch::Routing::RoutesProxy) do |instance|
+ allow(instance).to receive(:user_crowd_omniauth_authorize_path)
+ .and_return("/users/auth/crowd/callback")
+ end
+
visit new_user_session_path
- allow(page).to receive(:form_based_providers).and_return([:crowd])
- allow(page).to receive(:crowd_enabled?).and_return(true)
end
it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness(false)
+ ensure_tab_pane_correctness(%w(Crowd Standard))
end
end
end
diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb
index 466b7361da9..aebe2cc602d 100644
--- a/spec/features/users/show_spec.rb
+++ b/spec/features/users/show_spec.rb
@@ -5,11 +5,13 @@ require 'spec_helper'
RSpec.describe 'User page' do
include ExternalAuthorizationServiceHelpers
- let(:user) { create(:user, bio: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') }
+ let_it_be(:user) { create(:user, bio: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') }
+
+ subject { visit(user_path(user)) }
context 'with public profile' do
it 'shows all the tabs' do
- visit(user_path(user))
+ subject
page.within '.nav-links' do
expect(page).to have_link('Overview')
@@ -22,14 +24,12 @@ RSpec.describe 'User page' do
end
it 'does not show private profile message' do
- visit(user_path(user))
+ subject
expect(page).not_to have_content("This user has a private profile")
end
context 'work information' do
- subject { visit(user_path(user)) }
-
it 'shows job title and organization details' do
user.update(organization: 'GitLab - work info test', job_title: 'Frontend Engineer')
@@ -57,24 +57,24 @@ RSpec.describe 'User page' do
end
context 'with private profile' do
- let(:user) { create(:user, private_profile: true) }
+ let_it_be(:user) { create(:user, private_profile: true) }
it 'shows no tab' do
- visit(user_path(user))
+ subject
expect(page).to have_css("div.profile-header")
expect(page).not_to have_css("ul.nav-links")
end
it 'shows private profile message' do
- visit(user_path(user))
+ subject
expect(page).to have_content("This user has a private profile")
end
it 'shows own tabs' do
sign_in(user)
- visit(user_path(user))
+ subject
page.within '.nav-links' do
expect(page).to have_link('Overview')
@@ -88,36 +88,36 @@ RSpec.describe 'User page' do
end
context 'with blocked profile' do
- let(:user) { create(:user, state: :blocked) }
+ let_it_be(:user) { create(:user, state: :blocked) }
it 'shows no tab' do
- visit(user_path(user))
+ subject
expect(page).to have_css("div.profile-header")
expect(page).not_to have_css("ul.nav-links")
end
it 'shows blocked message' do
- visit(user_path(user))
+ subject
expect(page).to have_content("This user is blocked")
end
it 'shows user name as blocked' do
- visit(user_path(user))
+ subject
expect(page).to have_css(".cover-title", text: 'Blocked user')
end
it 'shows no additional fields' do
- visit(user_path(user))
+ subject
expect(page).not_to have_css(".profile-user-bio")
expect(page).not_to have_css(".profile-link-holder")
end
it 'shows username' do
- visit(user_path(user))
+ subject
expect(page).to have_content("@#{user.username}")
end
@@ -126,7 +126,7 @@ RSpec.describe 'User page' do
it 'shows the status if there was one' do
create(:user_status, user: user, message: "Working hard!")
- visit(user_path(user))
+ subject
expect(page).to have_content("Working hard!")
end
@@ -135,7 +135,7 @@ RSpec.describe 'User page' do
it 'shows the sign in link' do
stub_application_setting(signup_enabled: false)
- visit(user_path(user))
+ subject
page.within '.navbar-nav' do
expect(page).to have_link('Sign in')
@@ -147,7 +147,7 @@ RSpec.describe 'User page' do
it 'shows the sign in and register link' do
stub_application_setting(signup_enabled: true)
- visit(user_path(user))
+ subject
page.within '.navbar-nav' do
expect(page).to have_link('Sign in / Register')
@@ -157,7 +157,7 @@ RSpec.describe 'User page' do
context 'most recent activity' do
it 'shows the most recent activity' do
- visit(user_path(user))
+ subject
expect(page).to have_content('Most Recent Activity')
end
@@ -168,7 +168,7 @@ RSpec.describe 'User page' do
end
it 'hides the most recent activity' do
- visit(user_path(user))
+ subject
expect(page).not_to have_content('Most Recent Activity')
end
@@ -177,14 +177,14 @@ RSpec.describe 'User page' do
context 'page description' do
before do
- visit(user_path(user))
+ subject
end
it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet'
end
context 'with a bot user' do
- let(:user) { create(:user, user_type: :security_bot) }
+ let_it_be(:user) { create(:user, user_type: :security_bot) }
describe 'feature flag enabled' do
before do
@@ -192,7 +192,7 @@ RSpec.describe 'User page' do
end
it 'only shows Overview and Activity tabs' do
- visit(user_path(user))
+ subject
page.within '.nav-links' do
expect(page).to have_link('Overview')
@@ -211,7 +211,7 @@ RSpec.describe 'User page' do
end
it 'only shows Overview and Activity tabs' do
- visit(user_path(user))
+ subject
page.within '.nav-links' do
expect(page).to have_link('Overview')
@@ -224,4 +224,24 @@ RSpec.describe 'User page' do
end
end
end
+
+ context 'structured markup' do
+ let_it_be(:user) { create(:user, website_url: 'https://gitlab.com', organization: 'GitLab', job_title: 'Frontend Engineer', email: 'public@example.com', public_email: 'public@example.com', location: 'Country', created_at: Time.now, updated_at: Time.now) }
+
+ it 'shows Person structured markup' do
+ subject
+
+ aggregate_failures do
+ expect(page).to have_selector('[itemscope][itemtype="http://schema.org/Person"]')
+ expect(page).to have_selector('img[itemprop="image"]')
+ expect(page).to have_selector('[itemprop="name"]')
+ expect(page).to have_selector('[itemprop="address"][itemscope][itemtype="https://schema.org/PostalAddress"]')
+ expect(page).to have_selector('[itemprop="addressLocality"]')
+ expect(page).to have_selector('[itemprop="url"]')
+ expect(page).to have_selector('[itemprop="email"]')
+ expect(page).to have_selector('span[itemprop="jobTitle"]')
+ expect(page).to have_selector('span[itemprop="worksFor"]')
+ end
+ end
+ end
end
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index c59121626f0..bfdd1e1bdb7 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -2,9 +2,51 @@
require 'spec_helper'
-RSpec.shared_examples 'Signup' do
+RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
+ before do
+ visit new_user_registration_path
+ end
+
+ describe "#{field} validation", :js do
+ it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do
+ fill_in field, with: 'u' * max_length
+
+ expect(find('.name')).not_to have_css '.gl-field-error-outline'
+ end
+
+ it 'shows an error border if the user\'s fullname contains an emoji' do
+ simulate_input("##{field}", 'Ehsan 🦋')
+
+ expect(find('.name')).to have_css '.gl-field-error-outline'
+ end
+
+ it "shows an error border if the user\'s fullname is longer than #{max_length} characters" do
+ fill_in field, with: 'n' * (max_length + 1)
+
+ expect(find('.name')).to have_css '.gl-field-error-outline'
+ end
+
+ it "shows an error message if the user\'s #{label} is longer than #{max_length} characters" do
+ fill_in field, with: 'n' * (max_length + 1)
+
+ expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).")
+ end
+
+ it 'shows an error message if the username contains emojis' do
+ simulate_input("##{field}", 'Ehsan 🦋')
+
+ expect(page).to have_content("Invalid input, please avoid emojis")
+ end
+ end
+end
+
+RSpec.describe 'Signup' do
include TermsHelper
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: false)
+ end
+
let(:new_user) { build_stubbed(:user) }
def fill_in_signup_form
@@ -190,6 +232,22 @@ RSpec.shared_examples 'Signup' do
expect(current_path).to eq users_sign_up_welcome_path
end
end
+
+ context 'with required admin approval enabled' do
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: true)
+ end
+
+ it 'creates the user but does not sign them in' do
+ visit new_user_registration_path
+
+ fill_in_signup_form
+
+ expect { click_button 'Register' }.to change { User.count }.by(1)
+ expect(current_path).to eq new_user_session_path
+ expect(page).to have_content("You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator")
+ end
+ end
end
context 'with errors' do
@@ -295,64 +353,7 @@ RSpec.shared_examples 'Signup' do
expect(created_user.setup_for_company).to be_nil
expect(page).to have_current_path(new_project_path)
end
-end
-
-RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
- before do
- visit new_user_registration_path
- end
-
- describe "#{field} validation", :js do
- it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do
- fill_in field, with: 'u' * max_length
-
- expect(find('.name')).not_to have_css '.gl-field-error-outline'
- end
-
- it 'shows an error border if the user\'s fullname contains an emoji' do
- simulate_input("##{field}", 'Ehsan 🦋')
-
- expect(find('.name')).to have_css '.gl-field-error-outline'
- end
-
- it "shows an error border if the user\'s fullname is longer than #{max_length} characters" do
- fill_in field, with: 'n' * (max_length + 1)
-
- expect(find('.name')).to have_css '.gl-field-error-outline'
- end
-
- it "shows an error message if the user\'s #{label} is longer than #{max_length} characters" do
- fill_in field, with: 'n' * (max_length + 1)
-
- expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).")
- end
-
- it 'shows an error message if the username contains emojis' do
- simulate_input("##{field}", 'Ehsan 🦋')
-
- expect(page).to have_content("Invalid input, please avoid emojis")
- end
- end
-end
-
-RSpec.describe 'With original flow' do
- before do
- stub_experiment(signup_flow: false)
- stub_experiment_for_user(signup_flow: false)
- end
-
- it_behaves_like 'Signup'
- it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
- it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
-end
-
-RSpec.describe 'With experimental flow' do
- before do
- stub_experiment(signup_flow: true)
- stub_experiment_for_user(signup_flow: true)
- end
- it_behaves_like 'Signup'
it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
end