summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/admin/admin_broadcast_messages_spec.rb7
-rw-r--r--spec/features/admin/admin_dev_ops_reports_spec.rb (renamed from spec/features/admin/admin_dev_ops_report_spec.rb)10
-rw-r--r--spec/features/admin/admin_runners_spec.rb292
-rw-r--r--spec/features/admin/admin_sees_background_migrations_spec.rb10
-rw-r--r--spec/features/admin/admin_settings_spec.rb93
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb4
-rw-r--r--spec/features/admin/clusters/eks_spec.rb4
-rw-r--r--spec/features/boards/boards_spec.rb2
-rw-r--r--spec/features/boards/focus_mode_spec.rb2
-rw-r--r--spec/features/boards/multi_select_spec.rb6
-rw-r--r--spec/features/clusters/create_agent_spec.rb4
-rw-r--r--spec/features/commit_spec.rb4
-rw-r--r--spec/features/commits_spec.rb3
-rw-r--r--spec/features/error_tracking/user_searches_sentry_errors_spec.rb2
-rw-r--r--spec/features/groups/clusters/eks_spec.rb4
-rw-r--r--spec/features/groups/clusters/user_spec.rb3
-rw-r--r--spec/features/groups/group_runners_spec.rb168
-rw-r--r--spec/features/groups/import_export/export_file_spec.rb16
-rw-r--r--spec/features/groups/members/manage_groups_spec.rb149
-rw-r--r--spec/features/groups/members/manage_members_spec.rb139
-rw-r--r--spec/features/groups/members/sort_members_spec.rb40
-rw-r--r--spec/features/groups/milestone_spec.rb2
-rw-r--r--spec/features/groups/milestones_sorting_spec.rb14
-rw-r--r--spec/features/groups/settings/ci_cd_spec.rb81
-rw-r--r--spec/features/issuables/shortcuts_issuable_spec.rb12
-rw-r--r--spec/features/issues/incident_issue_spec.rb32
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb6
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb6
-rw-r--r--spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb37
-rw-r--r--spec/features/jira_connect/subscriptions_spec.rb2
-rw-r--r--spec/features/jira_oauth_provider_authorize_spec.rb6
-rw-r--r--spec/features/merge_request/user_merges_merge_request_spec.rb21
-rw-r--r--spec/features/merge_request/user_posts_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb3
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb37
-rw-r--r--spec/features/merge_requests/user_mass_updates_spec.rb2
-rw-r--r--spec/features/milestones/user_deletes_milestone_spec.rb2
-rw-r--r--spec/features/oauth_login_spec.rb2
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb4
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb25
-rw-r--r--spec/features/profiles/user_visits_profile_preferences_page_spec.rb8
-rw-r--r--spec/features/projects/blobs/balsamiq_spec.rb17
-rw-r--r--spec/features/projects/blobs/blob_line_permalink_updater_spec.rb8
-rw-r--r--spec/features/projects/branches_spec.rb10
-rw-r--r--spec/features/projects/cluster_agents_spec.rb1
-rw-r--r--spec/features/projects/clusters/eks_spec.rb2
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb5
-rw-r--r--spec/features/projects/clusters/user_spec.rb5
-rw-r--r--spec/features/projects/clusters_spec.rb5
-rw-r--r--spec/features/projects/commits/multi_view_diff_spec.rb79
-rw-r--r--spec/features/projects/environments/environments_spec.rb6
-rw-r--r--spec/features/projects/import_export/import_file_spec.rb6
-rw-r--r--spec/features/projects/issues/design_management/user_uploads_designs_spec.rb4
-rw-r--r--spec/features/projects/jobs/user_browses_jobs_spec.rb11
-rw-r--r--spec/features/projects/members/groups_with_access_list_spec.rb5
-rw-r--r--spec/features/projects/members/invite_group_spec.rb116
-rw-r--r--spec/features/projects/members/manage_members_spec.rb (renamed from spec/features/projects/members/list_spec.rb)65
-rw-r--r--spec/features/projects/members/sorting_spec.rb40
-rw-r--r--spec/features/projects/milestones/milestones_sorting_spec.rb62
-rw-r--r--spec/features/projects/new_project_spec.rb11
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb13
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb1
-rw-r--r--spec/features/projects/releases/user_views_releases_spec.rb154
-rw-r--r--spec/features/projects/terraform_spec.rb2
-rw-r--r--spec/features/projects/user_creates_project_spec.rb28
-rw-r--r--spec/features/projects/user_sorts_projects_spec.rb28
-rw-r--r--spec/features/projects_spec.rb39
-rw-r--r--spec/features/refactor_blob_viewer_disabled/projects/blobs/balsamiq_spec.rb18
-rw-r--r--spec/features/runners_spec.rb1
-rw-r--r--spec/features/search/user_searches_for_projects_spec.rb2
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb38
-rw-r--r--spec/features/static_site_editor_spec.rb113
-rw-r--r--spec/features/task_lists_spec.rb16
-rw-r--r--spec/features/users/login_spec.rb11
74 files changed, 1299 insertions, 889 deletions
diff --git a/spec/features/admin/admin_broadcast_messages_spec.rb b/spec/features/admin/admin_broadcast_messages_spec.rb
index e40f4c4678c..875eb9dd0ce 100644
--- a/spec/features/admin/admin_broadcast_messages_spec.rb
+++ b/spec/features/admin/admin_broadcast_messages_spec.rb
@@ -22,9 +22,8 @@ RSpec.describe 'Admin Broadcast Messages' do
it 'creates a customized broadcast banner message' do
fill_in 'broadcast_message_message', with: 'Application update from **4:00 CST to 5:00 CST**'
- fill_in 'broadcast_message_color', with: '#f2dede'
fill_in 'broadcast_message_target_path', with: '*/user_onboarded'
- fill_in 'broadcast_message_font', with: '#b94a48'
+ select 'light-indigo', from: 'broadcast_message_theme'
select Date.today.next_year.year, from: 'broadcast_message_ends_at_1i'
check 'Guest'
check 'Owner'
@@ -35,7 +34,7 @@ RSpec.describe 'Admin Broadcast Messages' do
expect(page).to have_content 'Guest, Owner'
expect(page).to have_content '*/user_onboarded'
expect(page).to have_selector 'strong', text: '4:00 CST to 5:00 CST'
- expect(page).to have_selector %(div[style="background-color: #f2dede; color: #b94a48"])
+ expect(page).to have_selector %(.light-indigo[role=alert])
end
it 'creates a customized broadcast notification message' do
@@ -90,7 +89,7 @@ RSpec.describe 'Admin Broadcast Messages' do
fill_in 'broadcast_message_message', with: "Live **Markdown** previews. :tada:"
select 'Notification', from: 'broadcast_message_broadcast_type'
- page.within('.js-broadcast-notification-message-preview') do
+ page.within('#broadcast-message-preview') do
expect(page).to have_selector('strong', text: 'Markdown')
expect(page).to have_emoji('tada')
end
diff --git a/spec/features/admin/admin_dev_ops_report_spec.rb b/spec/features/admin/admin_dev_ops_reports_spec.rb
index cee79f8f440..bf32819cb52 100644
--- a/spec/features/admin/admin_dev_ops_report_spec.rb
+++ b/spec/features/admin/admin_dev_ops_reports_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'DevOps Report page', :js do
end
it 'has dismissable intro callout' do
- visit admin_dev_ops_report_path
+ visit admin_dev_ops_reports_path
expect(page).to have_content 'Introducing Your DevOps Report'
@@ -32,13 +32,13 @@ RSpec.describe 'DevOps Report page', :js do
end
it 'shows empty state' do
- visit admin_dev_ops_report_path
+ visit admin_dev_ops_reports_path
expect(page).to have_text('Service ping is off')
end
it 'hides the intro callout' do
- visit admin_dev_ops_report_path
+ visit admin_dev_ops_reports_path
expect(page).not_to have_content 'Introducing Your DevOps Report'
end
@@ -48,7 +48,7 @@ RSpec.describe 'DevOps Report page', :js do
it 'shows empty state' do
stub_application_setting(usage_ping_enabled: true)
- visit admin_dev_ops_report_path
+ visit admin_dev_ops_reports_path
expect(page).to have_content('Data is still calculating')
end
@@ -59,7 +59,7 @@ RSpec.describe 'DevOps Report page', :js do
stub_application_setting(usage_ping_enabled: true)
create(:dev_ops_report_metric)
- visit admin_dev_ops_report_path
+ visit admin_dev_ops_reports_path
expect(page).to have_selector('[data-testid="devops-score-app"]')
end
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 3f0c7e64a1f..7fe49c2571c 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -3,65 +3,71 @@
require 'spec_helper'
RSpec.describe "Admin Runners" do
- include StubENV
- include Spec::Support::Helpers::ModalHelpers
+ include Spec::Support::Helpers::Features::RunnersHelpers
+
+ let_it_be(:admin) { create(:admin) }
before do
- stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
wait_for_requests
end
- describe "Runners page", :js do
+ describe "Admin Runners page", :js do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:namespace) { create(:namespace) }
let_it_be(:project) { create(:project, namespace: namespace, creator: user) }
- context "when there are runners" do
- it 'has all necessary texts' do
- create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: Time.zone.now)
- create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: 1.week.ago)
- create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: 1.year.ago)
-
+ context "runners registration" do
+ before do
visit admin_runners_path
-
- expect(page).to have_text "Register an instance runner"
- expect(page).to have_text "Online runners 1"
- expect(page).to have_text "Offline runners 2"
- expect(page).to have_text "Stale runners 1"
end
- it 'with an instance runner shows an instance badge' do
- runner = create(:ci_runner, :instance)
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { 'Register an instance runner' }
+ let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token }
+ end
+ end
- visit admin_runners_path
+ context "when there are runners" do
+ context "with an instance runner" do
+ let!(:instance_runner) { create(:ci_runner, :instance) }
- within "[data-testid='runner-row-#{runner.id}']" do
- expect(page).to have_selector '.badge', text: 'shared'
+ before do
+ visit admin_runners_path
end
- end
- it 'with a group runner shows a group badge' do
- runner = create(:ci_runner, :group, groups: [group])
+ it_behaves_like 'shows runner in list' do
+ let(:runner) { instance_runner }
+ end
- visit admin_runners_path
+ it_behaves_like 'pauses, resumes and deletes a runner' do
+ let(:runner) { instance_runner }
+ end
- within "[data-testid='runner-row-#{runner.id}']" do
- expect(page).to have_selector '.badge', text: 'group'
+ it 'shows an instance badge' do
+ within_runner_row(instance_runner.id) do
+ expect(page).to have_selector '.badge', text: 'shared'
+ end
end
end
- it 'with a project runner shows a project badge' do
- runner = create(:ci_runner, :project, projects: [project])
+ context "with multiple runners" do
+ before do
+ create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: Time.zone.now)
+ create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: 1.week.ago)
+ create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: 1.year.ago)
- visit admin_runners_path
+ visit admin_runners_path
+ end
- within "[data-testid='runner-row-#{runner.id}']" do
- expect(page).to have_selector '.badge', text: 'specific'
+ it 'has all necessary texts' do
+ expect(page).to have_text "Register an instance runner"
+ expect(page).to have_text "Online runners 1"
+ expect(page).to have_text "Offline runners 2"
+ expect(page).to have_text "Stale runners 1"
end
end
@@ -73,44 +79,8 @@ RSpec.describe "Admin Runners" do
visit admin_runners_path
- within "[data-testid='runner-row-#{runner.id}'] [data-label='Jobs']" do
- expect(page).to have_content '2'
- end
- end
-
- describe 'delete runner' do
- let!(:runner) { create(:ci_runner, description: 'runner-foo') }
-
- before do
- visit admin_runners_path
-
- within "[data-testid='runner-row-#{runner.id}']" do
- click_on 'Delete runner'
- end
- end
-
- it 'shows a confirmation modal' do
- expect(page).to have_text "Delete runner ##{runner.id} (#{runner.short_sha})?"
- expect(page).to have_text "Are you sure you want to continue?"
- end
-
- it 'deletes a runner' do
- within '.modal' do
- click_on 'Delete runner'
- end
-
- expect(page.find('.gl-toast')).to have_text(/Runner .+ deleted/)
- expect(page).not_to have_content 'runner-foo'
- end
-
- it 'cancels runner deletion' do
- within '.modal' do
- click_on 'Cancel'
- end
-
- wait_for_requests
-
- expect(page).to have_content 'runner-foo'
+ within_runner_row(runner.id) do
+ expect(find("[data-label='Jobs']")).to have_content '2'
end
end
@@ -154,35 +124,69 @@ RSpec.describe "Admin Runners" do
end
end
+ describe 'filter by paused' do
+ before do
+ create(:ci_runner, :instance, description: 'runner-active')
+ create(:ci_runner, :instance, description: 'runner-paused', active: false)
+
+ visit admin_runners_path
+ end
+
+ it 'shows all runners' do
+ expect(page).to have_link('All 2')
+
+ expect(page).to have_content 'runner-active'
+ expect(page).to have_content 'runner-paused'
+ end
+
+ it 'shows paused runners' do
+ input_filtered_search_filter_is_only('Paused', 'Yes')
+
+ expect(page).to have_link('All 1')
+
+ expect(page).not_to have_content 'runner-active'
+ expect(page).to have_content 'runner-paused'
+ end
+
+ it 'shows active runners' do
+ input_filtered_search_filter_is_only('Paused', 'No')
+
+ expect(page).to have_link('All 1')
+
+ expect(page).to have_content 'runner-active'
+ expect(page).not_to have_content 'runner-paused'
+ end
+ end
+
describe 'filter by status' do
let!(:never_contacted) { create(:ci_runner, :instance, description: 'runner-never-contacted', contacted_at: nil) }
before do
create(:ci_runner, :instance, description: 'runner-1', contacted_at: Time.zone.now)
create(:ci_runner, :instance, description: 'runner-2', contacted_at: Time.zone.now)
- create(:ci_runner, :instance, description: 'runner-paused', active: false, contacted_at: Time.zone.now)
+ create(:ci_runner, :instance, description: 'runner-offline', contacted_at: 1.week.ago)
visit admin_runners_path
end
it 'shows all runners' do
+ expect(page).to have_link('All 4')
+
expect(page).to have_content 'runner-1'
expect(page).to have_content 'runner-2'
- expect(page).to have_content 'runner-paused'
+ expect(page).to have_content 'runner-offline'
expect(page).to have_content 'runner-never-contacted'
-
- expect(page).to have_link('All 4')
end
it 'shows correct runner when status matches' do
- input_filtered_search_filter_is_only('Status', 'Active')
+ input_filtered_search_filter_is_only('Status', 'Online')
- expect(page).to have_link('All 3')
+ expect(page).to have_link('All 2')
expect(page).to have_content 'runner-1'
expect(page).to have_content 'runner-2'
- expect(page).to have_content 'runner-never-contacted'
- expect(page).not_to have_content 'runner-paused'
+ expect(page).not_to have_content 'runner-offline'
+ expect(page).not_to have_content 'runner-never-contacted'
end
it 'shows no runner when status does not match' do
@@ -194,15 +198,15 @@ RSpec.describe "Admin Runners" do
end
it 'shows correct runner when status is selected and search term is entered' do
- input_filtered_search_filter_is_only('Status', 'Active')
+ input_filtered_search_filter_is_only('Status', 'Online')
input_filtered_search_keys('runner-1')
expect(page).to have_link('All 1')
expect(page).to have_content 'runner-1'
expect(page).not_to have_content 'runner-2'
+ expect(page).not_to have_content 'runner-offline'
expect(page).not_to have_content 'runner-never-contacted'
- expect(page).not_to have_content 'runner-paused'
end
it 'shows correct runner when status filter is entered' do
@@ -216,7 +220,7 @@ RSpec.describe "Admin Runners" do
expect(page).not_to have_content 'runner-paused'
expect(page).to have_content 'runner-never-contacted'
- within "[data-testid='runner-row-#{never_contacted.id}']" do
+ within_runner_row(never_contacted.id) do
expect(page).to have_selector '.badge', text: 'never contacted'
end
end
@@ -308,7 +312,7 @@ RSpec.describe "Admin Runners" do
visit admin_runners_path
- input_filtered_search_filter_is_only('Status', 'Active')
+ input_filtered_search_filter_is_only('Paused', 'No')
expect(page).to have_content 'runner-project'
expect(page).to have_content 'runner-group'
@@ -330,6 +334,17 @@ RSpec.describe "Admin Runners" do
create(:ci_runner, :instance, description: 'runner-red', tag_list: ['red'])
end
+ it 'shows tags suggestions' do
+ visit admin_runners_path
+
+ open_filtered_search_suggestions('Tags')
+
+ page.within(search_bar_selector) do
+ expect(page).to have_content 'blue'
+ expect(page).to have_content 'red'
+ end
+ end
+
it 'shows correct runner when tag matches' do
visit admin_runners_path
@@ -403,15 +418,7 @@ RSpec.describe "Admin Runners" do
visit admin_runners_path
end
- it 'has all necessary texts including no runner message' do
- expect(page).to have_text "Register an instance runner"
-
- expect(page).to have_text "Online runners 0"
- expect(page).to have_text "Offline runners 0"
- expect(page).to have_text "Stale runners 0"
-
- expect(page).to have_text 'No runners found'
- end
+ it_behaves_like "shows no runners"
it 'shows tabs with total counts equal to 0' do
expect(page).to have_link('All 0')
@@ -427,65 +434,17 @@ RSpec.describe "Admin Runners" do
expect(page).to have_current_path(admin_runners_path('status[]': 'NEVER_CONTACTED') )
end
- end
- describe 'runners registration' do
- let!(:token) { Gitlab::CurrentSettings.runners_registration_token }
-
- before do
- visit admin_runners_path
+ it 'updates ACTIVE runner status to paused=false' do
+ visit admin_runners_path('status[]': 'ACTIVE')
- click_on 'Register an instance runner'
+ expect(page).to have_current_path(admin_runners_path('paused[]': 'false') )
end
- describe 'show registration instructions' do
- before do
- click_on 'Show runner installation and registration instructions'
-
- wait_for_requests
- end
-
- it 'opens runner installation modal' do
- expect(page).to have_text "Install a runner"
-
- expect(page).to have_text "Environment"
- expect(page).to have_text "Architecture"
- expect(page).to have_text "Download and install binary"
- end
-
- it 'dismisses runner installation modal' do
- within_modal do
- click_button('Close', match: :first)
- end
-
- expect(page).not_to have_text "Install a runner"
- end
- end
+ it 'updates PAUSED runner status to paused=true' do
+ visit admin_runners_path('status[]': 'PAUSED')
- it 'has a registration token' do
- click_on 'Click to reveal'
- expect(page.find('[data-testid="token-value"]')).to have_content(token)
- end
-
- describe 'reset registration token' do
- let(:page_token) { find('[data-testid="token-value"]').text }
-
- before do
- click_on 'Reset registration token'
-
- within_modal do
- click_button('Reset token', match: :first)
- end
-
- wait_for_requests
- end
-
- it 'changes registration token' do
- click_on 'Register an instance runner'
-
- click_on 'Click to reveal'
- expect(page_token).not_to eq token
- end
+ expect(page).to have_current_path(admin_runners_path('paused[]': 'true') )
end
end
end
@@ -637,47 +596,4 @@ RSpec.describe "Admin Runners" do
end
end
end
-
- private
-
- def search_bar_selector
- '[data-testid="runners-filtered-search"]'
- end
-
- # The filters must be clicked first to be able to receive events
- # See: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1493
- def focus_filtered_search
- page.within(search_bar_selector) do
- page.find('.gl-filtered-search-term-token').click
- end
- end
-
- def input_filtered_search_keys(search_term)
- focus_filtered_search
-
- page.within(search_bar_selector) do
- page.find('input').send_keys(search_term)
- click_on 'Search'
- end
-
- wait_for_requests
- end
-
- def input_filtered_search_filter_is_only(filter, value)
- focus_filtered_search
-
- page.within(search_bar_selector) do
- click_on filter
-
- # For OPERATOR_IS_ONLY, clicking the filter
- # immediately preselects "=" operator
-
- page.find('input').send_keys(value)
- page.find('input').send_keys(:enter)
-
- click_on 'Search'
- end
-
- wait_for_requests
- end
end
diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb
index d05a09a79ef..432721d63ad 100644
--- a/spec/features/admin/admin_sees_background_migrations_spec.rb
+++ b/spec/features/admin/admin_sees_background_migrations_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe "Admin > Admin sees background migrations" do
let_it_be(:admin) { create(:admin) }
- let_it_be(:active_migration) { create(:batched_background_migration, table_name: 'active', status: :active) }
- let_it_be(:failed_migration) { create(:batched_background_migration, table_name: 'failed', status: :failed, total_tuple_count: 100) }
- let_it_be(:finished_migration) { create(:batched_background_migration, table_name: 'finished', status: :finished) }
+ let_it_be(:active_migration) { create(:batched_background_migration, :active, table_name: 'active') }
+ let_it_be(:failed_migration) { create(:batched_background_migration, :failed, table_name: 'failed', total_tuple_count: 100) }
+ let_it_be(:finished_migration) { create(:batched_background_migration, :finished, table_name: 'finished') }
before_all do
create(:batched_background_migration_job, :failed, batched_migration: failed_migration, batch_size: 10, min_value: 6, max_value: 15, attempts: 3)
@@ -81,7 +81,7 @@ RSpec.describe "Admin > Admin sees background migrations" do
expect(page).to have_content(failed_migration.job_class_name)
expect(page).to have_content(failed_migration.table_name)
expect(page).to have_content('0.00%')
- expect(page).to have_content(failed_migration.status.humanize)
+ expect(page).to have_content(failed_migration.status_name.to_s)
click_button('Retry')
expect(page).not_to have_content(failed_migration.job_class_name)
@@ -106,7 +106,7 @@ RSpec.describe "Admin > Admin sees background migrations" do
expect(page).to have_content(finished_migration.job_class_name)
expect(page).to have_content(finished_migration.table_name)
expect(page).to have_content('100.00%')
- expect(page).to have_content(finished_migration.status.humanize)
+ expect(page).to have_content(finished_migration.status_name.to_s)
end
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index df93bd773a6..4cdc3df978d 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -34,16 +34,16 @@ RSpec.describe 'Admin updates settings' do
it 'uncheck all restricted visibility levels' do
page.within('.as-visibility-access') do
- find('#application_setting_visibility_level_0').set(false)
- find('#application_setting_visibility_level_10').set(false)
- find('#application_setting_visibility_level_20').set(false)
+ find('#application_setting_restricted_visibility_levels_0').set(false)
+ find('#application_setting_restricted_visibility_levels_10').set(false)
+ find('#application_setting_restricted_visibility_levels_20').set(false)
click_button 'Save changes'
end
expect(page).to have_content "Application settings saved successfully"
- expect(find('#application_setting_visibility_level_0')).not_to be_checked
- expect(find('#application_setting_visibility_level_10')).not_to be_checked
- expect(find('#application_setting_visibility_level_20')).not_to be_checked
+ expect(find('#application_setting_restricted_visibility_levels_0')).not_to be_checked
+ expect(find('#application_setting_restricted_visibility_levels_10')).not_to be_checked
+ expect(find('#application_setting_restricted_visibility_levels_20')).not_to be_checked
end
it 'modify import sources' do
@@ -311,7 +311,9 @@ RSpec.describe 'Admin updates settings' do
end
context 'CI/CD page' do
- it 'change CI/CD settings' do
+ let_it_be(:default_plan) { create(:default_plan) }
+
+ it 'changes CI/CD settings' do
visit ci_cd_admin_application_settings_path
page.within('.as-ci-cd') do
@@ -329,6 +331,33 @@ RSpec.describe 'Admin updates settings' do
expect(page).to have_content "Application settings saved successfully"
end
+ it 'changes CI/CD limits', :aggregate_failures do
+ visit ci_cd_admin_application_settings_path
+
+ page.within('.as-ci-cd') do
+ fill_in 'plan_limits_ci_pipeline_size', with: 10
+ fill_in 'plan_limits_ci_active_jobs', with: 20
+ fill_in 'plan_limits_ci_active_pipelines', with: 25
+ fill_in 'plan_limits_ci_project_subscriptions', with: 30
+ fill_in 'plan_limits_ci_pipeline_schedules', with: 40
+ fill_in 'plan_limits_ci_needs_size_limit', with: 50
+ fill_in 'plan_limits_ci_registered_group_runners', with: 60
+ fill_in 'plan_limits_ci_registered_project_runners', with: 70
+ click_button 'Save Default limits'
+ end
+
+ limits = default_plan.reload.limits
+ expect(limits.ci_pipeline_size).to eq(10)
+ expect(limits.ci_active_jobs).to eq(20)
+ expect(limits.ci_active_pipelines).to eq(25)
+ expect(limits.ci_project_subscriptions).to eq(30)
+ expect(limits.ci_pipeline_schedules).to eq(40)
+ expect(limits.ci_needs_size_limit).to eq(50)
+ expect(limits.ci_registered_group_runners).to eq(60)
+ expect(limits.ci_registered_project_runners).to eq(70)
+ expect(page).to have_content 'Application limits saved successfully'
+ end
+
context 'Runner Registration' do
context 'when feature is enabled' do
before do
@@ -421,7 +450,7 @@ RSpec.describe 'Admin updates settings' do
visit ci_cd_admin_application_settings_path
page.within('.as-registry') do
- find('#application_setting_container_registry_expiration_policies_caching.form-check-input').click
+ find('#application_setting_container_registry_expiration_policies_caching').click
click_button 'Save changes'
end
@@ -489,8 +518,8 @@ RSpec.describe 'Admin updates settings' do
page.within('.as-spam') do
fill_in 'reCAPTCHA site key', with: 'key'
fill_in 'reCAPTCHA private key', with: 'key'
- check 'Enable reCAPTCHA'
- check 'Enable reCAPTCHA for login'
+ find('#application_setting_recaptcha_enabled').set(true)
+ find('#application_setting_login_recaptcha_protection_enabled').set(true)
fill_in 'IP addresses per user', with: 15
check 'Enable Spam Check via external API endpoint'
fill_in 'URL of the external Spam Check endpoint', with: 'grpc://www.example.com/spamcheck'
@@ -825,31 +854,45 @@ RSpec.describe 'Admin updates settings' do
before do
stub_usage_data_connections
stub_database_flavor_check
-
- visit service_usage_data_admin_application_settings_path
end
- it 'loads usage ping payload on click', :js do
- expected_payload_content = /(?=.*"uuid")(?=.*"hostname")/m
+ context 'when service data cached', :clean_gitlab_redis_cache do
+ before do
+ allow(Rails.cache).to receive(:exist?).with('usage_data').and_return(true)
- expect(page).not_to have_content expected_payload_content
+ visit service_usage_data_admin_application_settings_path
+ end
- click_button('Preview payload')
+ it 'loads usage ping payload on click', :js do
+ expected_payload_content = /(?=.*"uuid")(?=.*"hostname")/m
- wait_for_requests
+ expect(page).not_to have_content expected_payload_content
- expect(page).to have_button 'Hide payload'
- expect(page).to have_content expected_payload_content
- end
+ click_button('Preview payload')
- it 'generates usage ping payload on button click', :js do
- expect_next_instance_of(Admin::ApplicationSettingsController) do |instance|
- expect(instance).to receive(:usage_data).and_call_original
+ wait_for_requests
+
+ expect(page).to have_button 'Hide payload'
+ expect(page).to have_content expected_payload_content
+ end
+
+ it 'generates usage ping payload on button click', :js do
+ expect_next_instance_of(Admin::ApplicationSettingsController) do |instance|
+ expect(instance).to receive(:usage_data).and_call_original
+ end
+
+ click_button('Download payload')
+
+ wait_for_requests
end
+ end
- click_button('Download payload')
+ context 'when service data not cached' do
+ it 'renders missing cache information' do
+ visit service_usage_data_admin_application_settings_path
- wait_for_requests
+ expect(page).to have_text('Service Ping payload not found in the application cache')
+ end
end
end
end
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 6643ebe82e6..15bc2318022 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -36,14 +36,14 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
click_on "1"
# Scopes
- check "api"
+ check "read_api"
check "read_user"
click_on "Create impersonation token"
expect(active_impersonation_tokens).to have_text(name)
expect(active_impersonation_tokens).to have_text('in')
- expect(active_impersonation_tokens).to have_text('api')
+ expect(active_impersonation_tokens).to have_text('read_api')
expect(active_impersonation_tokens).to have_text('read_user')
expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1)
expect(created_impersonation_token).not_to be_empty
diff --git a/spec/features/admin/clusters/eks_spec.rb b/spec/features/admin/clusters/eks_spec.rb
index 71d2bba73b1..4667f9c20a1 100644
--- a/spec/features/admin/clusters/eks_spec.rb
+++ b/spec/features/admin/clusters/eks_spec.rb
@@ -15,8 +15,8 @@ RSpec.describe 'Instance-level AWS EKS Cluster', :js do
before do
visit admin_clusters_path
- click_button 'Actions'
- click_link 'Create a new cluster'
+ click_button(class: 'dropdown-toggle-split')
+ click_link 'Create a cluster (deprecated)'
end
context 'when user creates a cluster on AWS EKS' do
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 5dd627f3b76..bf976168bbe 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -282,7 +282,7 @@ RSpec.describe 'Project issue boards', :js do
it 'shows issue count on the list' do
page.within(find(".board:nth-child(2)")) do
expect(page.find('[data-testid="board-items-count"]')).to have_text(total_planning_issues)
- expect(page).not_to have_selector('.js-max-issue-size')
+ expect(page).not_to have_selector('.max-issue-size')
end
end
end
diff --git a/spec/features/boards/focus_mode_spec.rb b/spec/features/boards/focus_mode_spec.rb
index 2bd1e625236..453a8d8870b 100644
--- a/spec/features/boards/focus_mode_spec.rb
+++ b/spec/features/boards/focus_mode_spec.rb
@@ -12,6 +12,6 @@ RSpec.describe 'Issue Boards focus mode', :js do
end
it 'shows focus mode button to anonymous users' do
- expect(page).to have_selector('.js-focus-mode-btn')
+ expect(page).to have_button _('Toggle focus mode')
end
end
diff --git a/spec/features/boards/multi_select_spec.rb b/spec/features/boards/multi_select_spec.rb
index 9148fb23214..cad303a14e5 100644
--- a/spec/features/boards/multi_select_spec.rb
+++ b/spec/features/boards/multi_select_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe 'Multi Select Issue', :js do
wait_for_requests
- page.within(all('.js-board-list')[2]) do
+ page.within(all('.board-list')[2]) do
expect(find('.board-card:nth-child(1)')).to have_content(issue1.title)
expect(find('.board-card:nth-child(2)')).to have_content(issue2.title)
end
@@ -87,7 +87,7 @@ RSpec.describe 'Multi Select Issue', :js do
wait_for_requests
- page.within(all('.js-board-list')[2]) do
+ page.within(all('.board-list')[2]) do
expect(find('.board-card:nth-child(1)')).to have_content(issue1.title)
expect(find('.board-card:nth-child(2)')).to have_content(issue2.title)
expect(find('.board-card:nth-child(3)')).to have_content(issue3.title)
@@ -102,7 +102,7 @@ RSpec.describe 'Multi Select Issue', :js do
wait_for_requests
- page.within(all('.js-board-list')[1]) do
+ page.within(all('.board-list')[1]) do
expect(find('.board-card:nth-child(1)')).to have_content(issue1.title)
expect(find('.board-card:nth-child(2)')).to have_content(issue2.title)
expect(find('.board-card:nth-child(3)')).to have_content(issue5.title)
diff --git a/spec/features/clusters/create_agent_spec.rb b/spec/features/clusters/create_agent_spec.rb
index e03126d344e..c7326204bf6 100644
--- a/spec/features/clusters/create_agent_spec.rb
+++ b/spec/features/clusters/create_agent_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'Cluster agent registration', :js do
end
it 'allows the user to select an agent to install, and displays the resulting agent token' do
- click_button('Actions')
+ click_button('Connect a cluster')
expect(page).to have_content('Register')
click_button('Select an agent')
@@ -34,7 +34,7 @@ RSpec.describe 'Cluster agent registration', :js do
expect(page).to have_content('You cannot see this token again after you close this window.')
expect(page).to have_content('example-agent-token')
- expect(page).to have_content('docker run --pull=always --rm')
+ expect(page).to have_content('helm upgrade --install')
within find('.modal-footer') do
click_button('Close')
diff --git a/spec/features/commit_spec.rb b/spec/features/commit_spec.rb
index 3fd613ce393..c9fa10d58e6 100644
--- a/spec/features/commit_spec.rb
+++ b/spec/features/commit_spec.rb
@@ -33,6 +33,10 @@ RSpec.describe 'Commit' do
it "reports the correct number of total changes" do
expect(page).to have_content("Changes #{commit.diffs.size}")
end
+
+ it 'renders diff stats', :js do
+ expect(page).to have_selector(".diff-stats")
+ end
end
describe "pagination" do
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index db841ffc627..4b38df175e2 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'Commits' do
before do
sign_in(user)
stub_ci_pipeline_to_return_yaml_file
+ stub_feature_flags(pipeline_tabs_vue: false)
end
let(:creator) { create(:user, developer_projects: [project]) }
@@ -93,6 +94,7 @@ RSpec.describe 'Commits' do
context 'Download artifacts', :js do
before do
+ stub_feature_flags(pipeline_tabs_vue: false)
create(:ci_job_artifact, :archive, file: artifacts_file, job: build)
end
@@ -122,6 +124,7 @@ RSpec.describe 'Commits' do
context "when logged as reporter", :js do
before do
+ stub_feature_flags(pipeline_tabs_vue: false)
project.add_reporter(user)
create(:ci_job_artifact, :archive, file: artifacts_file, job: build)
visit builds_project_pipeline_path(project, pipeline)
diff --git a/spec/features/error_tracking/user_searches_sentry_errors_spec.rb b/spec/features/error_tracking/user_searches_sentry_errors_spec.rb
index 89bf79ebb81..40718deed75 100644
--- a/spec/features/error_tracking/user_searches_sentry_errors_spec.rb
+++ b/spec/features/error_tracking/user_searches_sentry_errors_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe 'When a user searches for Sentry errors', :js, :use_clean_rails_m
expect(results.count).to be(3)
end
- find('.gl-form-input').set('NotFound').native.send_keys(:return)
+ find('.filtered-search-input-container .gl-form-input').set('NotFound').native.send_keys(:return)
page.within(find('.gl-table')) do
results = page.all('.table-row')
diff --git a/spec/features/groups/clusters/eks_spec.rb b/spec/features/groups/clusters/eks_spec.rb
index 3cca2d0919c..0e64a2faf3e 100644
--- a/spec/features/groups/clusters/eks_spec.rb
+++ b/spec/features/groups/clusters/eks_spec.rb
@@ -20,8 +20,8 @@ RSpec.describe 'Group AWS EKS Cluster', :js do
before do
visit group_clusters_path(group)
- click_button 'Actions'
- click_link 'Create a new cluster'
+ click_button(class: 'dropdown-toggle-split')
+ click_link 'Create a cluster (deprecated)'
end
context 'when user creates a cluster on AWS EKS' do
diff --git a/spec/features/groups/clusters/user_spec.rb b/spec/features/groups/clusters/user_spec.rb
index 2ed6ddc09ab..74ea72b238f 100644
--- a/spec/features/groups/clusters/user_spec.rb
+++ b/spec/features/groups/clusters/user_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'User Cluster', :js do
before do
visit group_clusters_path(group)
- click_link 'Connect with a certificate'
+ click_link 'Connect a cluster (deprecated)'
end
context 'when user filled form with valid parameters' do
@@ -119,7 +119,6 @@ RSpec.describe 'User Cluster', :js do
it 'user sees creation form with the successful message' do
expect(page).to have_content('Kubernetes cluster integration was successfully removed.')
- expect(page).to have_link('Connect with a certificate')
end
end
end
diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb
new file mode 100644
index 00000000000..1d821edefa3
--- /dev/null
+++ b/spec/features/groups/group_runners_spec.rb
@@ -0,0 +1,168 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Group Runners" do
+ include Spec::Support::Helpers::Features::RunnersHelpers
+
+ let_it_be(:group_owner) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ before do
+ group.add_owner(group_owner)
+ sign_in(group_owner)
+ end
+
+ describe "Group runners page", :js do
+ let!(:group_registration_token) { group.runners_token }
+
+ context "runners registration" do
+ before do
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { 'Register a group runner' }
+ let(:registration_token) { group_registration_token }
+ end
+ end
+
+ context "with no runners" do
+ before do
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like "shows no runners"
+
+ it 'shows tabs with total counts equal to 0' do
+ expect(page).to have_link('All 0')
+ expect(page).to have_link('Group 0')
+ expect(page).to have_link('Project 0')
+ end
+ end
+
+ context "with an online group runner" do
+ let!(:group_runner) do
+ create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
+ end
+
+ before do
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like 'shows runner in list' do
+ let(:runner) { group_runner }
+ end
+
+ it_behaves_like 'pauses, resumes and deletes a runner' do
+ let(:runner) { group_runner }
+ end
+
+ it 'shows a group badge' do
+ within_runner_row(group_runner.id) do
+ expect(page).to have_selector '.badge', text: 'group'
+ end
+ end
+
+ it 'can edit runner information' do
+ within_runner_row(group_runner.id) do
+ expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, group_runner))
+ end
+ end
+ end
+
+ context "with an online project runner" do
+ let!(:project_runner) do
+ create(:ci_runner, :project, projects: [project], description: 'runner-bar', contacted_at: Time.zone.now)
+ end
+
+ before do
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like 'shows runner in list' do
+ let(:runner) { project_runner }
+ end
+
+ it_behaves_like 'pauses, resumes and deletes a runner' do
+ let(:runner) { project_runner }
+ end
+
+ it 'shows a project (specific) badge' do
+ within_runner_row(project_runner.id) do
+ expect(page).to have_selector '.badge', text: 'specific'
+ end
+ end
+
+ it 'can edit runner information' do
+ within_runner_row(project_runner.id) do
+ expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, project_runner))
+ end
+ end
+ end
+
+ context 'with a multi-project runner' do
+ let(:project) { create(:project, group: group) }
+ let(:project_2) { create(:project, group: group) }
+ let!(:runner) { create(:ci_runner, :project, projects: [project, project_2], description: 'group-runner') }
+
+ it 'user cannot remove the project runner' do
+ visit group_runners_path(group)
+
+ within_runner_row(runner.id) do
+ expect(page).to have_button 'Delete runner', disabled: true
+ end
+ end
+ end
+
+ context 'filtered search' do
+ before do
+ visit group_runners_path(group)
+ end
+
+ it 'allows user to search by paused and status', :js do
+ focus_filtered_search
+
+ page.within(search_bar_selector) do
+ expect(page).to have_link('Paused')
+ expect(page).to have_content('Status')
+ end
+ end
+ end
+ end
+
+ describe "Group runner edit page", :js do
+ let!(:runner) do
+ create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
+ end
+
+ it 'user edits the runner to be protected' do
+ visit edit_group_runner_path(group, runner)
+
+ expect(page.find_field('runner[access_level]')).not_to be_checked
+
+ check 'runner_access_level'
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Protected Yes'
+ end
+
+ context 'when a runner has a tag' do
+ before do
+ runner.update!(tag_list: ['tag'])
+ end
+
+ it 'user edits runner not to run untagged jobs' do
+ visit edit_group_runner_path(group, runner)
+
+ expect(page.find_field('runner[run_untagged]')).to be_checked
+
+ uncheck 'runner_run_untagged'
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Can run untagged jobs No'
+ end
+ end
+ end
+end
diff --git a/spec/features/groups/import_export/export_file_spec.rb b/spec/features/groups/import_export/export_file_spec.rb
index 9feb8085e66..e3cb1ad77a7 100644
--- a/spec/features/groups/import_export/export_file_spec.rb
+++ b/spec/features/groups/import_export/export_file_spec.rb
@@ -26,22 +26,6 @@ RSpec.describe 'Group Export', :js do
end
end
- context 'when the group import/export FF is disabled' do
- before do
- stub_feature_flags(group_import_export: false)
-
- group.add_owner(user)
- sign_in(user)
- end
-
- it 'does not show the group export options' do
- visit edit_group_path(group)
-
- expect(page).to have_content('Advanced')
- expect(page).not_to have_content('Export group')
- end
- end
-
context 'when the signed in user does not have the required permission level' do
before do
group.add_guest(user)
diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb
index 5ab5a7ea716..5a9223d9ee8 100644
--- a/spec/features/groups/members/manage_groups_spec.rb
+++ b/spec/features/groups/members/manage_groups_spec.rb
@@ -3,7 +3,6 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Manage groups', :js do
- include Select2Helper
include Spec::Support::Helpers::Features::MembersHelpers
include Spec::Support::Helpers::Features::InviteMembersModalHelper
include Spec::Support::Helpers::ModalHelpers
@@ -119,16 +118,92 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
describe 'group search results' do
let_it_be(:group, refind: true) { create(:group) }
- let_it_be(:group_within_hierarchy) { create(:group, parent: group) }
- let_it_be(:group_outside_hierarchy) { create(:group) }
- before_all do
- group.add_owner(user)
- group_within_hierarchy.add_owner(user)
- group_outside_hierarchy.add_owner(user)
+ context 'with instance admin considerations' do
+ let_it_be(:group_to_share) { create(:group) }
+
+ context 'when user is an admin' do
+ let_it_be(:admin) { create(:admin) }
+
+ before do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ end
+
+ it 'shows groups where the admin has no direct membership' do
+ visit group_group_members_path(group)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_to_share)
+ expect_not_to_have_group(group)
+ end
+ end
+
+ it 'shows groups where the admin has at least guest level membership' do
+ group_to_share.add_guest(admin)
+
+ visit group_group_members_path(group)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_to_share)
+ expect_not_to_have_group(group)
+ end
+ end
+ end
+
+ context 'when user is not an admin' do
+ before do
+ group.add_owner(user)
+ end
+
+ it 'shows groups where the user has no direct membership' do
+ visit group_group_members_path(group)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_not_to_have_group(group_to_share)
+ expect_not_to_have_group(group)
+ end
+ end
+
+ it 'shows groups where the user has at least guest level membership' do
+ group_to_share.add_guest(user)
+
+ visit group_group_members_path(group)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_to_share)
+ expect_not_to_have_group(group)
+ end
+ end
+ end
end
- context 'when the invite members group modal is enabled' do
+ context 'when user is not an admin and there are hierarchy considerations' do
+ let_it_be(:group_within_hierarchy) { create(:group, parent: group) }
+ let_it_be(:group_outside_hierarchy) { create(:group) }
+
+ before_all do
+ group.add_owner(user)
+ group_within_hierarchy.add_owner(user)
+ group_outside_hierarchy.add_owner(user)
+ end
+
it 'does not show self or ancestors', :aggregate_failures do
group_sibbling = create(:group, parent: group)
group_sibbling.add_owner(user)
@@ -139,46 +214,46 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
click_on 'Select a group'
wait_for_requests
- page.within('[data-testid="group-select-dropdown"]') do
- expect(page).to have_selector("[entity-id='#{group_outside_hierarchy.id}']")
- expect(page).to have_selector("[entity-id='#{group_sibbling.id}']")
- expect(page).not_to have_selector("[entity-id='#{group.id}']")
- expect(page).not_to have_selector("[entity-id='#{group_within_hierarchy.id}']")
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_outside_hierarchy)
+ expect_to_have_group(group_sibbling)
+ expect_not_to_have_group(group)
+ expect_not_to_have_group(group_within_hierarchy)
end
end
- end
- context 'when sharing with groups outside the hierarchy is enabled' do
- it 'shows groups within and outside the hierarchy in search results' do
- visit group_group_members_path(group)
+ context 'when sharing with groups outside the hierarchy is enabled' do
+ it 'shows groups within and outside the hierarchy in search results' do
+ visit group_group_members_path(group)
- click_on 'Invite a group'
- click_on 'Select a group'
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
- expect(page).to have_text group_within_hierarchy.name
- expect(page).to have_text group_outside_hierarchy.name
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_within_hierarchy)
+ expect_to_have_group(group_outside_hierarchy)
+ end
+ end
end
- end
- context 'when sharing with groups outside the hierarchy is disabled' do
- before do
- group.namespace_settings.update!(prevent_sharing_groups_outside_hierarchy: true)
- end
+ context 'when sharing with groups outside the hierarchy is disabled' do
+ before do
+ group.namespace_settings.update!(prevent_sharing_groups_outside_hierarchy: true)
+ end
- it 'shows only groups within the hierarchy in search results' do
- visit group_group_members_path(group)
+ it 'shows only groups within the hierarchy in search results' do
+ visit group_group_members_path(group)
- click_on 'Invite a group'
- click_on 'Select a group'
+ click_on 'Invite a group'
+ click_on 'Select a group'
- expect(page).to have_text group_within_hierarchy.name
- expect(page).not_to have_text group_outside_hierarchy.name
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_within_hierarchy)
+ expect_not_to_have_group(group_outside_hierarchy)
+ end
+ end
end
end
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 533d2118b30..468001c3be6 100644
--- a/spec/features/groups/members/manage_members_spec.rb
+++ b/spec/features/groups/members/manage_members_spec.rb
@@ -42,46 +42,6 @@ RSpec.describe 'Groups > Members > Manage members' do
end
end
- it 'add user to group', :js, :snowplow, :aggregate_failures do
- group.add_owner(user1)
-
- visit group_group_members_path(group)
-
- invite_member(user2.name, role: 'Reporter')
-
- page.within(second_row) do
- expect(page).to have_content(user2.name)
- expect(page).to have_button('Reporter')
- end
-
- expect_snowplow_event(
- category: 'Members::CreateService',
- action: 'create_member',
- label: 'group-members-page',
- property: 'existing_user',
- user: user1
- )
- end
-
- it 'do not disclose email addresses', :js do
- group.add_owner(user1)
- create(:user, email: 'undisclosed_email@gitlab.com', name: "Jane 'invisible' Doe")
-
- visit group_group_members_path(group)
-
- click_on 'Invite members'
- find('[data-testid="members-token-select-input"]').set('@gitlab.com')
-
- wait_for_requests
-
- expect(page).to have_content('No matches found')
-
- find('[data-testid="members-token-select-input"]').set('undisclosed_email@gitlab.com')
- wait_for_requests
-
- expect(page).to have_content('Invite "undisclosed_email@gitlab.com" by email')
- end
-
it 'remove user from group', :js do
group.add_owner(user1)
group.add_developer(user2)
@@ -106,43 +66,29 @@ RSpec.describe 'Groups > Members > Manage members' do
end
end
- it 'add yourself to group when already an owner', :js, :aggregate_failures do
- group.add_owner(user1)
-
- visit group_group_members_path(group)
-
- invite_member(user1.name, role: 'Reporter')
-
- page.within(first_row) do
- expect(page).to have_content(user1.name)
- expect(page).to have_content('Owner')
- end
- end
+ context 'when inviting' do
+ it 'add yourself to group when already an owner', :js do
+ group.add_owner(user1)
- it 'invite user to group', :js, :snowplow do
- group.add_owner(user1)
+ visit group_group_members_path(group)
- visit group_group_members_path(group)
+ invite_member(user1.name, role: 'Reporter', refresh: false)
- invite_member('test@example.com', role: 'Reporter')
+ expect(page).to have_selector(invite_modal_selector)
+ expect(page).to have_content("not authorized to update member")
- expect(page).to have_link 'Invited'
- click_link 'Invited'
+ page.refresh
- aggregate_failures 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')
+ page.within find_member_row(user1) do
+ expect(page).to have_content('Owner')
end
+ end
- expect_snowplow_event(
- category: 'Members::InviteService',
- action: 'create_member',
- label: 'group-members-page',
- property: 'net_new_user',
- user: user1
- )
+ it_behaves_like 'inviting members', 'group-members-page' do
+ let_it_be(:entity) { group }
+ let_it_be(:members_page_path) { group_group_members_path(entity) }
+ let_it_be(:subentity) { create(:group, parent: group) }
+ let_it_be(:subentity_members_page_path) { group_group_members_path(subentity) }
end
end
@@ -169,4 +115,57 @@ RSpec.describe 'Groups > Members > Manage members' do
end
end
end
+
+ describe 'member search results', :js do
+ before do
+ group.add_owner(user1)
+ end
+
+ it 'does not disclose email addresses' do
+ create(:user, email: 'undisclosed_email@gitlab.com', name: "Jane 'invisible' Doe")
+
+ visit group_group_members_path(group)
+
+ click_on 'Invite members'
+ find(member_dropdown_selector).set('@gitlab.com')
+
+ wait_for_requests
+
+ expect(page).to have_content('No matches found')
+
+ find(member_dropdown_selector).set('undisclosed_email@gitlab.com')
+ wait_for_requests
+
+ expect(page).to have_content('Invite "undisclosed_email@gitlab.com" by email')
+ end
+
+ it 'does not show project_bots', :aggregate_failures do
+ internal_project_bot = create(:user, :project_bot, name: '_internal_project_bot_')
+ project = create(:project, group: group)
+ project.add_maintainer(internal_project_bot)
+
+ external_group = create(:group)
+ external_project_bot = create(:user, :project_bot, name: '_external_project_bot_')
+ external_project = create(:project, group: external_group)
+ external_project.add_maintainer(external_project_bot)
+ external_project.add_maintainer(user1)
+
+ visit group_group_members_path(group)
+
+ click_on 'Invite members'
+
+ page.within invite_modal_selector do
+ field = find(member_dropdown_selector)
+ field.native.send_keys :tab
+ field.click
+
+ wait_for_requests
+
+ expect(page).to have_content(user1.name)
+ expect(page).to have_content(user2.name)
+ expect(page).not_to have_content(internal_project_bot.name)
+ expect(page).not_to have_content(external_project_bot.name)
+ end
+ end
+ end
end
diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb
index 03758e0d401..bf8e64fa1e2 100644
--- a/spec/features/groups/members/sort_members_spec.rb
+++ b/spec/features/groups/members/sort_members_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
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(:owner) { create(:user, name: 'John Doe', created_at: 5.days.ago, last_activity_on: Date.today) }
+ let(:developer) { create(:user, name: 'Mary Jane', created_at: 1.day.ago, last_sign_in_at: 5.days.ago, last_activity_on: Date.today - 5) }
let(:group) { create(:group) }
before do
@@ -50,6 +50,42 @@ RSpec.describe 'Groups > Members > Sort members', :js do
expect_sort_by('Max role', :desc)
end
+ it 'sorts by user created on ascending' do
+ visit_members_list(sort: :oldest_created_user)
+
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
+
+ expect_sort_by('Created on', :asc)
+ end
+
+ it 'sorts by user created on descending' do
+ visit_members_list(sort: :recent_created_user)
+
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
+
+ expect_sort_by('Created on', :desc)
+ end
+
+ it 'sorts by last activity ascending' do
+ visit_members_list(sort: :oldest_last_activity)
+
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
+
+ expect_sort_by('Last activity', :asc)
+ end
+
+ it 'sorts by last activity descending' do
+ visit_members_list(sort: :recent_last_activity)
+
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
+
+ expect_sort_by('Last activity', :desc)
+ end
+
it 'sorts by access granted ascending' do
visit_members_list(sort: :last_joined)
diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb
index 4edf27e8fa4..42eaa8358a1 100644
--- a/spec/features/groups/milestone_spec.rb
+++ b/spec/features/groups/milestone_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe 'Group milestones' do
context 'when no milestones' do
it 'renders no milestones text' do
visit group_milestones_path(group)
- expect(page).to have_content('No milestones to show')
+ expect(page).to have_content('Use milestones to track issues and merge requests')
end
end
diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb
index a06e64fdee0..22d7ff91d41 100644
--- a/spec/features/groups/milestones_sorting_spec.rb
+++ b/spec/features/groups/milestones_sorting_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'Milestones sorting', :js do
sign_in(user)
end
- it 'visit group milestones and sort by due_date_asc' do
+ it 'visit group milestones and sort by due_date_asc', :js do
visit group_milestones_path(group)
expect(page).to have_button('Due soon')
@@ -27,13 +27,13 @@ RSpec.describe 'Milestones sorting', :js do
expect(page.all('ul.content-list > li strong > a').map(&:text)).to eq(['v2.0', 'v2.0', 'v3.0', 'v1.0', 'v1.0'])
end
- click_button 'Due soon'
+ within '[data-testid=milestone_sort_by_dropdown]' do
+ click_button 'Due soon'
+ expect(find('.gl-new-dropdown-contents').all('.gl-new-dropdown-item-text-wrapper p').map(&:text)).to eq(['Due soon', 'Due later', 'Start soon', 'Start later', 'Name, ascending', 'Name, descending'])
- expect(find('ul.dropdown-menu-sort li').all('a').map(&:text)).to eq(['Due soon', 'Due later', 'Start soon', 'Start later', 'Name, ascending', 'Name, descending'])
-
- click_link 'Due later'
-
- expect(page).to have_button('Due later')
+ click_button 'Due later'
+ expect(page).to have_button('Due later')
+ end
# assert descending sorting
within '.milestones' do
diff --git a/spec/features/groups/settings/ci_cd_spec.rb b/spec/features/groups/settings/ci_cd_spec.rb
index 8851aeb6381..c5ad524e647 100644
--- a/spec/features/groups/settings/ci_cd_spec.rb
+++ b/spec/features/groups/settings/ci_cd_spec.rb
@@ -5,52 +5,73 @@ require 'spec_helper'
RSpec.describe 'Group CI/CD settings' do
include WaitForRequests
- let(:user) { create(:user) }
- let(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group, reload: true) { create(:group) }
- before do
+ before_all do
group.add_owner(user)
+ end
+
+ before do
sign_in(user)
end
- describe 'new group runners view banner' do
- it 'displays banner' do
- visit group_settings_ci_cd_path(group)
+ describe 'Runners section' do
+ let(:shared_runners_toggle) { page.find('[data-testid="enable-runners-toggle"]') }
+
+ context 'with runner_list_group_view_vue_ui enabled' do
+ before do
+ visit group_settings_ci_cd_path(group)
+ end
+
+ it 'displays the new group runners view banner' do
+ expect(page).to have_content(s_('Runners|New group runners view'))
+ expect(page).to have_link(href: group_runners_path(group))
+ end
- expect(page).to have_content(s_('Runners|New group runners view'))
- expect(page).to have_link(href: group_runners_path(group))
+ it 'has "Enable shared runners for this group" toggle', :js do
+ expect(shared_runners_toggle).to have_content(_('Enable shared runners for this group'))
+ end
end
- it 'does not display banner' do
- stub_feature_flags(runner_list_group_view_vue_ui: false)
+ context 'with runner_list_group_view_vue_ui disabled' do
+ before do
+ stub_feature_flags(runner_list_group_view_vue_ui: false)
- visit group_settings_ci_cd_path(group)
+ visit group_settings_ci_cd_path(group)
+ end
- expect(page).not_to have_content(s_('Runners|New group runners view'))
- expect(page).not_to have_link(href: group_runners_path(group))
- end
- end
+ it 'does not display the new group runners view banner' do
+ expect(page).not_to have_content(s_('Runners|New group runners view'))
+ expect(page).not_to have_link(href: group_runners_path(group))
+ end
- describe 'runners registration token' do
- let!(:token) { group.runners_token }
+ it 'has "Enable shared runners for this group" toggle', :js do
+ expect(shared_runners_toggle).to have_content(_('Enable shared runners for this group'))
+ end
- before do
- visit group_settings_ci_cd_path(group)
- end
+ context 'with runners registration token' do
+ let!(:token) { group.runners_token }
- it 'has a registration token' do
- expect(page.find('#registration_token')).to have_content(token)
- end
+ before do
+ visit group_settings_ci_cd_path(group)
+ end
- describe 'reload registration token' do
- let(:page_token) { find('#registration_token').text }
+ it 'displays the registration token' do
+ expect(page.find('#registration_token')).to have_content(token)
+ end
- before do
- click_button 'Reset registration token'
- end
+ describe 'reload registration token' do
+ let(:page_token) { find('#registration_token').text }
+
+ before do
+ click_button 'Reset registration token'
+ end
- it 'changes registration token' do
- expect(page_token).not_to eq token
+ it 'changes the registration token' do
+ expect(page_token).not_to eq token
+ end
+ end
end
end
end
diff --git a/spec/features/issuables/shortcuts_issuable_spec.rb b/spec/features/issuables/shortcuts_issuable_spec.rb
index 7e8f39c47a7..528420062dd 100644
--- a/spec/features/issuables/shortcuts_issuable_spec.rb
+++ b/spec/features/issuables/shortcuts_issuable_spec.rb
@@ -15,12 +15,20 @@ RSpec.describe 'Blob shortcuts', :js do
end
shared_examples "quotes the selected text" do
- it "quotes the selected text", :quarantine do
- select_element('.note-text')
+ it 'quotes the selected text in main comment form', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/356388' do
+ select_element('#notes-list .note:first-child .note-text')
find('body').native.send_key('r')
expect(find('.js-main-target-form .js-vue-comment-form').value).to include(note_text)
end
+
+ it 'quotes the selected text in the discussion reply form', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/356388' do
+ find('#notes-list .note:first-child .js-reply-button').click
+ select_element('#notes-list .note:first-child .note-text')
+ find('body').native.send_key('r')
+
+ expect(find('#notes-list .note:first-child .js-vue-markdown-field .js-gfm-input').value).to include(note_text)
+ end
end
describe 'pressing "r"' do
diff --git a/spec/features/issues/incident_issue_spec.rb b/spec/features/issues/incident_issue_spec.rb
index 2956ddede2e..a2519a44604 100644
--- a/spec/features/issues/incident_issue_spec.rb
+++ b/spec/features/issues/incident_issue_spec.rb
@@ -56,5 +56,37 @@ RSpec.describe 'Incident Detail', :js do
end
end
end
+
+ context 'when on summary tab' do
+ before do
+ click_link 'Summary'
+ end
+
+ it 'shows the summary tab with all components' do
+ page.within('.issuable-details') do
+ hidden_items = find_all('.js-issue-widgets')
+
+ # Linked Issues/MRs and comment box
+ expect(hidden_items.count).to eq(2)
+
+ expect(hidden_items).to all(be_visible)
+ end
+ end
+ end
+
+ context 'when on alert details tab' do
+ before do
+ click_link 'Alert details'
+ end
+
+ it 'does not show the linked issues and notes/comment components' do
+ page.within('.issuable-details') do
+ hidden_items = find_all('.js-issue-widgets')
+
+ # Linked Issues/MRs and comment box are hidden on page
+ expect(hidden_items.count).to eq(0)
+ end
+ end
+ end
end
end
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index 446f13dc4d0..8a5e33ba18c 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -71,6 +71,12 @@ RSpec.describe "User creates issue" do
expect(preview).to have_css("gl-emoji")
expect(textarea).not_to be_visible
+
+ click_button("Write")
+ fill_in("Description", with: "/confidential")
+ click_button("Preview")
+
+ expect(form).to have_content('Makes this issue confidential.')
end
end
end
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index 8c906e6a27c..3b440002cb5 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -35,6 +35,12 @@ RSpec.describe "Issues > User edits issue", :js do
end
expect(form).to have_button("Write")
+
+ click_button("Write")
+ fill_in("Description", with: "/confidential")
+ click_button("Preview")
+
+ expect(form).to have_content('Makes this issue confidential.')
end
it 'allows user to select unassigned' do
diff --git a/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb b/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb
index 6473fe01052..311818d2d15 100644
--- a/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb
+++ b/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb
@@ -6,6 +6,10 @@ RSpec.describe 'Issues > Real-time sidebar', :js do
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user) }
+ let_it_be(:label) { create(:label, project: project, name: 'Development') }
+
+ let(:labels_widget) { find('[data-testid="sidebar-labels"]') }
+ let(:labels_value) { find('[data-testid="value-wrapper"]') }
before_all do
project.add_developer(user)
@@ -32,4 +36,37 @@ RSpec.describe 'Issues > Real-time sidebar', :js do
expect(page.find('.assignee')).to have_content user.name
end
end
+
+ it 'updates the label in real-time' do
+ Capybara::Session.new(:other_session)
+
+ using_session :other_session do
+ visit project_issue_path(project, issue)
+ wait_for_requests
+ expect(labels_value).to have_content('None')
+ end
+
+ sign_in(user)
+
+ visit project_issue_path(project, issue)
+ wait_for_requests
+ expect(labels_value).to have_content('None')
+
+ page.within(labels_widget) do
+ click_on 'Edit'
+ end
+
+ wait_for_all_requests
+
+ click_button label.name
+ click_button 'Close'
+
+ wait_for_requests
+
+ expect(labels_value).to have_content(label.name)
+
+ using_session :other_session do
+ expect(labels_value).to have_content(label.name)
+ end
+ end
end
diff --git a/spec/features/jira_connect/subscriptions_spec.rb b/spec/features/jira_connect/subscriptions_spec.rb
index 0b7321bf271..94c293c88b9 100644
--- a/spec/features/jira_connect/subscriptions_spec.rb
+++ b/spec/features/jira_connect/subscriptions_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe 'Subscriptions Content Security Policy' do
it 'appends to CSP directives' do
visit jira_connect_subscriptions_path(jwt: jwt)
- is_expected.to include("frame-ancestors 'self' https://*.atlassian.net")
+ is_expected.to include("frame-ancestors 'self' https://*.atlassian.net https://*.jira.com")
is_expected.to include("script-src 'self' https://some-cdn.test https://connect-cdn.atl-paas.net")
is_expected.to include("style-src 'self' https://some-cdn.test 'unsafe-inline'")
end
diff --git a/spec/features/jira_oauth_provider_authorize_spec.rb b/spec/features/jira_oauth_provider_authorize_spec.rb
index daecae56101..a216d2d44b2 100644
--- a/spec/features/jira_oauth_provider_authorize_spec.rb
+++ b/spec/features/jira_oauth_provider_authorize_spec.rb
@@ -4,13 +4,13 @@ require 'spec_helper'
RSpec.describe 'JIRA OAuth Provider' do
describe 'JIRA DVCS OAuth Authorization' do
- let(:application) { create(:oauth_application, redirect_uri: oauth_jira_callback_url, scopes: 'read_user') }
+ let(:application) { create(:oauth_application, redirect_uri: oauth_jira_dvcs_callback_url, scopes: 'read_user') }
before do
sign_in(user)
- visit oauth_jira_authorize_path(client_id: application.uid,
- redirect_uri: oauth_jira_callback_url,
+ visit oauth_jira_dvcs_authorize_path(client_id: application.uid,
+ redirect_uri: oauth_jira_dvcs_callback_url,
response_type: 'code',
state: 'my_state',
scope: 'read_user')
diff --git a/spec/features/merge_request/user_merges_merge_request_spec.rb b/spec/features/merge_request/user_merges_merge_request_spec.rb
index d1be93cae02..a861ca2eea5 100644
--- a/spec/features/merge_request/user_merges_merge_request_spec.rb
+++ b/spec/features/merge_request/user_merges_merge_request_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe "User merges a merge request", :js do
end
shared_examples "fast forward merge a merge request" do
- it "merges a merge request", :sidekiq_might_not_need_inline do
+ it "merges a merge request", :sidekiq_inline do
expect(page).to have_content("Fast-forward merge without a merge commit").and have_button("Merge")
page.within(".mr-state-widget") do
@@ -42,4 +42,23 @@ RSpec.describe "User merges a merge request", :js do
it_behaves_like "fast forward merge a merge request"
end
end
+
+ context 'sidebar merge requests counter' do
+ let(:project) { create(:project, :public, :repository) }
+ let!(:merge_request) { create(:merge_request, source_project: project) }
+
+ it 'decrements the open MR count', :sidekiq_inline do
+ create(:merge_request, source_project: project, source_branch: 'branch-1')
+
+ visit(merge_request_path(merge_request))
+
+ expect(page).to have_css('.js-merge-counter', text: '2')
+
+ page.within(".mr-state-widget") do
+ click_button("Merge")
+ end
+
+ expect(page).to have_css('.js-merge-counter', text: '1')
+ end
+ end
end
diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb
index 1779567624c..ad602afe68a 100644
--- a/spec/features/merge_request/user_posts_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_notes_spec.rb
@@ -169,7 +169,7 @@ RSpec.describe 'Merge request > User posts notes', :js do
end
page.within('.modal') do
- click_button('OK', match: :first)
+ click_button('Cancel editing', match: :first)
end
expect(find('.js-note-text').text).to eq ''
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 27f7c699c50..c9b21d4a4ae 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -17,6 +17,9 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
project.add_maintainer(user)
project_only_mwps.add_maintainer(user)
sign_in(user)
+
+ stub_feature_flags(refactor_mr_widgets_extensions: false)
+ stub_feature_flags(refactor_mr_widgets_extensions_user: false)
end
context 'new merge request', :sidekiq_might_not_need_inline do
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 beb658bb7a0..f77a42ee506 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
@@ -379,4 +379,41 @@ RSpec.describe 'User comments on a diff', :js do
end
end
end
+
+ context 'failed to load metadata' do
+ let(:dummy_controller) do
+ Class.new(Projects::MergeRequests::DiffsController) do
+ def diffs_metadata
+ render json: '', status: :internal_server_error
+ end
+ end
+ end
+
+ before do
+ stub_const('Projects::MergeRequests::DiffsController', dummy_controller)
+
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
+
+ page.within('.js-discussion-note-form') do
+ fill_in('note_note', with: "```suggestion\n# change to a comment\n```")
+ click_button('Add comment now')
+ end
+
+ wait_for_requests
+
+ visit(project_merge_request_path(project, merge_request))
+
+ wait_for_requests
+ end
+
+ it 'displays an error' do
+ page.within('.discussion-notes') do
+ click_button('Apply suggestion')
+
+ wait_for_requests
+
+ expect(page).to have_content('Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct.')
+ end
+ end
+ end
end
diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb
index f781ba0827c..a15b6072e70 100644
--- a/spec/features/merge_requests/user_mass_updates_spec.rb
+++ b/spec/features/merge_requests/user_mass_updates_spec.rb
@@ -70,7 +70,7 @@ RSpec.describe 'Merge requests > User mass updates', :js do
it 'updates merge request with assignee' do
change_assignee(user.name)
- expect(find('.issuable-meta a.author-link')[:title]).to eq "Attention requested from assignee #{user.name}, go to their profile."
+ expect(find('.issuable-meta a.author-link')[:title]).to eq "Attention requested from assignee #{user.name}"
end
end
end
diff --git a/spec/features/milestones/user_deletes_milestone_spec.rb b/spec/features/milestones/user_deletes_milestone_spec.rb
index ede9faed876..40626407642 100644
--- a/spec/features/milestones/user_deletes_milestone_spec.rb
+++ b/spec/features/milestones/user_deletes_milestone_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe "User deletes milestone", :js do
click_button("Delete")
click_button("Delete milestone")
- expect(page).to have_content("No milestones to show")
+ expect(page).to have_content("Use milestones to track issues and merge requests over a fixed period of time")
visit(activity_project_path(project))
diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb
index 93674057fed..ea5bb8c33b2 100644
--- a/spec/features/oauth_login_spec.rb
+++ b/spec/features/oauth_login_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'OAuth Login', :js, :allow_forgery_protection do
end
providers = [:github, :twitter, :bitbucket, :gitlab, :google_oauth2,
- :facebook, :cas3, :auth0, :authentiq, :salesforce, :dingtalk]
+ :facebook, :cas3, :auth0, :authentiq, :salesforce, :dingtalk, :alicloud]
around do |example|
with_omniauth_full_host { example.run }
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index f1e5658cd7b..8cbc0491441 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -47,14 +47,14 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
click_on "1"
# Scopes
- check "api"
+ check "read_api"
check "read_user"
click_on "Create personal access token"
expect(active_personal_access_tokens).to have_text(name)
expect(active_personal_access_tokens).to have_text('in')
- expect(active_personal_access_tokens).to have_text('api')
+ expect(active_personal_access_tokens).to have_text('read_api')
expect(active_personal_access_tokens).to have_text('read_user')
expect(created_personal_access_token).not_to be_empty
end
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 026da5814e3..4b6ed458c68 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -8,8 +8,6 @@ RSpec.describe 'User edit profile' do
let(:user) { create(:user) }
before do
- stub_feature_flags(improved_emoji_picker: false)
-
sign_in(user)
visit(profile_path)
end
@@ -169,10 +167,9 @@ RSpec.describe 'User edit profile' do
context 'user status', :js do
def select_emoji(emoji_name, is_modal = false)
- emoji_menu_class = is_modal ? '.js-modal-status-emoji-menu' : '.js-status-emoji-menu'
- toggle_button = find('.js-toggle-emoji-menu')
+ toggle_button = find('.emoji-menu-toggle-button')
toggle_button.click
- emoji_button = find(%Q{#{emoji_menu_class} .js-emoji-btn gl-emoji[data-name="#{emoji_name}"]})
+ emoji_button = find("gl-emoji[data-name=\"#{emoji_name}\"]")
emoji_button.click
end
@@ -207,7 +204,7 @@ RSpec.describe 'User edit profile' do
end
it 'adds message and emoji to user status' do
- emoji = 'tanabata_tree'
+ emoji = '8ball'
message = 'Playing outside'
select_emoji(emoji)
fill_in 'js-status-message-field', with: message
@@ -356,7 +353,7 @@ RSpec.describe 'User edit profile' do
end
it 'adds emoji to user status' do
- emoji = 'biohazard'
+ emoji = '8ball'
open_user_status_modal
select_emoji(emoji, true)
set_user_status_in_modal
@@ -387,18 +384,18 @@ RSpec.describe 'User edit profile' do
it 'opens the emoji modal again after closing it' do
open_user_status_modal
- select_emoji('biohazard', true)
+ select_emoji('8ball', true)
- find('.js-toggle-emoji-menu').click
+ find('.emoji-menu-toggle-button').click
- expect(page).to have_selector('.emoji-menu')
+ expect(page).to have_selector('.emoji-picker-emoji')
end
it 'does not update the awards panel emoji' do
project.add_maintainer(user)
visit(project_issue_path(project, issue))
- emoji = 'biohazard'
+ emoji = '8ball'
open_user_status_modal
select_emoji(emoji, true)
@@ -420,7 +417,7 @@ RSpec.describe 'User edit profile' do
end
it 'adds message and emoji to user status' do
- emoji = 'tanabata_tree'
+ emoji = '8ball'
message = 'Playing outside'
open_user_status_modal
select_emoji(emoji, true)
@@ -495,9 +492,7 @@ RSpec.describe 'User edit profile' do
open_user_status_modal
find('.js-status-message-field').native.send_keys(message)
- within('.js-toggle-emoji-menu') do
- expect(page).to have_emoji('speech_balloon')
- end
+ expect(page).to have_emoji('speech_balloon')
end
context 'note header' do
diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
index e19e29bf63a..4c61e8d45e4 100644
--- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
+++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
@@ -18,14 +18,6 @@ RSpec.describe 'User visits the profile preferences page', :js do
end
describe 'User changes their syntax highlighting theme', :js do
- it 'creates a flash message' do
- choose 'user_color_scheme_id_5'
-
- wait_for_requests
-
- expect_preferences_saved_message
- end
-
it 'updates their preference' do
choose 'user_color_scheme_id_5'
diff --git a/spec/features/projects/blobs/balsamiq_spec.rb b/spec/features/projects/blobs/balsamiq_spec.rb
deleted file mode 100644
index bce60856544..00000000000
--- a/spec/features/projects/blobs/balsamiq_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Balsamiq file blob', :js do
- let(:project) { create(:project, :public, :repository) }
-
- before do
- visit project_blob_path(project, 'add-balsamiq-file/files/images/balsamiq.bmpr')
-
- wait_for_requests
- end
-
- it 'displays Balsamiq file content' do
- expect(page).to have_content("Mobile examples")
- end
-end
diff --git a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb
index 11e2d24c36a..9b0edcd09d2 100644
--- a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb
+++ b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do
find('#L3').click
find("#L5").click
- expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: "LC5")))
+ expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: "L5")))
end
it 'with initial fragment hash, changes fragment hash if line number clicked' do
@@ -50,7 +50,7 @@ RSpec.describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do
find('#L3').click
find("#L5").click
- expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: "LC5")))
+ expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: "L5")))
end
end
@@ -75,7 +75,7 @@ RSpec.describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do
find('#L3').click
find("#L5").click
- expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: "LC5")))
+ expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: "L5")))
end
it 'with initial fragment hash, changes fragment hash if line number clicked' do
@@ -86,7 +86,7 @@ RSpec.describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do
find('#L3').click
find("#L5").click
- expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: "LC5")))
+ expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: "L5")))
end
end
end
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index 363d08da024..d906bb396be 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -36,6 +36,8 @@ RSpec.describe 'Branches' do
expect(page).to have_content(sorted_branches(repository, count: 5, sort_by: :updated_desc, state: 'active'))
expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_asc, state: 'stale'))
+ expect(page).to have_button('Copy branch name')
+
expect(page).to have_link('Show more active branches', href: project_branches_filtered_path(project, state: 'active'))
expect(page).not_to have_content('Show more stale branches')
end
@@ -197,14 +199,6 @@ RSpec.describe 'Branches' do
project.add_maintainer(user)
end
- describe 'Initial branches page' do
- it 'shows description for admin' do
- visit project_branches_filtered_path(project, state: 'all')
-
- expect(page).to have_content("Protected branches can be managed in project settings")
- end
- end
-
it 'shows the merge request button' do
visit project_branches_path(project)
diff --git a/spec/features/projects/cluster_agents_spec.rb b/spec/features/projects/cluster_agents_spec.rb
index e9162359940..5d931afe4a7 100644
--- a/spec/features/projects/cluster_agents_spec.rb
+++ b/spec/features/projects/cluster_agents_spec.rb
@@ -27,7 +27,6 @@ RSpec.describe 'ClusterAgents', :js do
end
it 'displays empty state', :aggregate_failures do
- expect(page).to have_content('Install a new agent')
expect(page).to have_selector('.empty-state')
end
end
diff --git a/spec/features/projects/clusters/eks_spec.rb b/spec/features/projects/clusters/eks_spec.rb
index 0dd6effe551..7e599ff1198 100644
--- a/spec/features/projects/clusters/eks_spec.rb
+++ b/spec/features/projects/clusters/eks_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'AWS EKS Cluster', :js do
visit project_clusters_path(project)
click_button(class: 'dropdown-toggle-split')
- click_link 'Create a new cluster'
+ click_link 'Create a cluster (certificate - deprecated)'
end
context 'when user creates a cluster on AWS EKS' do
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 90d7e2d02e9..491121a3743 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe 'Gcp Cluster', :js do
visit project_clusters_path(project)
click_button(class: 'dropdown-toggle-split')
- click_link 'Connect with a certificate'
+ click_link 'Connect a cluster (certificate - deprecated)'
end
it 'user sees the "Environment scope" field' do
@@ -154,7 +154,6 @@ RSpec.describe 'Gcp Cluster', :js do
it 'user sees creation form with the successful message' do
expect(page).to have_content('Kubernetes cluster integration was successfully removed.')
- expect(page).to have_link('Connect with a certificate')
end
end
end
@@ -220,6 +219,6 @@ RSpec.describe 'Gcp Cluster', :js do
def visit_create_cluster_page
click_button(class: 'dropdown-toggle-split')
- click_link 'Create a new cluster'
+ click_link 'Create a cluster (certificate - deprecated)'
end
end
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index 3fd78d338da..b6bfaa3a9b9 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -25,8 +25,8 @@ RSpec.describe 'User Cluster', :js do
before do
visit project_clusters_path(project)
- click_link 'Certificate'
- click_link 'Connect with a certificate'
+ click_button(class: 'dropdown-toggle-split')
+ click_link 'Connect a cluster (certificate - deprecated)'
end
context 'when user filled form with valid parameters' do
@@ -108,7 +108,6 @@ RSpec.describe 'User Cluster', :js do
it 'user sees creation form with the successful message' do
expect(page).to have_content('Kubernetes cluster integration was successfully removed.')
- expect(page).to have_link('Connect with a certificate')
end
end
end
diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb
index b9a544144c3..0ecd7795964 100644
--- a/spec/features/projects/clusters_spec.rb
+++ b/spec/features/projects/clusters_spec.rb
@@ -20,7 +20,6 @@ RSpec.describe 'Clusters', :js do
end
it 'sees empty state' do
- expect(page).to have_link('Connect with a certificate')
expect(page).to have_selector('.empty-state')
end
end
@@ -222,11 +221,11 @@ RSpec.describe 'Clusters', :js do
visit project_clusters_path(project)
click_button(class: 'dropdown-toggle-split')
- click_link 'Create a new cluster'
+ click_link 'Create a cluster (certificate - deprecated)'
end
def visit_connect_cluster_page
click_button(class: 'dropdown-toggle-split')
- click_link 'Connect with a certificate'
+ click_link 'Connect a cluster (certificate - deprecated)'
end
end
diff --git a/spec/features/projects/commits/multi_view_diff_spec.rb b/spec/features/projects/commits/multi_view_diff_spec.rb
index ecdd398c739..009dd05c6d1 100644
--- a/spec/features/projects/commits/multi_view_diff_spec.rb
+++ b/spec/features/projects/commits/multi_view_diff_spec.rb
@@ -27,17 +27,11 @@ RSpec.describe 'Multiple view Diffs', :js do
context 'when :rendered_diffs_viewer is off' do
context 'and diff does not have ipynb' do
- include_examples "no multiple viewers", 'ddd0f15ae83993f5cb66a927a28673882e99100b'
+ it_behaves_like "no multiple viewers", 'ddd0f15ae83993f5cb66a927a28673882e99100b'
end
context 'and diff has ipynb' do
- include_examples "no multiple viewers", '5d6ed1503801ca9dc28e95eeb85a7cf863527aee'
-
- it 'shows the transformed diff' do
- diff = page.find('.diff-file, .file-holder', match: :first)
-
- expect(diff['innerHTML']).to include('%% Cell type:markdown id:0aac5da7-745c-4eda-847a-3d0d07a1bb9b tags:')
- end
+ it_behaves_like "no multiple viewers", '5d6ed1503801ca9dc28e95eeb85a7cf863527aee'
end
end
@@ -45,14 +39,28 @@ RSpec.describe 'Multiple view Diffs', :js do
let(:feature_flag_on) { true }
context 'and diff does not include ipynb' do
- include_examples "no multiple viewers", 'ddd0f15ae83993f5cb66a927a28673882e99100b'
- end
+ it_behaves_like "no multiple viewers", 'ddd0f15ae83993f5cb66a927a28673882e99100b'
- context 'and opening a diff with ipynb' do
- context 'but the changes are not renderable' do
- include_examples "no multiple viewers", 'a867a602d2220e5891b310c07d174fbe12122830'
+ context 'and in inline diff' do
+ let(:ref) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' }
+
+ it 'does not change display for non-ipynb' do
+ expect(page).to have_selector line_with_content('new', 1)
+ end
end
+ context 'and in parallel diff' do
+ let(:ref) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' }
+
+ it 'does not change display for non-ipynb' do
+ page.find('#parallel-diff-btn').click
+
+ expect(page).to have_selector line_with_content('new', 1)
+ end
+ end
+ end
+
+ context 'and opening a diff with ipynb' do
it 'loads the rendered diff as hidden' do
diff = page.find('.diff-file, .file-holder', match: :first)
@@ -76,10 +84,55 @@ RSpec.describe 'Multiple view Diffs', :js do
expect(classes_for_element(diff, 'toHideBtn')).not_to include('selected')
expect(classes_for_element(diff, 'toShowBtn')).to include('selected')
end
+
+ it 'transforms the diff' do
+ diff = page.find('.diff-file, .file-holder', match: :first)
+
+ expect(diff['innerHTML']).to include('%% Cell type:markdown id:0aac5da7-745c-4eda-847a-3d0d07a1bb9b tags:')
+ end
+
+ context 'on parallel view' do
+ before do
+ page.find('#parallel-diff-btn').click
+ end
+
+ it 'lines without mapping cannot receive comments' do
+ expect(page).not_to have_selector('td.line_content.nomappinginraw ~ td.diff-line-num > .add-diff-note')
+ expect(page).to have_selector('td.line_content:not(.nomappinginraw) ~ td.diff-line-num > .add-diff-note')
+ end
+
+ it 'lines numbers without mapping are empty' do
+ expect(page).not_to have_selector('td.nomappinginraw + td.diff-line-num')
+ expect(page).to have_selector('td.nomappinginraw + td.diff-line-num', visible: false)
+ end
+
+ it 'transforms the diff' do
+ diff = page.find('.diff-file, .file-holder', match: :first)
+
+ expect(diff['innerHTML']).to include('%% Cell type:markdown id:0aac5da7-745c-4eda-847a-3d0d07a1bb9b tags:')
+ end
+ end
+
+ context 'on inline view' do
+ it 'lines without mapping cannot receive comments' do
+ expect(page).not_to have_selector('tr.line_holder[class$="nomappinginraw"] > td.diff-line-num > .add-diff-note')
+ expect(page).to have_selector('tr.line_holder:not([class$="nomappinginraw"]) > td.diff-line-num > .add-diff-note')
+ end
+
+ it 'lines numbers without mapping are empty' do
+ elements = page.all('tr.line_holder[class$="nomappinginraw"] > td.diff-line-num').map { |e| e.text(:all) }
+
+ expect(elements).to all(be == "")
+ end
+ end
end
end
def classes_for_element(node, data_diff_entity, visible: true)
node.find("[data-diff-toggle-entity=\"#{data_diff_entity}\"]", visible: visible)[:class]
end
+
+ def line_with_content(old_or_new, line_number)
+ "td.#{old_or_new}_line.diff-line-num[data-linenumber=\"#{line_number}\"] > a[data-linenumber=\"#{line_number}\"]"
+ end
end
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 99137018d6b..6cf59394af7 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -70,7 +70,7 @@ RSpec.describe 'Environments page', :js do
it 'shows no environments' do
visit_environments(project, scope: 'stopped')
- expect(page).to have_content('You don\'t have any environments right now')
+ expect(page).to have_content(s_('Environments|You don\'t have any stopped environments.'))
end
end
@@ -99,7 +99,7 @@ RSpec.describe 'Environments page', :js do
it 'shows no environments' do
visit_environments(project, scope: 'available')
- expect(page).to have_content('You don\'t have any environments right now')
+ expect(page).to have_content(s_('Environments|You don\'t have any environments.'))
end
end
@@ -120,7 +120,7 @@ RSpec.describe 'Environments page', :js do
end
it 'does not show environments and counters are set to zero' do
- expect(page).to have_content('You don\'t have any environments right now')
+ expect(page).to have_content(s_('Environments|You don\'t have any environments.'))
expect(page).to have_link("#{_('Available')} 0")
expect(page).to have_link("#{_('Stopped')} 0")
diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb
index 1e5c5d33ad9..c7fbaa85483 100644
--- a/spec/features/projects/import_export/import_file_spec.rb
+++ b/spec/features/projects/import_export/import_file_spec.rb
@@ -24,9 +24,9 @@ RSpec.describe 'Import/Export - project import integration test', :js do
context 'when selecting the namespace' do
let(:user) { create(:admin) }
let!(:namespace) { user.namespace }
- let(:randomHex) { SecureRandom.hex }
- let(:project_name) { 'Test Project Name' + randomHex }
- let(:project_path) { 'test-project-name' + randomHex }
+ let(:random_hex) { SecureRandom.hex }
+ let(:project_name) { 'Test Project Name' + random_hex }
+ let(:project_path) { 'test-project-name' + random_hex }
it 'user imports an exported project successfully', :sidekiq_might_not_need_inline do
visit new_project_path
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 762f9c33510..48ae70d3ec9 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
@@ -10,8 +10,8 @@ RSpec.describe 'User uploads new design', :js do
let(:issue) { create(:issue, project: project) }
before do
- # Cause of raising query limiting threshold https://gitlab.com/gitlab-org/gitlab/-/issues/347334
- stub_const("Gitlab::QueryLimiting::Transaction::THRESHOLD", 102)
+ # Cause of raising query limiting threshold https://gitlab.com/gitlab-org/gitlab/-/issues/358845
+ stub_const("Gitlab::QueryLimiting::Transaction::THRESHOLD", 106)
sign_in(user)
enable_design_management(feature_enabled)
diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb
index fde6240d373..3b70d177fce 100644
--- a/spec/features/projects/jobs/user_browses_jobs_spec.rb
+++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb
@@ -67,19 +67,8 @@ RSpec.describe 'User browses jobs' do
expect(page.find('[data-testid="jobs-all-tab"] .badge').text).to include('0')
end
- it 'shows a tab for Pending jobs and count' do
- expect(page.find('[data-testid="jobs-pending-tab"]').text).to include('Pending')
- expect(page.find('[data-testid="jobs-pending-tab"] .badge').text).to include('0')
- end
-
- it 'shows a tab for Running jobs and count' do
- expect(page.find('[data-testid="jobs-running-tab"]').text).to include('Running')
- expect(page.find('[data-testid="jobs-running-tab"] .badge').text).to include('0')
- end
-
it 'shows a tab for Finished jobs and count' do
expect(page.find('[data-testid="jobs-finished-tab"]').text).to include('Finished')
- expect(page.find('[data-testid="jobs-finished-tab"] .badge').text).to include('0')
end
it 'updates the content when tab is clicked' do
diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb
index 6adc3503492..9bd6476f836 100644
--- a/spec/features/projects/members/groups_with_access_list_spec.rb
+++ b/spec/features/projects/members/groups_with_access_list_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Members > Groups with access list', :js do
include Spec::Support::Helpers::Features::MembersHelpers
include Spec::Support::Helpers::ModalHelpers
+ include Spec::Support::Helpers::Features::InviteMembersModalHelper
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
@@ -95,8 +96,4 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do
expect(members_table).to have_content(group.full_name)
end
end
-
- def click_groups_tab
- click_link 'Groups'
- end
end
diff --git a/spec/features/projects/members/invite_group_spec.rb b/spec/features/projects/members/invite_group_spec.rb
index 9c256504934..a48229249e0 100644
--- a/spec/features/projects/members/invite_group_spec.rb
+++ b/spec/features/projects/members/invite_group_spec.rb
@@ -17,20 +17,18 @@ RSpec.describe 'Project > Members > Invite group', :js do
visit project_project_members_path(project)
- expect(page).to have_selector('button[data-test-id="invite-group-button"]')
+ expect(page).to have_selector(invite_group_selector)
end
- it 'does not display the button when visiting the page not signed in' do
+ it 'does not display the button when visiting the page not signed in' do
project = create(:project, namespace: create(:group))
visit project_project_members_path(project)
- expect(page).not_to have_selector('button[data-test-id="invite-group-button"]')
+ expect(page).not_to have_selector(invite_group_selector)
end
describe 'Share with group lock' do
- let(:invite_group_selector) { 'button[data-test-id="invite-group-button"]' }
-
shared_examples 'the project can be shared with groups' do
it 'the "Invite a group" button exists' do
visit project_project_members_path(project)
@@ -158,21 +156,95 @@ RSpec.describe 'Project > Members > Invite group', :js do
describe 'the groups dropdown' do
let_it_be(:parent_group) { create(:group, :public) }
let_it_be(:project_group) { create(:group, :public, parent: parent_group) }
- let_it_be(:public_sub_subgroup) { create(:group, :public, parent: project_group) }
- let_it_be(:public_sibbling_group) { create(:group, :public, parent: parent_group) }
- let_it_be(:private_sibbling_group) { create(:group, :private, parent: parent_group) }
- let_it_be(:private_membership_group) { create(:group, :private) }
- let_it_be(:public_membership_group) { create(:group, :public) }
let_it_be(:project) { create(:project, group: project_group) }
- before do
- private_membership_group.add_guest(maintainer)
- public_membership_group.add_maintainer(maintainer)
+ context 'with instance admin considerations' do
+ let_it_be(:group_to_share) { create(:group) }
- sign_in(maintainer)
+ context 'when user is an admin' do
+ let_it_be(:admin) { create(:admin) }
+
+ before do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ end
+
+ it 'shows groups where the admin has no direct membership' do
+ visit project_project_members_path(project)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_to_share)
+ end
+ end
+
+ it 'shows groups where the admin has at least guest level membership' do
+ group_to_share.add_guest(admin)
+
+ visit project_project_members_path(project)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_to_share)
+ end
+ end
+ end
+
+ context 'when user is not an admin' do
+ before do
+ project.add_maintainer(maintainer)
+ sign_in(maintainer)
+ end
+
+ it 'does not show groups where the user has no direct membership' do
+ visit project_project_members_path(project)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_not_to_have_group(group_to_share)
+ end
+ end
+
+ it 'shows groups where the user has at least guest level membership' do
+ group_to_share.add_guest(maintainer)
+
+ visit project_project_members_path(project)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within(group_dropdown_selector) do
+ expect_to_have_group(group_to_share)
+ end
+ end
+ end
end
context 'for a project in a nested group' do
+ let_it_be(:public_sub_subgroup) { create(:group, :public, parent: project_group) }
+ let_it_be(:public_sibbling_group) { create(:group, :public, parent: parent_group) }
+ let_it_be(:private_sibbling_group) { create(:group, :private, parent: parent_group) }
+ let_it_be(:private_membership_group) { create(:group, :private) }
+ let_it_be(:public_membership_group) { create(:group, :public) }
+ let_it_be(:project) { create(:project, group: project_group) }
+
+ before do
+ private_membership_group.add_guest(maintainer)
+ public_membership_group.add_maintainer(maintainer)
+
+ sign_in(maintainer)
+ end
+
it 'does not show the groups inherited from projects' do
project.add_maintainer(maintainer)
public_sibbling_group.add_maintainer(maintainer)
@@ -183,7 +255,7 @@ RSpec.describe 'Project > Members > Invite group', :js do
click_on 'Select a group'
wait_for_requests
- page.within('[data-testid="group-select-dropdown"]') do
+ page.within(group_dropdown_selector) do
expect_to_have_group(public_membership_group)
expect_to_have_group(public_sibbling_group)
expect_to_have_group(private_membership_group)
@@ -204,7 +276,7 @@ RSpec.describe 'Project > Members > Invite group', :js do
click_on 'Select a group'
wait_for_requests
- page.within('[data-testid="group-select-dropdown"]') do
+ page.within(group_dropdown_selector) do
expect_to_have_group(public_membership_group)
expect_to_have_group(public_sibbling_group)
expect_to_have_group(private_membership_group)
@@ -215,14 +287,10 @@ RSpec.describe 'Project > Members > Invite group', :js do
expect_not_to_have_group(project_group)
end
end
-
- def expect_to_have_group(group)
- expect(page).to have_selector("[entity-id='#{group.id}']")
- end
-
- def expect_not_to_have_group(group)
- expect(page).not_to have_selector("[entity-id='#{group.id}']")
- end
end
end
+
+ def invite_group_selector
+ 'button[data-test-id="invite-group-button"]'
+ end
end
diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/manage_members_spec.rb
index f2424a4acc3..0f4120e88e0 100644
--- a/spec/features/projects/members/list_spec.rb
+++ b/spec/features/projects/members/manage_members_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project members list', :js do
+RSpec.describe 'Projects > Members > Manage members', :js do
include Spec::Support::Helpers::Features::MembersHelpers
include Spec::Support::Helpers::Features::InviteMembersModalHelper
include Spec::Support::Helpers::ModalHelpers
@@ -48,24 +48,6 @@ RSpec.describe 'Project members list', :js do
end
end
- it 'add user to project', :snowplow, :aggregate_failures do
- visit_members_page
-
- invite_member(user2.name, role: 'Reporter')
-
- page.within find_member_row(user2) do
- expect(page).to have_button('Reporter')
- end
-
- expect_snowplow_event(
- category: 'Members::CreateService',
- action: 'create_member',
- label: 'project-members-page',
- property: 'existing_user',
- user: user1
- )
- end
-
it 'uses ProjectMember access_level_roles for the invite members modal access option', :aggregate_failures do
visit_members_page
@@ -104,24 +86,41 @@ RSpec.describe 'Project members list', :js do
expect(members_table).not_to have_content(other_user.name)
end
- it 'invite user to project', :snowplow, :aggregate_failures do
- visit_members_page
+ it_behaves_like 'inviting members', 'project-members-page' do
+ let_it_be(:entity) { project }
+ let_it_be(:members_page_path) { project_project_members_path(entity) }
+ let_it_be(:subentity) { project }
+ let_it_be(:subentity_members_page_path) { project_project_members_path(entity) }
+ end
- invite_member('test@example.com', role: 'Reporter')
+ describe 'member search results' do
+ it 'does not show project_bots', :aggregate_failures do
+ internal_project_bot = create(:user, :project_bot, name: '_internal_project_bot_')
+ project.add_maintainer(internal_project_bot)
- click_link 'Invited'
+ external_group = create(:group)
+ external_project_bot = create(:user, :project_bot, name: '_external_project_bot_')
+ external_project = create(:project, group: external_group)
+ external_project.add_maintainer(external_project_bot)
+ external_project.add_maintainer(user1)
- page.within find_invited_member_row('test@example.com') do
- expect(page).to have_button('Reporter')
- end
+ visit_members_page
+
+ click_on 'Invite members'
- expect_snowplow_event(
- category: 'Members::InviteService',
- action: 'create_member',
- label: 'project-members-page',
- property: 'net_new_user',
- user: user1
- )
+ page.within invite_modal_selector do
+ field = find(member_dropdown_selector)
+ field.native.send_keys :tab
+ field.click
+
+ wait_for_requests
+
+ expect(page).to have_content(user1.name)
+ expect(page).to have_content(user2.name)
+ expect(page).not_to have_content(internal_project_bot.name)
+ expect(page).not_to have_content(external_project_bot.name)
+ end
+ end
end
context 'as a signed out visitor viewing a public project' do
diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb
index 653564d1566..8aadd6302d0 100644
--- a/spec/features/projects/members/sorting_spec.rb
+++ b/spec/features/projects/members/sorting_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'Projects > Members > Sorting', :js do
include Spec::Support::Helpers::Features::MembersHelpers
- let(:maintainer) { create(:user, name: 'John Doe') }
- let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) }
+ let(:maintainer) { create(:user, name: 'John Doe', created_at: 5.days.ago, last_activity_on: Date.today) }
+ let(:developer) { create(:user, name: 'Mary Jane', created_at: 1.day.ago, last_sign_in_at: 5.days.ago, last_activity_on: Date.today - 5) }
let(:project) { create(:project, namespace: maintainer.namespace, creator: maintainer) }
before do
@@ -42,6 +42,42 @@ RSpec.describe 'Projects > Members > Sorting', :js do
expect_sort_by('Max role', :desc)
end
+ it 'sorts by user created on ascending' do
+ visit_members_list(sort: :oldest_created_user)
+
+ expect(first_row.text).to have_content(maintainer.name)
+ expect(second_row.text).to have_content(developer.name)
+
+ expect_sort_by('Created on', :asc)
+ end
+
+ it 'sorts by user created on descending' do
+ visit_members_list(sort: :recent_created_user)
+
+ expect(first_row.text).to have_content(developer.name)
+ expect(second_row.text).to have_content(maintainer.name)
+
+ expect_sort_by('Created on', :desc)
+ end
+
+ it 'sorts by last activity ascending' do
+ visit_members_list(sort: :oldest_last_activity)
+
+ expect(first_row.text).to have_content(developer.name)
+ expect(second_row.text).to have_content(maintainer.name)
+
+ expect_sort_by('Last activity', :asc)
+ end
+
+ it 'sorts by last activity descending' do
+ visit_members_list(sort: :recent_last_activity)
+
+ expect(first_row.text).to have_content(maintainer.name)
+ expect(second_row.text).to have_content(developer.name)
+
+ expect_sort_by('Last activity', :desc)
+ end
+
it 'sorts by access granted ascending' do
visit_members_list(sort: :last_joined)
diff --git a/spec/features/projects/milestones/milestones_sorting_spec.rb b/spec/features/projects/milestones/milestones_sorting_spec.rb
index 565c61cfaa0..2ad820e4a06 100644
--- a/spec/features/projects/milestones/milestones_sorting_spec.rb
+++ b/spec/features/projects/milestones/milestones_sorting_spec.rb
@@ -5,49 +5,55 @@ require 'spec_helper'
RSpec.describe 'Milestones sorting', :js do
let(:user) { create(:user) }
let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+ let(:milestones_for_sort_by) do
+ {
+ 'Due later' => %w[b c a],
+ 'Name, ascending' => %w[a b c],
+ 'Name, descending' => %w[c b a],
+ 'Start later' => %w[a c b],
+ 'Start soon' => %w[b c a],
+ 'Due soon' => %w[a c b]
+ }
+ end
+
+ let(:ordered_milestones) do
+ ['Due soon', 'Due later', 'Start soon', 'Start later', 'Name, ascending', 'Name, descending']
+ end
before do
- # Milestones
- create(:milestone,
- due_date: 10.days.from_now,
- created_at: 2.hours.ago,
- title: "aaa", project: project)
- create(:milestone,
- due_date: 11.days.from_now,
- created_at: 1.hour.ago,
- title: "bbb", project: project)
+ create(:milestone, start_date: 7.days.from_now, due_date: 10.days.from_now, title: "a", project: project)
+ create(:milestone, start_date: 6.days.from_now, due_date: 11.days.from_now, title: "c", project: project)
+ create(:milestone, start_date: 5.days.from_now, due_date: 12.days.from_now, title: "b", project: project)
sign_in(user)
end
- it 'visit project milestones and sort by due_date_asc' do
+ it 'visit project milestones and sort by various orders' do
visit project_milestones_path(project)
expect(page).to have_button('Due soon')
- # assert default sorting
+ # assert default sorting order
within '.milestones' do
- expect(page.all('ul.content-list > li').first.text).to include('aaa')
- expect(page.all('ul.content-list > li').last.text).to include('bbb')
+ expect(page.all('ul.content-list > li strong > a').map(&:text)).to eq(%w[a c b])
end
- click_button 'Due soon'
+ # assert milestones listed for given sort order
+ selected_sort_order = 'Due soon'
+ milestones_for_sort_by.each do |sort_by, expected_milestones|
+ within '[data-testid=milestone_sort_by_dropdown]' do
+ click_button selected_sort_order
+ milestones = find('.gl-new-dropdown-contents').all('.gl-new-dropdown-item-text-wrapper p').map(&:text)
+ expect(milestones).to eq(ordered_milestones)
- sort_options = find('ul.dropdown-menu-sort li').all('a').collect(&:text)
+ click_button sort_by
+ expect(page).to have_button(sort_by)
+ end
- expect(sort_options[0]).to eq('Due soon')
- expect(sort_options[1]).to eq('Due later')
- expect(sort_options[2]).to eq('Start soon')
- expect(sort_options[3]).to eq('Start later')
- expect(sort_options[4]).to eq('Name, ascending')
- expect(sort_options[5]).to eq('Name, descending')
+ within '.milestones' do
+ expect(page.all('ul.content-list > li strong > a').map(&:text)).to eq(expected_milestones)
+ end
- click_link 'Due later'
-
- expect(page).to have_button('Due later')
-
- within '.milestones' do
- expect(page.all('ul.content-list > li').first.text).to include('bbb')
- expect(page.all('ul.content-list > li').last.text).to include('aaa')
+ selected_sort_order = sort_by
end
end
end
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index c57e39b6508..0046dfe436f 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -191,7 +191,8 @@ RSpec.describe 'New project', :js do
click_link 'Create blank project'
end
- it 'selects the user namespace' do
+ it 'does not select the user namespace' do
+ click_on 'Pick a group or namespace'
expect(page).to have_button user.username
end
end
@@ -328,6 +329,14 @@ RSpec.describe 'New project', :js do
click_on 'Create project'
+ expect(page).to have_content(
+ s_('ProjectsNew|Pick a group or namespace where you want to create this project.')
+ )
+
+ click_on 'Pick a group or namespace'
+ click_on user.username
+ click_on 'Create project'
+
expect(page).to have_css('#import-project-pane.active')
expect(page).not_to have_css('.toggle-import-form.hide')
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 6b9dfdf3a7b..219c8ec0070 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -15,6 +15,7 @@ RSpec.describe 'Pipeline', :js do
before do
sign_in(user)
project.add_role(user, role)
+ stub_feature_flags(pipeline_tabs_vue: false)
end
shared_context 'pipeline builds' do
@@ -356,6 +357,7 @@ RSpec.describe 'Pipeline', :js do
context 'page tabs' do
before do
+ stub_feature_flags(pipeline_tabs_vue: false)
visit_pipeline
end
@@ -388,6 +390,7 @@ RSpec.describe 'Pipeline', :js do
let(:pipeline) { create(:ci_pipeline, :with_test_reports, :with_report_results, project: project) }
before do
+ stub_feature_flags(pipeline_tabs_vue: false)
visit_pipeline
wait_for_requests
end
@@ -924,6 +927,7 @@ RSpec.describe 'Pipeline', :js do
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
before do
+ stub_feature_flags(pipeline_tabs_vue: false)
visit builds_project_pipeline_path(project, pipeline)
end
@@ -944,6 +948,10 @@ RSpec.describe 'Pipeline', :js do
end
context 'page tabs' do
+ before do
+ stub_feature_flags(pipeline_tabs_vue: false)
+ end
+
it 'shows Pipeline, Jobs and DAG tabs with link' do
expect(page).to have_link('Pipeline')
expect(page).to have_link('Jobs')
@@ -1014,6 +1022,10 @@ RSpec.describe 'Pipeline', :js do
end
describe 'GET /:project/-/pipelines/:id/failures' do
+ before do
+ stub_feature_flags(pipeline_tabs_vue: false)
+ end
+
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: '1234') }
let(:pipeline_failures_page) { failures_project_pipeline_path(project, pipeline) }
let!(:failed_build) { create(:ci_build, :failed, pipeline: pipeline) }
@@ -1139,6 +1151,7 @@ RSpec.describe 'Pipeline', :js do
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
before do
+ stub_feature_flags(pipeline_tabs_vue: false)
visit dag_project_pipeline_path(project, pipeline)
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 0e1728858ec..8b1a22ae05a 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -623,6 +623,7 @@ RSpec.describe 'Pipelines', :js do
create(:generic_commit_status, pipeline: pipeline, stage: 'external', name: 'jenkins', stage_idx: 3, ref: 'master')
+ stub_feature_flags(pipeline_tabs_vue: false)
visit project_pipeline_path(project, pipeline)
wait_for_requests
end
diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb
index 98935fdf872..a7348b62fc0 100644
--- a/spec/features/projects/releases/user_views_releases_spec.rb
+++ b/spec/features/projects/releases/user_views_releases_spec.rb
@@ -24,129 +24,111 @@ RSpec.describe 'User views releases', :js do
stub_default_url_options(host: 'localhost')
end
- shared_examples 'releases index page' do
- context('when the user is a maintainer') do
- before do
- sign_in(maintainer)
+ context('when the user is a maintainer') do
+ before do
+ sign_in(maintainer)
- visit project_releases_path(project)
+ visit project_releases_path(project)
- wait_for_requests
- end
+ wait_for_requests
+ end
- 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
+ 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
- it 'renders the correct links', :aggregate_failures do
- page.within("##{release_v1.tag} .js-assets-list") do
- external_link_indicator_selector = '[data-testid="external-link-indicator"]'
+ it 'renders the correct links', :aggregate_failures do
+ page.within("##{release_v1.tag} .js-assets-list") do
+ external_link_indicator_selector = '[data-testid="external-link-indicator"]'
- expect(page).to have_link internal_link.name, href: internal_link.url
- expect(find_link(internal_link.name)).not_to have_css(external_link_indicator_selector)
+ expect(page).to have_link internal_link.name, href: internal_link.url
+ expect(find_link(internal_link.name)).not_to have_css(external_link_indicator_selector)
- expect(page).to have_link internal_link_with_redirect.name, href: Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{internal_link_with_redirect.filepath}"
- expect(find_link(internal_link_with_redirect.name)).not_to have_css(external_link_indicator_selector)
+ expect(page).to have_link internal_link_with_redirect.name, href: Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{internal_link_with_redirect.filepath}"
+ expect(find_link(internal_link_with_redirect.name)).not_to have_css(external_link_indicator_selector)
- expect(page).to have_link external_link.name, href: external_link.url
- expect(find_link(external_link.name)).to have_css(external_link_indicator_selector)
- end
+ expect(page).to have_link external_link.name, href: external_link.url
+ expect(find_link(external_link.name)).to have_css(external_link_indicator_selector)
end
+ end
- context 'with an upcoming release' do
- it 'sees the upcoming tag' do
- page.within("##{release_v3.tag}") do
- expect(page).to have_content('Upcoming Release')
- end
+ context 'with an upcoming release' do
+ it 'sees the upcoming tag' do
+ 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
- page.within("##{release_v2.tag.parameterize}") do
- expect(page).to have_content(release_v2.name)
- expect(page).to have_content(release_v2.tag)
- end
+ context 'with a tag containing a slash' do
+ it 'sees the release' do
+ 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 'sorting' do
+ def sort_page(by:, direction:)
+ within '[data-testid="releases-sort"]' do
+ find('.dropdown-toggle').click
- context "when the page is sorted by the default sort order" do
- let(:expected_releases) { [release_v3, release_v2, release_v1] }
+ click_button(by, class: 'dropdown-item')
- it_behaves_like 'releases sort order'
+ find('.sorting-direction-button').click if direction == :ascending
end
+ end
- context "when the page is sorted by created_at ascending " do
- let(:expected_releases) { [release_v2, release_v1, release_v3] }
+ shared_examples 'releases sort order' do
+ it "sorts the releases #{description}" do
+ card_titles = page.all('.release-block .card-title', minimum: expected_releases.count)
- before do
- sort_page by: 'Created date', direction: :ascending
+ card_titles.each_with_index do |title, index|
+ expect(title).to have_content(expected_releases[index].name)
end
-
- it_behaves_like 'releases sort order'
end
end
- end
- context('when the user is a guest') do
- before do
- sign_in(guest)
- end
+ context "when the page is sorted by the default sort order" do
+ let(:expected_releases) { [release_v3, release_v2, release_v1] }
- it 'renders release info except for Git-related data' do
- visit project_releases_path(project)
+ it_behaves_like 'releases sort order'
+ end
- within('.release-block', match: :first) do
- expect(page).to have_content(release_v3.description)
- expect(page).to have_content(release_v3.tag)
- expect(page).to have_content(release_v3.name)
+ context "when the page is sorted by created_at ascending " do
+ let(:expected_releases) { [release_v2, release_v1, release_v3] }
- # The following properties (sometimes) include Git info,
- # so they are not rendered for Guest users
- expect(page).not_to have_content(release_v3.commit.short_id)
+ before do
+ sort_page by: 'Created date', direction: :ascending
end
+
+ it_behaves_like 'releases sort order'
end
end
end
- context 'when the releases_index_apollo_client feature flag is enabled' do
+ context('when the user is a guest') do
before do
- stub_feature_flags(releases_index_apollo_client: true)
+ sign_in(guest)
end
- it_behaves_like 'releases index page'
- end
+ it 'renders release info except for Git-related data' do
+ visit project_releases_path(project)
- context 'when the releases_index_apollo_client feature flag is disabled' do
- before do
- stub_feature_flags(releases_index_apollo_client: false)
- end
+ within('.release-block', match: :first) do
+ expect(page).to have_content(release_v3.description)
+ expect(page).to have_content(release_v3.tag)
+ expect(page).to have_content(release_v3.name)
- it_behaves_like 'releases index page'
+ # The following properties (sometimes) include Git info,
+ # so they are not rendered for Guest users
+ expect(page).not_to have_content(release_v3.commit.short_id)
+ end
+ end
end
end
diff --git a/spec/features/projects/terraform_spec.rb b/spec/features/projects/terraform_spec.rb
index 2c63f2bfc02..d9e45b5e78e 100644
--- a/spec/features/projects/terraform_spec.rb
+++ b/spec/features/projects/terraform_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'Terraform', :js do
end
it 'sees an empty state' do
- expect(page).to have_content('Get started with Terraform')
+ expect(page).to have_content("Your project doesn't have any Terraform state files")
end
end
diff --git a/spec/features/projects/user_creates_project_spec.rb b/spec/features/projects/user_creates_project_spec.rb
index 6491a7425f7..b07f2d12660 100644
--- a/spec/features/projects/user_creates_project_spec.rb
+++ b/spec/features/projects/user_creates_project_spec.rb
@@ -33,29 +33,6 @@ RSpec.describe 'User creates a project', :js do
end
it 'creates a new project that is not blank' do
- stub_experiments(new_project_sast_enabled: 'candidate')
-
- visit(new_project_path)
-
- click_link 'Create blank project'
- fill_in(:project_name, with: 'With initial commits')
-
- expect(page).to have_checked_field 'Initialize repository with a README'
- expect(page).to have_checked_field 'Enable Static Application Security Testing (SAST)'
-
- click_button('Create project')
-
- project = Project.last
-
- expect(page).to have_current_path(project_path(project), ignore_query: true)
- expect(page).to have_content('With initial commits')
- expect(page).to have_content('Configure SAST in `.gitlab-ci.yml`, creating this file if it does not already exist')
- expect(page).to have_content('README.md Initial commit')
- end
-
- it 'allows creating a new project when the new_project_sast_enabled is assigned the unchecked candidate' do
- stub_experiments(new_project_sast_enabled: 'unchecked_candidate')
-
visit(new_project_path)
click_link 'Create blank project'
@@ -93,7 +70,7 @@ RSpec.describe 'User creates a project', :js do
fill_in :project_name, with: 'A Subgroup Project'
fill_in :project_path, with: 'a-subgroup-project'
- click_button user.username
+ click_on 'Pick a group or namespace'
click_button subgroup.full_path
click_button('Create project')
@@ -120,9 +97,6 @@ RSpec.describe 'User creates a project', :js do
fill_in :project_name, with: 'a-new-project'
fill_in :project_path, with: 'a-new-project'
- click_button user.username
- click_button group.full_path
-
page.within('#content-body') do
click_button('Create project')
end
diff --git a/spec/features/projects/user_sorts_projects_spec.rb b/spec/features/projects/user_sorts_projects_spec.rb
index 71e43467a39..7c970f7ee3d 100644
--- a/spec/features/projects/user_sorts_projects_spec.rb
+++ b/spec/features/projects/user_sorts_projects_spec.rb
@@ -14,25 +14,29 @@ RSpec.describe 'User sorts projects and order persists' do
it "is set on the dashboard_projects_path" do
visit(dashboard_projects_path)
- expect(find('.dropdown-menu a.is-active', text: project_paths_label)).to have_content(project_paths_label)
+ expect(find('#sort-projects-dropdown')).to have_content(project_paths_label)
end
it "is set on the explore_projects_path" do
visit(explore_projects_path)
- expect(find('.dropdown-menu a.is-active', text: project_paths_label)).to have_content(project_paths_label)
+ expect(find('#sort-projects-dropdown')).to have_content(project_paths_label)
end
it "is set on the group_canonical_path" do
visit(group_canonical_path(group))
- expect(find('.dropdown-menu a.is-active', text: group_paths_label)).to have_content(group_paths_label)
+ within '[data-testid=group_sort_by_dropdown]' do
+ expect(find('.gl-dropdown-toggle')).to have_content(group_paths_label)
+ end
end
it "is set on the details_group_path" do
visit(details_group_path(group))
- expect(find('.dropdown-menu a.is-active', text: group_paths_label)).to have_content(group_paths_label)
+ within '[data-testid=group_sort_by_dropdown]' do
+ expect(find('.gl-dropdown-toggle')).to have_content(group_paths_label)
+ end
end
end
@@ -58,23 +62,27 @@ RSpec.describe 'User sorts projects and order persists' do
it_behaves_like "sort order persists across all views", "Name", "Name"
end
- context 'from group homepage' do
+ context 'from group homepage', :js do
before do
sign_in(user)
visit(group_canonical_path(group))
- find('button.dropdown-menu-toggle').click
- first(:link, 'Last created').click
+ within '[data-testid=group_sort_by_dropdown]' do
+ find('button.gl-dropdown-toggle').click
+ first(:button, 'Last created').click
+ end
end
it_behaves_like "sort order persists across all views", "Created date", "Last created"
end
- context 'from group details' do
+ context 'from group details', :js do
before do
sign_in(user)
visit(details_group_path(group))
- find('button.dropdown-menu-toggle').click
- first(:link, 'Most stars').click
+ within '[data-testid=group_sort_by_dropdown]' do
+ find('button.gl-dropdown-toggle').click
+ first(:button, 'Most stars').click
+ end
end
it_behaves_like "sort order persists across all views", "Stars", "Most stars"
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 1049f8bc18f..db64f84aa76 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -15,6 +15,12 @@ RSpec.describe 'Project' do
end
shared_examples 'creates from template' do |template, sub_template_tab = nil|
+ let(:selected_template) { page.find('.project-fields-form .selected-template') }
+
+ choose_template_selector = '.choose-template'
+ template_option_selector = '.template-option'
+ template_name_selector = '.description strong'
+
it "is created from template", :js do
click_link 'Create from template'
find(".project-template #{sub_template_tab}").click if sub_template_tab
@@ -27,6 +33,39 @@ RSpec.describe 'Project' do
expect(page).to have_content template.name
end
+
+ it 'is created using keyboard navigation', :js do
+ click_link 'Create from template'
+
+ first_template = first(template_option_selector)
+ first_template_name = first_template.find(template_name_selector).text
+ first_template.find(choose_template_selector).click
+
+ expect(selected_template).to have_text(first_template_name)
+
+ click_button "Change template"
+ find("#built-in").click
+
+ # Jumps down 1 template, skipping the `preview` buttons
+ 2.times do
+ page.send_keys :tab
+ end
+
+ # Ensure the template with focus is selected
+ project_name = "project from template"
+ focused_template = page.find(':focus').ancestor(template_option_selector)
+ focused_template_name = focused_template.find(template_name_selector).text
+ focused_template.find(choose_template_selector).send_keys :enter
+ fill_in "project_name", with: project_name
+
+ expect(selected_template).to have_text(focused_template_name)
+
+ page.within '#content-body' do
+ click_button "Create project"
+ end
+
+ expect(page).to have_content project_name
+ end
end
context 'create with project template' do
diff --git a/spec/features/refactor_blob_viewer_disabled/projects/blobs/balsamiq_spec.rb b/spec/features/refactor_blob_viewer_disabled/projects/blobs/balsamiq_spec.rb
deleted file mode 100644
index 3638e98a08a..00000000000
--- a/spec/features/refactor_blob_viewer_disabled/projects/blobs/balsamiq_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Balsamiq file blob', :js do
- let(:project) { create(:project, :public, :repository) }
-
- before do
- stub_feature_flags(refactor_blob_viewer: false)
- visit project_blob_path(project, 'add-balsamiq-file/files/images/balsamiq.bmpr')
-
- wait_for_requests
- end
-
- it 'displays Balsamiq file content' do
- expect(page).to have_content("Mobile examples")
- end
-end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 49c468976b9..2dddcd62a6c 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -352,6 +352,7 @@ RSpec.describe 'Runners' do
before do
group.add_owner(user)
+ stub_feature_flags(runner_list_group_view_vue_ui: false)
end
context 'group with no runners' do
diff --git a/spec/features/search/user_searches_for_projects_spec.rb b/spec/features/search/user_searches_for_projects_spec.rb
index c38ad077cd0..562da56275c 100644
--- a/spec/features/search/user_searches_for_projects_spec.rb
+++ b/spec/features/search/user_searches_for_projects_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'User searches for projects', :js do
context 'when signed out' do
context 'when block_anonymous_global_searches is disabled' do
before do
+ allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit).and_return(1000)
+ allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit_unauthenticated).and_return(1000)
stub_feature_flags(block_anonymous_global_searches: false)
end
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 8736f16b991..7350a54e8df 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -17,12 +17,15 @@ RSpec.describe 'User uses header search field', :js do
end
before do
+ allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit).and_return(1000)
+ allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit_unauthenticated).and_return(1000)
sign_in(user)
end
shared_examples 'search field examples' do
before do
visit(url)
+ wait_for_all_requests
end
it 'starts searching by pressing the enter key' do
@@ -37,7 +40,6 @@ RSpec.describe 'User uses header search field', :js do
before do
find('#search')
find('body').native.send_keys('s')
-
wait_for_all_requests
end
@@ -49,6 +51,7 @@ RSpec.describe 'User uses header search field', :js do
context 'when clicking the search field' do
before do
page.find('#search').click
+ wait_for_all_requests
end
it 'shows category search dropdown', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/250285' do
@@ -59,7 +62,7 @@ RSpec.describe 'User uses header search field', :js do
let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
it 'shows assigned issues' do
- find('.search-input-container .dropdown-menu').click_link('Issues assigned to me')
+ find('[data-testid="header-search-dropdown-menu"]').click_link('Issues assigned to me')
expect(page).to have_selector('.issues-list .issue')
expect_tokens([assignee_token(user.name)])
@@ -67,7 +70,7 @@ RSpec.describe 'User uses header search field', :js do
end
it 'shows created issues' do
- find('.search-input-container .dropdown-menu').click_link("Issues I've created")
+ find('[data-testid="header-search-dropdown-menu"]').click_link("Issues I've created")
expect(page).to have_selector('.issues-list .issue')
expect_tokens([author_token(user.name)])
@@ -79,7 +82,7 @@ RSpec.describe 'User uses header search field', :js do
let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignees: [user]) }
it 'shows assigned merge requests' do
- find('.search-input-container .dropdown-menu').click_link('Merge requests assigned to me')
+ find('[data-testid="header-search-dropdown-menu"]').click_link('Merge requests assigned to me')
expect(page).to have_selector('.mr-list .merge-request')
expect_tokens([assignee_token(user.name)])
@@ -87,7 +90,7 @@ RSpec.describe 'User uses header search field', :js do
end
it 'shows created merge requests' do
- find('.search-input-container .dropdown-menu').click_link("Merge requests I've created")
+ find('[data-testid="header-search-dropdown-menu"]').click_link("Merge requests I've created")
expect(page).to have_selector('.mr-list .merge-request')
expect_tokens([author_token(user.name)])
@@ -150,10 +153,9 @@ RSpec.describe 'User uses header search field', :js do
it 'displays search options' do
fill_in_search('test')
-
- expect(page).to have_selector(scoped_search_link('test'))
- expect(page).to have_selector(scoped_search_link('test', group_id: group.id))
- expect(page).to have_selector(scoped_search_link('test', project_id: project.id, group_id: group.id))
+ expect(page).to have_selector(scoped_search_link('test', search_code: true))
+ expect(page).to have_selector(scoped_search_link('test', group_id: group.id, search_code: true))
+ expect(page).to have_selector(scoped_search_link('test', project_id: project.id, group_id: group.id, search_code: true))
end
end
@@ -165,10 +167,9 @@ RSpec.describe 'User uses header search field', :js do
it 'displays search options' do
fill_in_search('test')
-
- expect(page).to have_selector(scoped_search_link('test'))
- 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))
+ expect(page).to have_selector(scoped_search_link('test', search_code: true, repository_ref: 'master'))
+ expect(page).not_to have_selector(scoped_search_link('test', search_code: true, group_id: project.namespace_id, repository_ref: 'master'))
+ expect(page).to have_selector(scoped_search_link('test', search_code: true, project_id: project.id, repository_ref: 'master'))
end
it 'displays a link to project merge requests' do
@@ -217,7 +218,6 @@ RSpec.describe 'User uses header search field', :js do
it 'displays search options' do
fill_in_search('test')
-
expect(page).to have_selector(scoped_search_link('test'))
expect(page).to have_selector(scoped_search_link('test', group_id: group.id))
expect(page).not_to have_selector(scoped_search_link('test', project_id: project.id))
@@ -248,18 +248,20 @@ RSpec.describe 'User uses header search field', :js do
end
end
- def scoped_search_link(term, project_id: nil, group_id: nil)
+ def scoped_search_link(term, project_id: nil, group_id: nil, search_code: nil, repository_ref: nil)
# search_path will accept group_id and project_id but the order does not match
# what is expected in the href, so the variable must be built manually
href = search_path(search: term)
+ href.concat("&nav_source=navbar")
href.concat("&project_id=#{project_id}") if project_id
href.concat("&group_id=#{group_id}") if group_id
- href.concat("&nav_source=navbar")
+ href.concat("&search_code=true") if search_code
+ href.concat("&repository_ref=#{repository_ref}") if repository_ref
- ".dropdown a[href='#{href}']"
+ "[data-testid='header-search-dropdown-menu'] a[href='#{href}']"
end
def dashboard_search_options_popup_menu
- "div[data-testid='dashboard-search-options']"
+ "[data-testid='header-search-dropdown-menu'] .header-search-dropdown-content"
end
end
diff --git a/spec/features/static_site_editor_spec.rb b/spec/features/static_site_editor_spec.rb
deleted file mode 100644
index 98313905a33..00000000000
--- a/spec/features/static_site_editor_spec.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Static Site Editor' do
- include ContentSecurityPolicyHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project, :public, :repository) }
-
- let(:sse_path) { project_show_sse_path(project, 'master/README.md') }
-
- before_all do
- project.add_developer(user)
- end
-
- before do
- sign_in(user)
- end
-
- context "when no config file is present" do
- before do
- visit sse_path
- end
-
- it 'renders SSE page with all generated config values and default config file values' do
- node = page.find('#static-site-editor')
-
- # assert generated config values are present
- expect(node['data-base-url']).to eq("/#{project.full_path}/-/sse/master%2FREADME.md")
- expect(node['data-branch']).to eq('master')
- expect(node['data-commit-id']).to match(/\A[0-9a-f]{40}\z/)
- expect(node['data-is-supported-content']).to eq('true')
- expect(node['data-merge-requests-illustration-path'])
- .to match(%r{/assets/illustrations/merge_requests-.*\.svg})
- expect(node['data-namespace']).to eq(project.namespace.full_path)
- expect(node['data-project']).to eq(project.path)
- expect(node['data-project-id']).to eq(project.id.to_s)
-
- # assert default config file values are present
- expect(node['data-image-upload-path']).to eq('source/images')
- expect(node['data-mounts']).to eq('[{"source":"source","target":""}]')
- expect(node['data-static-site-generator']).to eq('middleman')
- end
- end
-
- context "when a config file is present" do
- let(:config_file_yml) do
- <<~YAML
- image_upload_path: custom-image-upload-path
- mounts:
- - source: source1
- target: ""
- - source: source2
- target: target2
- static_site_generator: middleman
- YAML
- end
-
- before do
- allow_next_instance_of(Repository) do |repository|
- allow(repository).to receive(:blob_data_at).and_return(config_file_yml)
- end
-
- visit sse_path
- end
-
- it 'renders Static Site Editor page values read from config file' do
- node = page.find('#static-site-editor')
-
- # assert user-specified config file values are present
- expected_mounts = '[{"source":"source1","target":""},{"source":"source2","target":"target2"}]'
- expect(node['data-image-upload-path']).to eq('custom-image-upload-path')
- expect(node['data-mounts']).to eq(expected_mounts)
- 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
- setup_csp_for_controller(Projects::StaticSiteEditorController)
- 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
-
- setup_existing_csp_for_controller(Projects::StaticSiteEditorController, csp)
- 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/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index 0f8daaf8e15..6907701de9c 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'Task Lists', :js do
MARKDOWN
end
- let(:singleIncompleteMarkdown) do
+ let(:single_incomplete_markdown) do
<<-MARKDOWN.strip_heredoc
This is a task list:
@@ -30,7 +30,7 @@ RSpec.describe 'Task Lists', :js do
MARKDOWN
end
- let(:singleCompleteMarkdown) do
+ let(:single_complete_markdown) do
<<-MARKDOWN.strip_heredoc
This is a task list:
@@ -94,7 +94,7 @@ RSpec.describe 'Task Lists', :js do
end
describe 'single incomplete task' do
- let!(:issue) { create(:issue, description: singleIncompleteMarkdown, author: user, project: project) }
+ let!(:issue) { create(:issue, description: single_incomplete_markdown, author: user, project: project) }
it 'renders' do
visit_issue(project, issue)
@@ -113,7 +113,7 @@ RSpec.describe 'Task Lists', :js do
end
describe 'single complete task' do
- let!(:issue) { create(:issue, description: singleCompleteMarkdown, author: user, project: project) }
+ let!(:issue) { create(:issue, description: single_complete_markdown, author: user, project: project) }
it 'renders' do
visit_issue(project, issue)
@@ -171,7 +171,7 @@ RSpec.describe 'Task Lists', :js do
describe 'single incomplete task' do
let!(:note) do
- create(:note, note: singleIncompleteMarkdown, noteable: issue,
+ create(:note, note: single_incomplete_markdown, noteable: issue,
project: project, author: user)
end
@@ -186,7 +186,7 @@ RSpec.describe 'Task Lists', :js do
describe 'single complete task' do
let!(:note) do
- create(:note, note: singleCompleteMarkdown, noteable: issue,
+ create(:note, note: single_complete_markdown, noteable: issue,
project: project, author: user)
end
@@ -264,7 +264,7 @@ RSpec.describe 'Task Lists', :js do
end
describe 'single incomplete task' do
- let!(:merge) { create(:merge_request, :simple, description: singleIncompleteMarkdown, author: user, source_project: project) }
+ let!(:merge) { create(:merge_request, :simple, description: single_incomplete_markdown, author: user, source_project: project) }
it 'renders for description' do
visit_merge_request(project, merge)
@@ -283,7 +283,7 @@ RSpec.describe 'Task Lists', :js do
end
describe 'single complete task' do
- let!(:merge) { create(:merge_request, :simple, description: singleCompleteMarkdown, author: user, source_project: project) }
+ let!(:merge) { create(:merge_request, :simple, description: single_complete_markdown, author: user, source_project: project) }
it 'renders for description' do
visit_merge_request(project, merge)
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 8610cae58a4..822bf898034 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -818,7 +818,6 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions do
context 'when 2FA is required for the user' do
before do
- stub_feature_flags(mr_attention_requests: false)
group = create(:group, require_two_factor_authentication: true)
group.add_developer(user)
end
@@ -840,7 +839,15 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions do
expect(page).to have_current_path(profile_two_factor_auth_path, ignore_query: true)
- fill_in 'pin_code', with: user.reload.current_otp
+ # Use the secret shown on the page to generate the OTP that will be entered.
+ # This detects issues wherein a new secret gets generated after the
+ # page is shown.
+ wait_for_requests
+
+ otp_secret = page.find('.two-factor-secret').text.gsub('Key:', '').delete(' ')
+ current_otp = ROTP::TOTP.new(otp_secret).now
+
+ fill_in 'pin_code', with: current_otp
fill_in 'current_password', with: user.password
click_button 'Register with two-factor app'