diff options
Diffstat (limited to 'spec/features')
175 files changed, 2818 insertions, 1575 deletions
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb index 5959fcd6306..5fdd0816006 100644 --- a/spec/features/abuse_report_spec.rb +++ b/spec/features/abuse_report_spec.rb @@ -9,7 +9,7 @@ RSpec.describe 'Abuse reports' do sign_in(create(:user)) end - it 'Report abuse' do + it 'report abuse' do visit user_path(another_user) click_link 'Report abuse' diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb index 845e186dd5b..192182adddc 100644 --- a/spec/features/admin/admin_abuse_reports_spec.rb +++ b/spec/features/admin/admin_abuse_reports_spec.rb @@ -7,7 +7,9 @@ RSpec.describe "Admin::AbuseReports", :js do context 'as an admin' do before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe 'if a user has been reported for abuse' do diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 48aaec6e6df..cd136af8d69 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -4,9 +4,11 @@ require 'spec_helper' RSpec.describe 'Admin Appearance' do let!(:appearance) { create(:appearance) } + let(:admin) { create(:admin) } - it 'Create new appearance' do - sign_in(create(:admin)) + it 'create new appearance' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit admin_appearances_path fill_in 'appearance_title', with: 'MyCompany' @@ -25,8 +27,9 @@ RSpec.describe 'Admin Appearance' do expect(page).to have_content 'Last edit' end - it 'Preview sign-in page appearance' do - sign_in(create(:admin)) + it 'preview sign-in page appearance' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit admin_appearances_path click_link "Sign-in page" @@ -34,8 +37,9 @@ RSpec.describe 'Admin Appearance' do expect_custom_sign_in_appearance(appearance) end - it 'Preview new project page appearance' do - sign_in(create(:admin)) + it 'preview new project page appearance' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit admin_appearances_path click_link "New project page" @@ -45,7 +49,8 @@ RSpec.describe 'Admin Appearance' do context 'Custom system header and footer' do before do - sign_in(create(:admin)) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end context 'when system header and footer messages are empty' do @@ -75,14 +80,15 @@ RSpec.describe 'Admin Appearance' do end end - it 'Custom sign-in page' do + it 'custom sign-in page' do visit new_user_session_path expect_custom_sign_in_appearance(appearance) end - it 'Custom new project page' do - sign_in create(:user) + it 'custom new project page' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit new_project_path expect_custom_new_project_appearance(appearance) @@ -91,6 +97,7 @@ RSpec.describe 'Admin Appearance' do context 'Profile page with custom profile image guidelines' do before do sign_in(create(:admin)) + gitlab_enable_admin_mode_sign_in(admin) visit admin_appearances_path fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!' click_button 'Update appearance settings' @@ -104,8 +111,9 @@ RSpec.describe 'Admin Appearance' do end end - it 'Appearance logo' do - sign_in(create(:admin)) + it 'appearance logo' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit admin_appearances_path attach_file(:appearance_logo, logo_fixture) @@ -116,8 +124,9 @@ RSpec.describe 'Admin Appearance' do expect(page).not_to have_css(logo_selector) end - it 'Header logos' do - sign_in(create(:admin)) + it 'header logos' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit admin_appearances_path attach_file(:appearance_header_logo, logo_fixture) @@ -129,7 +138,8 @@ RSpec.describe 'Admin Appearance' do end it 'Favicon' do - sign_in(create(:admin)) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit admin_appearances_path attach_file(:appearance_favicon, logo_fixture) diff --git a/spec/features/admin/admin_broadcast_messages_spec.rb b/spec/features/admin/admin_broadcast_messages_spec.rb index 091ed0a3396..476dd4469bc 100644 --- a/spec/features/admin/admin_broadcast_messages_spec.rb +++ b/spec/features/admin/admin_broadcast_messages_spec.rb @@ -4,12 +4,14 @@ require 'spec_helper' RSpec.describe 'Admin Broadcast Messages' do before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) create(:broadcast_message, :expired, message: 'Migration to new server') visit admin_broadcast_messages_path end - it 'See broadcast messages list' do + it 'see broadcast messages list' do expect(page).to have_content 'Migration to new server' end @@ -42,7 +44,7 @@ RSpec.describe 'Admin Broadcast Messages' do expect(page).to have_selector 'strong', text: '4:00 CST to 5:00 CST' end - it 'Edit an existing broadcast message' do + it 'edit an existing broadcast message' do click_link 'Edit' fill_in 'broadcast_message_message', with: 'Application update RIGHT NOW' click_button 'Update broadcast message' @@ -51,7 +53,7 @@ RSpec.describe 'Admin Broadcast Messages' do expect(page).to have_content 'Application update RIGHT NOW' end - it 'Remove an existing broadcast message' do + it 'remove an existing broadcast message' do click_link 'Remove' expect(current_path).to eq admin_broadcast_messages_path diff --git a/spec/features/admin/admin_browse_spam_logs_spec.rb b/spec/features/admin/admin_browse_spam_logs_spec.rb index 65847876c11..471a7e8f0ab 100644 --- a/spec/features/admin/admin_browse_spam_logs_spec.rb +++ b/spec/features/admin/admin_browse_spam_logs_spec.rb @@ -6,10 +6,12 @@ RSpec.describe 'Admin browse spam logs' do let!(:spam_log) { create(:spam_log, description: 'abcde ' * 20) } before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end - it 'Browse spam logs' do + it 'browse spam logs' do visit admin_spam_logs_path expect(page).to have_content('Spam Logs') diff --git a/spec/features/admin/admin_builds_spec.rb b/spec/features/admin/admin_builds_spec.rb index 166fde0f37a..42827dd5b49 100644 --- a/spec/features/admin/admin_builds_spec.rb +++ b/spec/features/admin/admin_builds_spec.rb @@ -4,7 +4,9 @@ require 'spec_helper' RSpec.describe 'Admin Builds' do before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe 'GET /admin/builds' do diff --git a/spec/features/admin/admin_cohorts_spec.rb b/spec/features/admin/admin_cohorts_spec.rb index f91446ed222..982a9333275 100644 --- a/spec/features/admin/admin_cohorts_spec.rb +++ b/spec/features/admin/admin_cohorts_spec.rb @@ -4,7 +4,9 @@ require 'spec_helper' RSpec.describe 'Cohorts page' do before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end context 'with usage ping enabled' do diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb index 2039a6ff1ee..c326d0fd741 100644 --- a/spec/features/admin/admin_deploy_keys_spec.rb +++ b/spec/features/admin/admin_deploy_keys_spec.rb @@ -7,7 +7,9 @@ RSpec.describe 'admin deploy keys' do let!(:another_deploy_key) { create(:another_deploy_key, public: true) } before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end it 'show all public deploy keys' do diff --git a/spec/features/admin/admin_dev_ops_report_spec.rb b/spec/features/admin/admin_dev_ops_report_spec.rb index 3b2c9d75870..a05fa0640d8 100644 --- a/spec/features/admin/admin_dev_ops_report_spec.rb +++ b/spec/features/admin/admin_dev_ops_report_spec.rb @@ -4,7 +4,9 @@ require 'spec_helper' RSpec.describe 'DevOps Report page', :js do before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end context 'with devops_adoption feature flag disabled' do diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb index d7feb21a8b3..f7f0592a315 100644 --- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb +++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb @@ -12,6 +12,7 @@ RSpec.describe 'Admin disables Git access protocol', :js do before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end context 'with HTTP disabled' do diff --git a/spec/features/admin/admin_disables_two_factor_spec.rb b/spec/features/admin/admin_disables_two_factor_spec.rb index 216c8ae36c7..1f34c4ed17c 100644 --- a/spec/features/admin/admin_disables_two_factor_spec.rb +++ b/spec/features/admin/admin_disables_two_factor_spec.rb @@ -4,7 +4,9 @@ require 'spec_helper' RSpec.describe 'Admin disables 2FA for a user' do it 'successfully', :js do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) user = create(:user, :two_factor) edit_user(user) @@ -19,7 +21,9 @@ RSpec.describe 'Admin disables 2FA for a user' do end it 'for a user without 2FA enabled' do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) user = create(:user) edit_user(user) diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index 96709cf8a12..0e350a5e12e 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -7,12 +7,14 @@ RSpec.describe 'Admin Groups' do include Spec::Support::Helpers::Features::MembersHelpers let(:internal) { Gitlab::VisibilityLevel::INTERNAL } - let(:user) { create :user } - let!(:group) { create :group } - let!(:current_user) { create(:admin) } + + let_it_be(:user) { create :user } + let_it_be(:group) { create :group } + let_it_be(:current_user) { create(:admin) } before do sign_in(current_user) + gitlab_enable_admin_mode_sign_in(current_user) stub_application_setting(default_group_visibility: internal) end @@ -25,6 +27,17 @@ RSpec.describe 'Admin Groups' do end describe 'create a group' do + describe 'with expected fields' do + it 'renders from as expected', :aggregate_failures do + visit new_admin_group_path + + expect(page).to have_field('name') + expect(page).to have_field('group_path') + expect(page).to have_field('group_visibility_level_0') + expect(page).to have_field('description') + end + end + it 'creates new group' do visit admin_groups_path diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb index dfc7f5f6f84..0f6cba6c105 100644 --- a/spec/features/admin/admin_health_check_spec.rb +++ b/spec/features/admin/admin_health_check_spec.rb @@ -9,6 +9,7 @@ RSpec.describe "Admin Health Check", :feature do before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe '#show' do diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index f4a70621cee..3f63bf9a15c 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -8,7 +8,9 @@ RSpec.describe 'Admin::HookLogs' do let(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') } before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end it 'show list of hook logs' do diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 1c14d65a1cd..3fed402267c 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Admin::Hooks' do before do sign_in(user) + gitlab_enable_admin_mode_sign_in(user) end describe 'GET /admin/hooks' do diff --git a/spec/features/admin/admin_labels_spec.rb b/spec/features/admin/admin_labels_spec.rb index 35638e0829b..815a73b1450 100644 --- a/spec/features/admin/admin_labels_spec.rb +++ b/spec/features/admin/admin_labels_spec.rb @@ -7,7 +7,9 @@ RSpec.describe 'admin issues labels' do let!(:feature_label) { Label.create(title: 'feature', template: true) } before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe 'list' do diff --git a/spec/features/admin/admin_manage_applications_spec.rb b/spec/features/admin/admin_manage_applications_spec.rb index 7a9a6f2ccb8..e54837ede11 100644 --- a/spec/features/admin/admin_manage_applications_spec.rb +++ b/spec/features/admin/admin_manage_applications_spec.rb @@ -4,7 +4,9 @@ require 'spec_helper' RSpec.describe 'admin manage applications' do before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end it 'creates new oauth application' do diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb index 7cbba9ec674..f1dee075925 100644 --- a/spec/features/admin/admin_mode/login_spec.rb +++ b/spec/features/admin/admin_mode/login_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do +RSpec.describe 'Admin Mode Login' do include TermsHelper include UserLoginHelper include LdapHelpers diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb index b4d49fe760f..b7fa59bbfb7 100644 --- a/spec/features/admin/admin_mode/logout_spec.rb +++ b/spec/features/admin/admin_mode/logout_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin Mode Logout', :js, :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do +RSpec.describe 'Admin Mode Logout', :js do include TermsHelper include UserLoginHelper diff --git a/spec/features/admin/admin_mode/workers_spec.rb b/spec/features/admin/admin_mode/workers_spec.rb index d037f5555dc..fbbcf19063b 100644 --- a/spec/features/admin/admin_mode/workers_spec.rb +++ b/spec/features/admin/admin_mode/workers_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' # Test an operation that triggers background jobs requiring administrative rights -RSpec.describe 'Admin mode for workers', :do_not_mock_admin_mode, :request_store, :clean_gitlab_redis_shared_state do +RSpec.describe 'Admin mode for workers', :request_store do let(:user) { create(:user) } let(:user_to_delete) { create(:user) } diff --git a/spec/features/admin/admin_mode_spec.rb b/spec/features/admin/admin_mode_spec.rb index 3b4edbc1a07..8169b3a20db 100644 --- a/spec/features/admin/admin_mode_spec.rb +++ b/spec/features/admin/admin_mode_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin mode', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do +RSpec.describe 'Admin mode' do include MobileHelpers include StubENV diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index 522da760062..ff4e592234b 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -11,6 +11,7 @@ RSpec.describe "Admin::Projects" do before do sign_in(current_user) + gitlab_enable_admin_mode_sign_in(current_user) end describe "GET /admin/projects" do diff --git a/spec/features/admin/admin_requests_profiles_spec.rb b/spec/features/admin/admin_requests_profiles_spec.rb index c649fdd8e19..e92528d431d 100644 --- a/spec/features/admin/admin_requests_profiles_spec.rb +++ b/spec/features/admin/admin_requests_profiles_spec.rb @@ -7,7 +7,9 @@ RSpec.describe 'Admin::RequestsProfilesController' do before do stub_const('Gitlab::RequestProfiler::PROFILES_DIR', tmpdir) - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end after do diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 0e20ccf6bec..e16cde3fa1c 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -9,7 +9,9 @@ RSpec.describe "Admin Runners" do before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe "Runners page" do @@ -282,6 +284,12 @@ RSpec.describe "Admin Runners" do visit admin_runner_path(runner) end + describe 'runner page breadcrumbs' do + it 'contains the current runner’s short sha' do + expect(page.find('h2')).to have_content(runner.short_sha) + end + end + describe 'projects' do it 'contains project names' do expect(page).to have_content(@project1.full_name) diff --git a/spec/features/admin/admin_sees_project_statistics_spec.rb b/spec/features/admin/admin_sees_project_statistics_spec.rb index d94889b825a..be781730924 100644 --- a/spec/features/admin/admin_sees_project_statistics_spec.rb +++ b/spec/features/admin/admin_sees_project_statistics_spec.rb @@ -7,6 +7,7 @@ RSpec.describe "Admin > Admin sees project statistics" do before do sign_in(current_user) + gitlab_enable_admin_mode_sign_in(current_user) visit admin_project_path(project) end @@ -15,7 +16,7 @@ RSpec.describe "Admin > Admin sees project statistics" do let(:project) { create(:project, :repository) } it "shows project statistics" do - expect(page).to have_content("Storage: 0 Bytes (Repository: 0 Bytes / Wikis: 0 Bytes / Build Artifacts: 0 Bytes / LFS: 0 Bytes / Snippets: 0 Bytes)") + expect(page).to have_content("Storage: 0 Bytes (Repository: 0 Bytes / Wikis: 0 Bytes / Build Artifacts: 0 Bytes / LFS: 0 Bytes / Snippets: 0 Bytes / Packages: 0 Bytes / Uploads: 0 Bytes)") end end diff --git a/spec/features/admin/admin_sees_projects_statistics_spec.rb b/spec/features/admin/admin_sees_projects_statistics_spec.rb index 786fa98255c..2e96814d1e9 100644 --- a/spec/features/admin/admin_sees_projects_statistics_spec.rb +++ b/spec/features/admin/admin_sees_projects_statistics_spec.rb @@ -10,6 +10,7 @@ RSpec.describe "Admin > Admin sees projects statistics" do create(:project, :repository) { |project| project.statistics.destroy } sign_in(current_user) + gitlab_enable_admin_mode_sign_in(current_user) visit admin_projects_path end diff --git a/spec/features/admin/admin_serverless_domains_spec.rb b/spec/features/admin/admin_serverless_domains_spec.rb index 256887f425f..0312e82e1ba 100644 --- a/spec/features/admin/admin_serverless_domains_spec.rb +++ b/spec/features/admin/admin_serverless_domains_spec.rb @@ -7,10 +7,12 @@ RSpec.describe 'Admin Serverless Domains', :js do before do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end - it 'Add domain with certificate' do + it 'add domain with certificate' do visit admin_serverless_domains_path fill_in 'pages_domain[domain]', with: 'foo.com' @@ -30,7 +32,7 @@ RSpec.describe 'Admin Serverless Domains', :js do expect(page).to have_content '/CN=test-certificate' end - it 'Update domain certificate' do + it 'update domain certificate' do visit admin_serverless_domains_path fill_in 'pages_domain[domain]', with: 'foo.com' @@ -60,7 +62,7 @@ RSpec.describe 'Admin Serverless Domains', :js do context 'when domain exists' do let!(:domain) { create(:pages_domain, :instance_serverless) } - it 'Displays a modal when attempting to delete a domain' do + it 'displays a modal when attempting to delete a domain' do visit admin_serverless_domains_path click_button 'Delete domain' @@ -71,7 +73,7 @@ RSpec.describe 'Admin Serverless Domains', :js do end end - it 'Displays a modal with disabled button if unable to delete a domain' do + it 'displays a modal with disabled button if unable to delete a domain' do create(:serverless_domain_cluster, pages_domain: domain) visit admin_serverless_domains_path diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 8929abc7edc..06d31b544ea 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do +RSpec.describe 'Admin updates settings' do include StubENV include TermsHelper include UsageDataHelpers @@ -24,7 +24,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n visit general_admin_application_settings_path end - it 'Change visibility settings' do + it 'change visibility settings' do page.within('.as-visibility-access') do choose "application_setting_default_project_visibility_20" click_button 'Save changes' @@ -33,7 +33,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Uncheck all restricted visibility levels' 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) @@ -47,7 +47,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(find('#application_setting_visibility_level_20')).not_to be_checked end - it 'Modify import sources' do + it 'modify import sources' do expect(current_settings.import_sources).not_to be_empty page.within('.as-visibility-access') do @@ -70,7 +70,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(current_settings.import_sources).to eq(['git']) end - it 'Change Visibility and Access Controls' do + it 'change Visibility and Access Controls' do page.within('.as-visibility-access') do uncheck 'Project export enabled' click_button 'Save changes' @@ -80,7 +80,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Change Keys settings' do + it 'change Keys settings' do page.within('.as-visibility-access') do select 'Are forbidden', from: 'RSA SSH keys' select 'Are allowed', from: 'DSA SSH keys' @@ -98,7 +98,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(find_field('ED25519 SSH keys').value).to eq(forbidden) end - it 'Change Account and Limit Settings' do + it 'change Account and Limit Settings' do page.within('.as-account-limit') do uncheck 'Gravatar enabled' click_button 'Save changes' @@ -108,7 +108,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Change Maximum import size' do + it 'change Maximum import size' do page.within('.as-account-limit') do fill_in 'Maximum import size (MB)', with: 15 click_button 'Save changes' @@ -118,7 +118,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Change New users set to external', :js do + it 'change New users set to external', :js do user_internal_regex = find('#application_setting_user_default_internal_regex', visible: :all) expect(user_internal_regex).to be_readonly @@ -144,7 +144,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n end end - it 'Change Sign-in restrictions' do + it 'change Sign-in restrictions' do page.within('.as-signin') do fill_in 'Home page URL', with: 'https://about.gitlab.com/' click_button 'Save changes' @@ -154,7 +154,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Terms of Service' do + it 'terms of Service' do # Already have the admin accept terms, so they don't need to accept in this spec. _existing_terms = create(:term) accept_terms(admin) @@ -170,7 +170,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content 'Application settings saved successfully' end - it 'Modify oauth providers' do + it 'modify oauth providers' do expect(current_settings.disabled_oauth_sign_in_sources).to be_empty page.within('.as-signin') do @@ -190,7 +190,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(current_settings.disabled_oauth_sign_in_sources).not_to include('google_oauth2') end - it 'Oauth providers do not raise validation errors when saving unrelated changes' do + it 'oauth providers do not raise validation errors when saving unrelated changes' do expect(current_settings.disabled_oauth_sign_in_sources).to be_empty page.within('.as-signin') do @@ -213,7 +213,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(current_settings.disabled_oauth_sign_in_sources).to include('google_oauth2') end - it 'Configure web terminal' do + it 'configure web terminal' do page.within('.as-terminal') do fill_in 'Max session time', with: 15 click_button 'Save changes' @@ -255,7 +255,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n visit general_admin_application_settings_path end - it 'Enable hiding third party offers' do + it 'enable hiding third party offers' do page.within('.as-third-party-offers') do check 'Do not display offers from third parties within GitLab' click_button 'Save changes' @@ -265,7 +265,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(current_settings.hide_third_party_offers).to be true end - it 'Change Slack Notifications Service template settings', :js do + it 'change Slack Notifications Service template settings', :js do first(:link, 'Service Templates').click click_link 'Slack notifications' fill_in 'Webhook', with: 'http://localhost' @@ -315,7 +315,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n end context 'CI/CD page' do - it 'Change CI/CD settings' do + it 'change CI/CD settings' do visit ci_cd_admin_application_settings_path page.within('.as-ci-cd') do @@ -380,7 +380,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n end context 'Repository page' do - it 'Change Repository storage settings' do + it 'change Repository storage settings' do visit repository_admin_application_settings_path page.within('.as-repository-storage') do @@ -393,7 +393,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n end context 'Reporting page' do - it 'Change Spam settings' do + it 'change Spam settings' do visit reporting_admin_application_settings_path page.within('.as-spam') do @@ -421,7 +421,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n visit metrics_and_profiling_admin_application_settings_path end - it 'Change Prometheus settings' do + it 'change Prometheus settings' do page.within('.as-prometheus') do check 'Enable Prometheus Metrics' click_button 'Save changes' @@ -431,7 +431,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Change Performance bar settings' do + it 'change Performance bar settings' do group = create(:group) page.within('.as-performance-bar') do @@ -474,7 +474,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n end context 'Network page' do - it 'Changes Outbound requests settings' do + it 'changes Outbound requests settings' do visit network_admin_application_settings_path page.within('.as-outbound') do @@ -492,7 +492,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(current_settings.dns_rebinding_protection_enabled).to be false end - it 'Changes Issues rate limits settings' do + it 'changes Issues rate limits settings' do visit network_admin_application_settings_path page.within('.as-issue-limits') do @@ -510,7 +510,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n visit preferences_admin_application_settings_path end - it 'Change Help page' do + it 'change Help page' do stub_feature_flags(help_page_documentation_redirect: true) new_support_url = 'http://example.com/help' @@ -531,7 +531,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Change Pages settings' do + it 'change Pages settings' do page.within('.as-pages') do fill_in 'Maximum size of pages (MB)', with: 15 check 'Require users to prove ownership of custom domains' @@ -543,7 +543,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n expect(page).to have_content "Application settings saved successfully" end - it 'Change Real-time features settings' do + it 'change Real-time features settings' do page.within('.as-realtime') do fill_in 'Polling interval multiplier', with: 5.0 click_button 'Save changes' @@ -564,7 +564,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n .to have_content "The form contains the following error: Polling interval multiplier must be greater than or equal to 0" end - it "Change Pages Let's Encrypt settings" do + it "change Pages Let's Encrypt settings" do visit preferences_admin_application_settings_path page.within('.as-pages') do fill_in 'Email', with: 'my@test.example.com' @@ -578,7 +578,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n end context 'Nav bar' do - it 'Shows default help links in nav' do + it 'shows default help links in nav' do default_support_url = 'https://about.gitlab.com/getting-help/' visit root_dashboard_path @@ -591,7 +591,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n end end - it 'Shows custom support url in nav when set' do + it 'shows custom support url in nav when set' do new_support_url = 'http://example.com/help' stub_application_setting(help_page_support_url: new_support_url) diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb index 6a0448fd890..2225f25aa1e 100644 --- a/spec/features/admin/admin_system_info_spec.rb +++ b/spec/features/admin/admin_system_info_spec.rb @@ -4,7 +4,9 @@ require 'spec_helper' RSpec.describe 'Admin System Info' do before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe 'GET /admin/system_info' do diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index ec3dd322f97..cae190e76b0 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -20,6 +20,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do before do sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe "token creation" do diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb index 0fb5124f673..0e448446085 100644 --- a/spec/features/admin/admin_uses_repository_checks_spec.rb +++ b/spec/features/admin/admin_uses_repository_checks_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin uses repository checks', :request_store, :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do +RSpec.describe 'Admin uses repository checks', :request_store do include StubENV let(:admin) { create(:admin) } diff --git a/spec/features/admin/clusters/applications_spec.rb b/spec/features/admin/clusters/applications_spec.rb index 3bcadfdbfc1..e083e4fee4c 100644 --- a/spec/features/admin/clusters/applications_spec.rb +++ b/spec/features/admin/clusters/applications_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'Instance-level Cluster Applications', :js do before do sign_in(user) + gitlab_enable_admin_mode_sign_in(user) end describe 'Installing applications' do diff --git a/spec/features/admin/clusters/eks_spec.rb b/spec/features/admin/clusters/eks_spec.rb index ad7122bf182..a1bac720349 100644 --- a/spec/features/admin/clusters/eks_spec.rb +++ b/spec/features/admin/clusters/eks_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Instance-level AWS EKS Cluster', :js do before do sign_in(user) + gitlab_enable_admin_mode_sign_in(user) end context 'when user does not have a cluster and visits group clusters page' do diff --git a/spec/features/admin/dashboard_spec.rb b/spec/features/admin/dashboard_spec.rb index acb8fb54e11..c040811ada1 100644 --- a/spec/features/admin/dashboard_spec.rb +++ b/spec/features/admin/dashboard_spec.rb @@ -6,7 +6,9 @@ RSpec.describe 'admin visits dashboard' do include ProjectForksHelper before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end context 'counting forks', :js do diff --git a/spec/features/admin/services/admin_activates_prometheus_spec.rb b/spec/features/admin/services/admin_activates_prometheus_spec.rb index 199eae59afc..a225de365c8 100644 --- a/spec/features/admin/services/admin_activates_prometheus_spec.rb +++ b/spec/features/admin/services/admin_activates_prometheus_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Admin activates Prometheus', :js do before do sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit(admin_application_settings_services_path) diff --git a/spec/features/admin/services/admin_visits_service_templates_spec.rb b/spec/features/admin/services/admin_visits_service_templates_spec.rb index a37e57304aa..563bca8b32f 100644 --- a/spec/features/admin/services/admin_visits_service_templates_spec.rb +++ b/spec/features/admin/services/admin_visits_service_templates_spec.rb @@ -8,6 +8,7 @@ RSpec.describe 'Admin visits service templates' do before do sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit(admin_application_settings_services_path) end diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb new file mode 100644 index 00000000000..e7dd50ed514 --- /dev/null +++ b/spec/features/admin/users/user_spec.rb @@ -0,0 +1,372 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Admin::Users::User' do + let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } + let_it_be(:current_user) { create(:admin, last_activity_on: 5.days.ago) } + + before do + sign_in(current_user) + gitlab_enable_admin_mode_sign_in(current_user) + stub_feature_flags(vue_admin_users: false) + end + + describe 'GET /admin/users/:id' do + it 'has user info', :aggregate_failures do + visit admin_users_path + click_link user.name + + expect(page).to have_content(user.email) + expect(page).to have_content(user.name) + expect(page).to have_content("ID: #{user.id}") + expect(page).to have_content("Namespace ID: #{user.namespace_id}") + expect(page).to have_button('Deactivate user') + expect(page).to have_button('Block user') + expect(page).to have_button('Delete user') + expect(page).to have_button('Delete user and contributions') + end + + context 'user pending approval' do + it 'shows user info', :aggregate_failures do + user = create(:user, :blocked_pending_approval) + + visit admin_users_path + click_link 'Pending approval' + click_link user.name + + expect(page).to have_content(user.name) + expect(page).to have_content('Pending approval') + expect(page).to have_link('Approve user') + expect(page).to have_link('Reject request') + end + end + + context 'when blocking/unblocking the user' do + it 'shows confirmation and allows blocking and unblocking', :js do + visit admin_user_path(user) + + find('button', text: 'Block user').click + + wait_for_requests + + expect(page).to have_content('Block user') + expect(page).to have_content('You can always unblock their account, their data will remain intact.') + + find('.modal-footer button', text: 'Block').click + + wait_for_requests + + expect(page).to have_content('Successfully blocked') + expect(page).to have_content('This user is blocked') + + find('button', text: 'Unblock user').click + + wait_for_requests + + expect(page).to have_content('Unblock user') + expect(page).to have_content('You can always block their account again if needed.') + + find('.modal-footer button', text: 'Unblock').click + + wait_for_requests + + expect(page).to have_content('Successfully unblocked') + expect(page).to have_content('Block this user') + end + end + + context 'when deactivating/re-activating the user' do + it 'shows confirmation and allows deactivating/re-activating', :js do + visit admin_user_path(user) + + find('button', text: 'Deactivate user').click + + wait_for_requests + + expect(page).to have_content('Deactivate user') + expect(page).to have_content('You can always re-activate their account, their data will remain intact.') + + find('.modal-footer button', text: 'Deactivate').click + + wait_for_requests + + expect(page).to have_content('Successfully deactivated') + expect(page).to have_content('Reactivate this user') + + find('button', text: 'Activate user').click + + wait_for_requests + + expect(page).to have_content('Activate user') + expect(page).to have_content('You can always deactivate their account again if needed.') + + find('.modal-footer button', text: 'Activate').click + + wait_for_requests + + expect(page).to have_content('Successfully activated') + expect(page).to have_content('Deactivate this user') + end + end + + describe 'Impersonation' do + let_it_be(:another_user) { create(:user) } + + context 'before impersonating' do + subject { visit admin_user_path(user_to_visit) } + + let(:user_to_visit) { another_user } + + context 'for other users' do + it 'shows impersonate button for other users' do + subject + + expect(page).to have_content('Impersonate') + end + end + + context 'for admin itself' do + let(:user_to_visit) { current_user } + + it 'does not show impersonate button for admin itself' do + subject + + expect(page).not_to have_content('Impersonate') + end + end + + context 'for blocked user' do + before do + another_user.block + end + + it 'does not show impersonate button for blocked user' do + subject + + expect(page).not_to have_content('Impersonate') + end + end + + context 'when impersonation is disabled' do + before do + stub_config_setting(impersonation_enabled: false) + end + + it 'does not show impersonate button' do + subject + + expect(page).not_to have_content('Impersonate') + end + end + end + + context 'when impersonating' do + subject { click_link 'Impersonate' } + + before do + visit admin_user_path(another_user) + end + + it 'logs in as the user when impersonate is clicked' do + subject + + expect(page.find(:css, '.header-user .profile-link')['data-user']).to eql(another_user.username) + end + + it 'sees impersonation log out icon' do + subject + + icon = first('[data-testid="incognito-icon"]') + expect(icon).not_to be nil + end + + context 'a user with an expired password' do + before do + another_user.update!(password_expires_at: Time.now - 5.minutes) + end + + it 'does not redirect to password change page' do + subject + + expect(current_path).to eq('/') + end + end + end + + context 'ending impersonation' do + subject { find(:css, 'li.impersonation a').click } + + before do + visit admin_user_path(another_user) + click_link 'Impersonate' + end + + it 'logs out of impersonated user back to original user' do + subject + + expect(page.find(:css, '.header-user .profile-link')['data-user']).to eq(current_user.username) + end + + it 'is redirected back to the impersonated users page in the admin after stopping' do + subject + + expect(current_path).to eq("/admin/users/#{another_user.username}") + end + + context 'a user with an expired password' do + before do + another_user.update!(password_expires_at: Time.now - 5.minutes) + end + + it 'is redirected back to the impersonated users page in the admin after stopping' do + subject + + expect(current_path).to eq("/admin/users/#{another_user.username}") + end + end + end + end + + describe 'Two-factor Authentication status' do + it 'shows when enabled' do + user.update!(otp_required_for_login: true) + + visit admin_user_path(user) + + expect_two_factor_status('Enabled') + end + + it 'shows when disabled' do + visit admin_user_path(user) + + expect_two_factor_status('Disabled') + end + + def expect_two_factor_status(status) + page.within('.two-factor-status') do + expect(page).to have_content(status) + end + end + end + + describe 'Email verification status' do + let!(:secondary_email) do + create :email, email: 'secondary@example.com', user: user + end + + it 'displays the correct status for an unverified email address', :aggregate_failures do + user.update!(confirmed_at: nil, unconfirmed_email: user.email) + visit admin_user_path(user) + + expect(page).to have_content("#{user.email} Unverified") + expect(page).to have_content("#{secondary_email.email} Unverified") + end + + it 'displays the correct status for a verified email address' do + visit admin_user_path(user) + expect(page).to have_content("#{user.email} Verified") + + secondary_email.confirm + expect(secondary_email.confirmed?).to be_truthy + + visit admin_user_path(user) + expect(page).to have_content("#{secondary_email.email} Verified") + end + end + end + + describe 'show user attributes' do + it 'has expected attributes', :aggregate_failures do + visit admin_users_path + + click_link user.name + + expect(page).to have_content 'Account' + expect(page).to have_content 'Personal projects limit' + end + end + + describe 'remove users secondary email', :js do + let!(:secondary_email) do + create :email, email: 'secondary@example.com', user: user + end + + it do + visit admin_user_path(user.username) + + expect(page).to have_content("Secondary email: #{secondary_email.email}") + + accept_confirm { find("#remove_email_#{secondary_email.id}").click } + + expect(page).not_to have_content(secondary_email.email) + end + end + + describe 'show user keys', :js do + it do + key1 = create(:key, user: user, title: 'ssh-rsa Key1', key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4FIEBXGi4bPU8kzxMefudPIJ08/gNprdNTaO9BR/ndy3+58s2HCTw2xCHcsuBmq+TsAqgEidVq4skpqoTMB+Uot5Uzp9z4764rc48dZiI661izoREoKnuRQSsRqUTHg5wrLzwxlQbl1MVfRWQpqiz/5KjBC7yLEb9AbusjnWBk8wvC1bQPQ1uLAauEA7d836tgaIsym9BrLsMVnR4P1boWD3Xp1B1T/ImJwAGHvRmP/ycIqmKdSpMdJXwxcb40efWVj0Ibbe7ii9eeoLdHACqevUZi6fwfbymdow+FeqlkPoHyGg3Cu4vD/D8+8cRc7mE/zGCWcQ15Var83Tczour Key1') + key2 = create(:key, user: user, title: 'ssh-rsa Key2', key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQSTWXhJAX/He+nG78MiRRRn7m0Pb0XbcgTxE0etArgoFoh9WtvDf36HG6tOSg/0UUNcp0dICsNAmhBKdncp6cIyPaXJTURPRAGvhI0/VDk4bi27bRnccGbJ/hDaUxZMLhhrzY0r22mjVf8PF6dvv5QUIQVm1/LeaWYsHHvLgiIjwrXirUZPnFrZw6VLREoBKG8uWvfSXw1L5eapmstqfsME8099oi+vWLR8MgEysZQmD28M73fgW4zek6LDQzKQyJx9nB+hJkKUDvcuziZjGmRFlNgSA2mguERwL1OXonD8WYUrBDGKroIvBT39zS5d9tQDnidEJZ9Y8gv5ViYP7x Key2') + + visit admin_users_path + + click_link user.name + click_link 'SSH keys' + + expect(page).to have_content(key1.title) + expect(page).to have_content(key2.title) + + click_link key2.title + + expect(page).to have_content(key2.title) + expect(page).to have_content(key2.key) + + click_button 'Delete' + + page.within('.modal') do + page.click_button('Delete') + end + + expect(page).not_to have_content(key2.title) + end + end + + describe 'show user identities' do + it 'shows user identities', :aggregate_failures do + visit admin_user_identities_path(user) + + expect(page).to have_content(user.name) + expect(page).to have_content('twitter') + end + end + + describe 'update user identities' do + before do + allow(Gitlab::Auth::OAuth::Provider).to receive(:providers).and_return([:twitter, :twitter_updated]) + end + + it 'modifies twitter identity', :aggregate_failures do + visit admin_user_identities_path(user) + + find('.table').find(:link, 'Edit').click + fill_in 'identity_extern_uid', with: '654321' + select 'twitter_updated', from: 'identity_provider' + click_button 'Save changes' + + expect(page).to have_content(user.name) + expect(page).to have_content('twitter_updated') + expect(page).to have_content('654321') + end + end + + describe 'remove user with identities' do + it 'removes user with twitter identity', :aggregate_failures do + visit admin_user_identities_path(user) + + click_link 'Delete' + + expect(page).to have_content(user.name) + expect(page).not_to have_content('twitter') + end + end +end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/users/users_spec.rb index 97a30143a59..9482b4f8603 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/users/users_spec.rb @@ -2,21 +2,20 @@ require 'spec_helper' -RSpec.describe "Admin::Users" do +RSpec.describe 'Admin::Users' do include Spec::Support::Helpers::Features::ResponsiveTableHelpers - let!(:user) do - create(:omniauth_user, provider: 'twitter', extern_uid: '123456') - end - - let!(:current_user) { create(:admin, last_activity_on: 5.days.ago) } + let_it_be(:user, reload: true) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } + let_it_be(:current_user) { create(:admin, last_activity_on: 5.days.ago) } before do sign_in(current_user) + gitlab_enable_admin_mode_sign_in(current_user) end - describe "GET /admin/users" do + describe 'GET /admin/users' do before do + stub_feature_flags(vue_admin_users: false) visit admin_users_path end @@ -27,8 +26,8 @@ RSpec.describe "Admin::Users" do it "has users list" do expect(page).to have_content(current_user.email) expect(page).to have_content(current_user.name) - expect(page).to have_content(current_user.created_at.strftime("%e %b, %Y")) - expect(page).to have_content(current_user.last_activity_on.strftime("%e %b, %Y")) + expect(page).to have_content(current_user.created_at.strftime('%e %b, %Y')) + expect(page).to have_content(current_user.last_activity_on.strftime('%e %b, %Y')) expect(page).to have_content(user.email) expect(page).to have_content(user.name) expect(page).to have_content('Projects') @@ -38,7 +37,7 @@ RSpec.describe "Admin::Users" do expect(page).to have_button('Delete user and contributions') end - describe "view extra user information" do + describe 'view extra user information' do it 'shows the user popover on hover', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/11290' do expect(page).not_to have_selector('#__BV_popover_1__') @@ -86,7 +85,7 @@ RSpec.describe "Admin::Users" do end describe 'search and sort' do - before do + before_all do create(:user, name: 'Foo Bar', last_activity_on: 3.days.ago) create(:user, name: 'Foo Baz', last_activity_on: 2.days.ago) create(:user, name: 'Dmitriy') @@ -205,15 +204,11 @@ RSpec.describe "Admin::Users" do end end - context 'when blocking a user' do - it 'shows confirmation and allows blocking', :js do + context 'when blocking/unblocking a user' do + it 'shows confirmation and allows blocking and unblocking', :js do expect(page).to have_content(user.email) - find("[data-testid='user-action-button-#{user.id}']").click - - within find("[data-testid='user-action-dropdown-#{user.id}']") do - find('li button', text: 'Block').click - end + click_action_in_user_dropdown(user.id, 'Block') wait_for_requests @@ -228,26 +223,92 @@ RSpec.describe "Admin::Users" do expect(page).to have_content('Successfully blocked') expect(page).not_to have_content(user.email) + + click_link 'Blocked' + + wait_for_requests + + expect(page).to have_content(user.email) + + click_action_in_user_dropdown(user.id, 'Unblock') + + expect(page).to have_content('Unblock user') + expect(page).to have_content('You can always block their account again if needed.') + + find('.modal-footer button', text: 'Unblock').click + + wait_for_requests + + expect(page).to have_content('Successfully unblocked') + expect(page).not_to have_content(user.email) + end + end + + context 'when deactivating/re-activating a user' do + it 'shows confirmation and allows deactivating and re-activating', :js do + expect(page).to have_content(user.email) + + click_action_in_user_dropdown(user.id, 'Deactivate') + + expect(page).to have_content('Deactivate user') + expect(page).to have_content('Deactivating a user has the following effects') + expect(page).to have_content('The user will be logged out') + expect(page).to have_content('Personal projects, group and user history will be left intact') + + find('.modal-footer button', text: 'Deactivate').click + + wait_for_requests + + expect(page).to have_content('Successfully deactivated') + expect(page).not_to have_content(user.email) + + click_link 'Deactivated' + + wait_for_requests + + expect(page).to have_content(user.email) + + click_action_in_user_dropdown(user.id, 'Activate') + + expect(page).to have_content('Activate user') + expect(page).to have_content('You can always deactivate their account again if needed.') + + find('.modal-footer button', text: 'Activate').click + + wait_for_requests + + expect(page).to have_content('Successfully activated') + expect(page).not_to have_content(user.email) end end + + def click_action_in_user_dropdown(user_id, action) + find("[data-testid='user-action-button-#{user_id}']").click + + within find("[data-testid='user-action-dropdown-#{user_id}']") do + find('li button', text: action).click + end + + wait_for_requests + end end - describe "GET /admin/users/new" do + describe 'GET /admin/users/new' do let(:user_username) { 'bang' } before do visit new_admin_user_path - fill_in "user_name", with: "Big Bang" - fill_in "user_username", with: user_username - fill_in "user_email", with: "bigbang@mail.com" + fill_in 'user_name', with: 'Big Bang' + fill_in 'user_username', with: user_username + fill_in 'user_email', with: 'bigbang@mail.com' end - it "creates new user" do - expect { click_button "Create user" }.to change {User.count}.by(1) + it 'creates new user' do + expect { click_button 'Create user' }.to change {User.count}.by(1) end - it "applies defaults to user" do - click_button "Create user" + it 'applies defaults to user' do + click_button 'Create user' user = User.find_by(username: 'bang') expect(user.projects_limit) .to eq(Gitlab.config.gitlab.default_projects_limit) @@ -255,24 +316,24 @@ RSpec.describe "Admin::Users" do .to eq(Gitlab.config.gitlab.default_can_create_group) end - it "creates user with valid data" do - click_button "Create user" + it 'creates user with valid data' do + click_button 'Create user' user = User.find_by(username: 'bang') expect(user.name).to eq('Big Bang') expect(user.email).to eq('bigbang@mail.com') end - it "calls send mail" do + it 'calls send mail' do expect_next_instance_of(NotificationService) do |instance| expect(instance).to receive(:new_user) end - click_button "Create user" + click_button 'Create user' end - it "sends valid email to user with email & password" do + it 'sends valid email to user with email & password' do perform_enqueued_jobs do - click_button "Create user" + click_button 'Create user' end user = User.find_by(username: 'bang') @@ -286,7 +347,7 @@ RSpec.describe "Admin::Users" do let(:user_username) { 'Bing bang' } it "doesn't create the user and shows an error message" do - expect { click_button "Create user" }.to change {User.count}.by(0) + expect { click_button 'Create user' }.to change {User.count}.by(0) expect(page).to have_content('The form contains the following error') expect(page).to have_content('Username can contain only letters, digits') @@ -356,252 +417,34 @@ RSpec.describe "Admin::Users" do end end - describe "GET /admin/users/:id" do - it "has user info" do - visit admin_users_path - click_link user.name - - expect(page).to have_content(user.email) - expect(page).to have_content(user.name) - expect(page).to have_content("ID: #{user.id}") - expect(page).to have_content("Namespace ID: #{user.namespace_id}") - expect(page).to have_button('Deactivate user') - expect(page).to have_button('Block user') - expect(page).to have_button('Delete user') - expect(page).to have_button('Delete user and contributions') - end - - context 'user pending approval' do - it 'shows user info' do - user = create(:user, :blocked_pending_approval) - - visit admin_users_path - click_link 'Pending approval' - click_link user.name - - expect(page).to have_content(user.name) - expect(page).to have_content('Pending approval') - expect(page).to have_link('Approve user') - expect(page).to have_button('Block user') - expect(page).to have_button('Delete user') - expect(page).to have_button('Delete user and contributions') - end - end - - context 'when blocking the user' do - it 'shows confirmation and allows blocking', :js do - visit admin_user_path(user) - - find('button', text: 'Block user').click - - wait_for_requests - - expect(page).to have_content('Block user') - expect(page).to have_content('You can always unblock their account, their data will remain intact.') - - find('.modal-footer button', text: 'Block').click - - wait_for_requests - - expect(page).to have_content('Successfully blocked') - expect(page).to have_content('This user is blocked') - end - end - - describe 'Impersonation' do - let(:another_user) { create(:user) } - - context 'before impersonating' do - subject { visit admin_user_path(user_to_visit) } - - let(:user_to_visit) { another_user } - - context 'for other users' do - it 'shows impersonate button for other users' do - subject - - expect(page).to have_content('Impersonate') - end - end - - context 'for admin itself' do - let(:user_to_visit) { current_user } - - it 'does not show impersonate button for admin itself' do - subject - - expect(page).not_to have_content('Impersonate') - end - end - - context 'for blocked user' do - before do - another_user.block - end - - it 'does not show impersonate button for blocked user' do - subject - - expect(page).not_to have_content('Impersonate') - end - end - - context 'when impersonation is disabled' do - before do - stub_config_setting(impersonation_enabled: false) - end - - it 'does not show impersonate button' do - subject - - expect(page).not_to have_content('Impersonate') - end - end - end - - context 'when impersonating' do - subject { click_link 'Impersonate' } - - before do - visit admin_user_path(another_user) - end - - it 'logs in as the user when impersonate is clicked' do - subject - - expect(page.find(:css, '.header-user .profile-link')['data-user']).to eql(another_user.username) - end - - it 'sees impersonation log out icon' do - subject - - icon = first('[data-testid="incognito-icon"]') - expect(icon).not_to be nil - end - - context 'a user with an expired password' do - before do - another_user.update(password_expires_at: Time.now - 5.minutes) - end - - it 'does not redirect to password change page' do - subject - - expect(current_path).to eq('/') - end - end - end - - context 'ending impersonation' do - subject { find(:css, 'li.impersonation a').click } - - before do - visit admin_user_path(another_user) - click_link 'Impersonate' - end - - it 'logs out of impersonated user back to original user' do - subject - - expect(page.find(:css, '.header-user .profile-link')['data-user']).to eq(current_user.username) - end - - it 'is redirected back to the impersonated users page in the admin after stopping' do - subject - - expect(current_path).to eq("/admin/users/#{another_user.username}") - end - - context 'a user with an expired password' do - before do - another_user.update(password_expires_at: Time.now - 5.minutes) - end - - it 'is redirected back to the impersonated users page in the admin after stopping' do - subject - - expect(current_path).to eq("/admin/users/#{another_user.username}") - end - end - end - end - - describe 'Two-factor Authentication status' do - it 'shows when enabled' do - user.update_attribute(:otp_required_for_login, true) - - visit admin_user_path(user) - - expect_two_factor_status('Enabled') - end - - it 'shows when disabled' do - visit admin_user_path(user) - - expect_two_factor_status('Disabled') - end - - def expect_two_factor_status(status) - page.within('.two-factor-status') do - expect(page).to have_content(status) - end - end - end - - describe 'Email verification status' do - let!(:secondary_email) do - create :email, email: 'secondary@example.com', user: user - end - - it 'displays the correct status for an unverified email address' do - user.update(confirmed_at: nil, unconfirmed_email: user.email) - visit admin_user_path(user) - - expect(page).to have_content("#{user.email} Unverified") - - expect(page).to have_content("#{secondary_email.email} Unverified") - end - - it 'displays the correct status for a verified email address' do - visit admin_user_path(user) - expect(page).to have_content("#{user.email} Verified") - - secondary_email.confirm - expect(secondary_email.confirmed?).to be_truthy - - visit admin_user_path(user) - expect(page).to have_content("#{secondary_email.email} Verified") - end - end - end - - describe "GET /admin/users/:id/edit" do + describe 'GET /admin/users/:id/edit' do before do + stub_feature_flags(vue_admin_users: false) visit admin_users_path click_link "edit_user_#{user.id}" end - it "has user edit page" do + it 'has user edit page' do expect(page).to have_content('Name') expect(page).to have_content('Password') end - describe "Update user" do + describe 'Update user' do before do - fill_in "user_name", with: "Big Bang" - fill_in "user_email", with: "bigbang@mail.com" - fill_in "user_password", with: "AValidPassword1" - fill_in "user_password_confirmation", with: "AValidPassword1" - choose "user_access_level_admin" - click_button "Save changes" + fill_in 'user_name', with: 'Big Bang' + fill_in 'user_email', with: 'bigbang@mail.com' + fill_in 'user_password', with: 'AValidPassword1' + fill_in 'user_password_confirmation', with: 'AValidPassword1' + choose 'user_access_level_admin' + click_button 'Save changes' end - it "shows page with new data" do + it 'shows page with new data' do expect(page).to have_content('bigbang@mail.com') expect(page).to have_content('Big Bang') end - it "changes user entry" do + it 'changes user entry' do user.reload expect(user.name).to eq('Big Bang') expect(user.admin?).to be_truthy @@ -623,9 +466,9 @@ RSpec.describe "Admin::Users" do end end - describe "GET /admin/users/:id/projects" do - let(:group) { create(:group) } - let!(:project) { create(:project, group: group) } + describe 'GET /admin/users/:id/projects' do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } before do group.add_developer(user) @@ -633,7 +476,7 @@ RSpec.describe "Admin::Users" do visit projects_admin_user_path(user) end - it "lists group projects" do + it 'lists group projects' do within(:css, '.gl-mb-3 + .card') do expect(page).to have_content 'Group projects' expect(page).to have_link group.name, href: admin_group_path(group) @@ -690,112 +533,13 @@ RSpec.describe "Admin::Users" do visit new_admin_user_identity_path(user) - check_breadcrumb("New Identity") + check_breadcrumb('New Identity') visit admin_user_identities_path(user) find('.table').find(:link, 'Edit').click - check_breadcrumb("Edit Identity") - end - end - - describe 'show user attributes' do - it do - visit admin_users_path - - click_link user.name - - expect(page).to have_content 'Account' - expect(page).to have_content 'Personal projects limit' - end - end - - describe 'remove users secondary email', :js do - let!(:secondary_email) do - create :email, email: 'secondary@example.com', user: user - end - - it do - visit admin_user_path(user.username) - - expect(page).to have_content("Secondary email: #{secondary_email.email}") - - accept_confirm { find("#remove_email_#{secondary_email.id}").click } - - expect(page).not_to have_content(secondary_email.email) - end - end - - describe 'show user keys', :js do - let!(:key1) do - create(:key, user: user, title: "ssh-rsa Key1", key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4FIEBXGi4bPU8kzxMefudPIJ08/gNprdNTaO9BR/ndy3+58s2HCTw2xCHcsuBmq+TsAqgEidVq4skpqoTMB+Uot5Uzp9z4764rc48dZiI661izoREoKnuRQSsRqUTHg5wrLzwxlQbl1MVfRWQpqiz/5KjBC7yLEb9AbusjnWBk8wvC1bQPQ1uLAauEA7d836tgaIsym9BrLsMVnR4P1boWD3Xp1B1T/ImJwAGHvRmP/ycIqmKdSpMdJXwxcb40efWVj0Ibbe7ii9eeoLdHACqevUZi6fwfbymdow+FeqlkPoHyGg3Cu4vD/D8+8cRc7mE/zGCWcQ15Var83Tczour Key1") - end - - let!(:key2) do - create(:key, user: user, title: "ssh-rsa Key2", key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQSTWXhJAX/He+nG78MiRRRn7m0Pb0XbcgTxE0etArgoFoh9WtvDf36HG6tOSg/0UUNcp0dICsNAmhBKdncp6cIyPaXJTURPRAGvhI0/VDk4bi27bRnccGbJ/hDaUxZMLhhrzY0r22mjVf8PF6dvv5QUIQVm1/LeaWYsHHvLgiIjwrXirUZPnFrZw6VLREoBKG8uWvfSXw1L5eapmstqfsME8099oi+vWLR8MgEysZQmD28M73fgW4zek6LDQzKQyJx9nB+hJkKUDvcuziZjGmRFlNgSA2mguERwL1OXonD8WYUrBDGKroIvBT39zS5d9tQDnidEJZ9Y8gv5ViYP7x Key2") - end - - it do - visit admin_users_path - - click_link user.name - click_link 'SSH keys' - - expect(page).to have_content(key1.title) - expect(page).to have_content(key2.title) - - click_link key2.title - - expect(page).to have_content(key2.title) - expect(page).to have_content(key2.key) - - click_button 'Delete' - - page.within('.modal') do - page.click_button('Delete') - end - - expect(page).not_to have_content(key2.title) - end - end - - describe 'show user identities' do - it 'shows user identities' do - visit admin_user_identities_path(user) - - expect(page).to have_content(user.name) - expect(page).to have_content('twitter') - end - end - - describe 'update user identities' do - before do - allow(Gitlab::Auth::OAuth::Provider).to receive(:providers).and_return([:twitter, :twitter_updated]) - end - - it 'modifies twitter identity' do - visit admin_user_identities_path(user) - - find('.table').find(:link, 'Edit').click - fill_in 'identity_extern_uid', with: '654321' - select 'twitter_updated', from: 'identity_provider' - click_button 'Save changes' - - expect(page).to have_content(user.name) - expect(page).to have_content('twitter_updated') - expect(page).to have_content('654321') - end - end - - describe 'remove user with identities' do - it 'removes user with twitter identity' do - visit admin_user_identities_path(user) - - click_link 'Delete' - - expect(page).to have_content(user.name) - expect(page).not_to have_content('twitter') + check_breadcrumb('Edit Identity') end end diff --git a/spec/features/alert_management/alert_management_list_spec.rb b/spec/features/alert_management/alert_management_list_spec.rb index 37658f8c545..44ed2f3d60c 100644 --- a/spec/features/alert_management/alert_management_list_spec.rb +++ b/spec/features/alert_management/alert_management_list_spec.rb @@ -5,54 +5,54 @@ require 'spec_helper' RSpec.describe 'Alert Management index', :js do let_it_be(:project) { create(:project) } let_it_be(:developer) { create(:user) } - let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered') } before_all do project.add_developer(developer) end - before do - sign_in(developer) + context 'when a developer displays the alert list' do + before do + sign_in(developer) - visit project_alert_management_index_path(project) - wait_for_requests - end - - context 'when a developer displays the alert list and alert integrations are not enabled' do - it 'shows the alert page title' do - expect(page).to have_content('Alerts') + visit project_alert_management_index_path(project) + wait_for_requests end - it 'shows the empty state by default' do + it 'shows the alert page title and empty state without filtered search or alert table' do + expect(page).to have_content('Alerts') expect(page).to have_content('Surface alerts in GitLab') - end - - it 'does not show the filtered search' do + expect(page).not_to have_selector('.gl-table') page.within('.layout-page') do expect(page).not_to have_css('[data-testid="search-icon"]') end end - it 'does not show the alert table' do - expect(page).not_to have_selector('.gl-table') + shared_examples 'alert page with title, filtered search, and table' do + it 'renders correctly' do + expect(page).to have_content('Alerts') + expect(page).to have_selector('.gl-table') + page.within('.layout-page') do + expect(page).to have_css('[data-testid="search-icon"]') + end + end end - end - context 'when a developer displays the alert list and an HTTP integration is enabled' do - let_it_be(:integration) { create(:alert_management_http_integration, project: project) } + context 'when alerts have already been created' do + let_it_be(:alert) { create(:alert_management_alert, project: project) } - it 'shows the alert page title' do - expect(page).to have_content('Alerts') + it_behaves_like 'alert page with title, filtered search, and table' end - it 'shows the filtered search' do - page.within('.layout-page') do - expect(page).to have_css('[data-testid="search-icon"]') - end + context 'when an HTTP integration is enabled' do + let_it_be(:integration) { create(:alert_management_http_integration, project: project) } + + it_behaves_like 'alert page with title, filtered search, and table' end - it 'shows the alert table' do - expect(page).to have_selector('.gl-table') + context 'when the prometheus integration is enabled' do + let_it_be(:integration) { create(:prometheus_service, project: project) } + + it_behaves_like 'alert page with title, filtered search, and table' end end end diff --git a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb index 0ded13ae607..698a36d3f76 100644 --- a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb +++ b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb @@ -17,7 +17,7 @@ RSpec.describe 'Alert integrations settings form', :js do end describe 'when viewing alert integrations as a maintainer' do - context 'with feature flag enabled' do + context 'with the default page permissions' do before do visit project_settings_operations_path(project, anchor: 'js-alert-management-settings') wait_for_requests @@ -33,19 +33,6 @@ RSpec.describe 'Alert integrations settings form', :js do expect(page).to have_content('1. Select integration type') end end - - context 'with feature flag disabled' do - before do - stub_feature_flags(http_integrations_list: false) - - visit project_settings_operations_path(project, anchor: 'js-alert-management-settings') - wait_for_requests - end - - it 'shows the old alerts setting form' do - expect(page).to have_content('Webhook URL') - end - end end describe 'when viewing alert integrations as a developer' do diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index f941adca233..8d0fa3e023b 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -37,6 +37,10 @@ RSpec.describe 'Issue Boards add issue modal', :js do end context 'modal interaction' do + before do + stub_feature_flags(add_issues_button: true) + end + it 'opens modal' do click_button('Add issues') @@ -72,6 +76,7 @@ RSpec.describe 'Issue Boards add issue modal', :js do context 'issues list' do before do + stub_feature_flags(add_issues_button: true) click_button('Add issues') wait_for_requests diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 06ec4e05828..b3cc2eb418d 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -27,11 +27,11 @@ RSpec.describe 'Issue Boards', :js do end it 'creates default lists' do - lists = ['Open', 'To Do', 'Doing', 'Closed'] + lists = %w[Open Closed] wait_for_requests - expect(page).to have_selector('.board', count: 4) + expect(page).to have_selector('.board', count: 2) page.all('.board').each_with_index do |list, i| expect(list.find('.board-title')).to have_content(lists[i]) diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb index f51b4d21e3b..cefb486349d 100644 --- a/spec/features/boards/keyboard_shortcut_spec.rb +++ b/spec/features/boards/keyboard_shortcut_spec.rb @@ -9,7 +9,9 @@ RSpec.describe 'Issue Boards shortcut', :js do before do create(:board, project: project) - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit project_path(project) end @@ -26,7 +28,9 @@ RSpec.describe 'Issue Boards shortcut', :js do let(:project) { create(:project, :issues_disabled) } before do - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit project_path(project) end diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 332c90df6d7..2af5b787a78 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -72,7 +72,7 @@ RSpec.describe 'Issue Boards', :js do end end - it 'removes card from board when clicking ' do + it 'removes card from board when clicking' do click_card(card) page.within('.issue-boards-sidebar') do diff --git a/spec/features/breadcrumbs_schema_markup_spec.rb b/spec/features/breadcrumbs_schema_markup_spec.rb index 30d5f40fea8..a87a3d284de 100644 --- a/spec/features/breadcrumbs_schema_markup_spec.rb +++ b/spec/features/breadcrumbs_schema_markup_spec.rb @@ -15,15 +15,12 @@ RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do item_list = get_schema_content - expect(item_list.size).to eq 3 + expect(item_list.size).to eq 2 expect(item_list[0]['name']).to eq project.namespace.name expect(item_list[0]['item']).to eq user_url(project.owner) expect(item_list[1]['name']).to eq project.name expect(item_list[1]['item']).to eq project_url(project) - - expect(item_list[2]['name']).to eq 'Details' - expect(item_list[2]['item']).to eq project_url(project) end it 'generates the breadcrumb schema for group projects' do @@ -31,7 +28,7 @@ RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do item_list = get_schema_content - expect(item_list.size).to eq 4 + expect(item_list.size).to eq 3 expect(item_list[0]['name']).to eq group.name expect(item_list[0]['item']).to eq group_url(group) @@ -40,9 +37,6 @@ RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do expect(item_list[2]['name']).to eq group_project.name expect(item_list[2]['item']).to eq project_url(group_project) - - expect(item_list[3]['name']).to eq 'Details' - expect(item_list[3]['item']).to eq project_url(group_project) end it 'generates the breadcrumb schema for group' do @@ -50,15 +44,12 @@ RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do item_list = get_schema_content - expect(item_list.size).to eq 3 + expect(item_list.size).to eq 2 expect(item_list[0]['name']).to eq group.name expect(item_list[0]['item']).to eq group_url(group) expect(item_list[1]['name']).to eq subgroup.name expect(item_list[1]['item']).to eq group_url(subgroup) - - expect(item_list[2]['name']).to eq 'Details' - expect(item_list[2]['item']).to eq group_url(subgroup) end it 'generates the breadcrumb schema for issues' do diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb index 31d6bcda9e8..6fe6c099d80 100644 --- a/spec/features/clusters/cluster_detail_page_spec.rb +++ b/spec/features/clusters/cluster_detail_page_spec.rb @@ -168,6 +168,10 @@ RSpec.describe 'Clusterable > Show page' do let(:cluster_path) { admin_cluster_path(cluster) } let(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + before do + gitlab_enable_admin_mode_sign_in(current_user) + end + it_behaves_like 'show page' do let(:cluster_type_label) { 'Instance cluster' } end diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 97ee891dbb8..f8e84043c1b 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -125,7 +125,7 @@ RSpec.describe 'Commits' do visit pipeline_path(pipeline) end - it 'Renders header', :js do + it 'renders header', :js do expect(page).to have_content pipeline.sha[0..7] expect(page).to have_content pipeline.git_commit_message.gsub!(/\s+/, ' ') expect(page).to have_content pipeline.user.name diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index b63079777cb..233a93c2054 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -24,10 +24,6 @@ RSpec.describe 'Value Stream Analytics', :js do wait_for_requests end - it 'shows introductory message' do - expect(page).to have_content('Introducing Value Stream Analytics') - end - it 'shows pipeline summary' do expect(new_issues_counter).to have_content('-') expect(commits_counter).to have_content('-') @@ -48,6 +44,16 @@ RSpec.describe 'Value Stream Analytics', :js do @build = create_cycle(user, project, issue, mr, milestone, pipeline) deploy_master(user, project) + issue.metrics.update!(first_mentioned_in_commit_at: issue.metrics.first_associated_with_milestone_at + 1.day) + merge_request = issue.merge_requests_closing_issues.first.merge_request + merge_request.update!(created_at: issue.metrics.first_associated_with_milestone_at + 1.day) + merge_request.metrics.update!( + latest_build_started_at: 4.hours.ago, + latest_build_finished_at: 3.hours.ago, + merged_at: merge_request.created_at + 1.hour, + first_deployed_to_production_at: merge_request.created_at + 2.hours + ) + sign_in(user) visit project_cycle_analytics_path(project) end diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb index 9965229a539..1b349fa2276 100644 --- a/spec/features/dashboard/archived_projects_spec.rb +++ b/spec/features/dashboard/archived_projects_spec.rb @@ -36,7 +36,7 @@ RSpec.describe 'Dashboard Archived Project' do end it 'searches archived projects', :js do - click_button 'Last updated' + click_button 'Name' click_link 'Show archived projects' expect(page).to have_link(project.name) diff --git a/spec/features/dashboard/group_spec.rb b/spec/features/dashboard/group_spec.rb index 653a16bbbcc..0b99fed2a2d 100644 --- a/spec/features/dashboard/group_spec.rb +++ b/spec/features/dashboard/group_spec.rb @@ -17,14 +17,11 @@ RSpec.describe 'Dashboard Group' do visit dashboard_groups_path find('.btn-success').click new_name = 'Samurai' - new_description = 'Tokugawa Shogunate' fill_in 'group_name', with: new_name - fill_in 'group_description', with: new_description click_button 'Create group' expect(current_path).to eq group_path(Group.find_by(name: new_name)) expect(page).to have_content(new_name) - expect(page).to have_content(new_description) end end diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index 952a78ec79a..0e76b5478a1 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -52,20 +52,29 @@ RSpec.describe 'Dashboard Merge Requests' do end context 'merge requests exist' do + let_it_be(:author_user) { create(:user) } let(:label) { create(:label) } let!(:assigned_merge_request) do create(:merge_request, assignees: [current_user], source_project: project, - author: create(:user)) + author: author_user) + end + + let!(:review_requested_merge_request) do + create(:merge_request, + reviewers: [current_user], + source_branch: 'review', + source_project: project, + author: author_user) end let!(:assigned_merge_request_from_fork) do create(:merge_request, source_branch: 'markdown', assignees: [current_user], target_project: public_project, source_project: forked_project, - author: create(:user)) + author: author_user) end let!(:authored_merge_request) do @@ -94,7 +103,7 @@ RSpec.describe 'Dashboard Merge Requests' do create(:merge_request, source_branch: 'fix', source_project: project, - author: create(:user)) + author: author_user) end before do @@ -111,6 +120,10 @@ RSpec.describe 'Dashboard Merge Requests' do expect(page).not_to have_content(labeled_merge_request.title) end + it 'does not show review requested merge requests' do + expect(page).not_to have_content(review_requested_merge_request.title) + end + it 'shows authored merge requests', :js do reset_filters input_filtered_search("author:=#{current_user.to_reference}") @@ -159,4 +172,25 @@ RSpec.describe 'Dashboard Merge Requests' do expect(find('.issues-filters')).to have_content('Created date') end end + + context 'merge request review', :js do + let_it_be(:author_user) { create(:user) } + let!(:review_requested_merge_request) do + create(:merge_request, + reviewers: [current_user], + source_branch: 'review', + source_project: project, + author: author_user) + end + + before do + visit merge_requests_dashboard_path(reviewer_username: current_user.username) + end + + it 'displays review requested merge requests' do + expect(page).to have_content(review_requested_merge_request.title) + + expect_tokens([reviewer_token(current_user.name)]) + end + end end diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index 58352518d43..b2fda28f0ec 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -13,7 +13,7 @@ RSpec.describe 'Dashboard shortcuts', :js do visit root_dashboard_path end - it 'Navigate to tabs' do + it 'navigate to tabs' do find('body').send_keys([:shift, 'I']) check_page_title('Issues') @@ -45,7 +45,7 @@ RSpec.describe 'Dashboard shortcuts', :js do visit explore_root_path end - it 'Navigate to tabs' do + it 'navigate to tabs' do find('body').send_keys([:shift, 'G']) find('.nothing-here-block') diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index 832f50932f4..9fa77d5917d 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -173,11 +173,11 @@ RSpec.describe 'Dashboard > User filters projects' do end end - it 'defaults to "Last updated"', :js do + it 'defaults to "Name"', :js do page.find('.filtered-search-block #filtered-search-sorting-dropdown').click active_sorting_option = page.first('.filtered-search-block #filtered-search-sorting-dropdown .is-active') - expect(active_sorting_option).to have_content 'Last updated' + expect(active_sorting_option).to have_content 'Name' end context 'Sorting by name' do diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb index 0912df22924..55bdf4c244e 100644 --- a/spec/features/expand_collapse_diffs_spec.rb +++ b/spec/features/expand_collapse_diffs_spec.rb @@ -10,7 +10,9 @@ RSpec.describe 'Expand and collapse diffs', :js do stub_feature_flags(increased_diff_limits: false) allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.kilobytes) - sign_in(create(:admin)) + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) # Ensure that undiffable.md is in .gitattributes project.repository.copy_gitattributes(branch) diff --git a/spec/features/file_uploads/git_lfs_spec.rb b/spec/features/file_uploads/git_lfs_spec.rb index b902d7ab702..239afb1a1bb 100644 --- a/spec/features/file_uploads/git_lfs_spec.rb +++ b/spec/features/file_uploads/git_lfs_spec.rb @@ -6,7 +6,7 @@ RSpec.describe 'Upload a git lfs object', :js do include_context 'file upload requests helpers' let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user, :admin) } + let_it_be(:user) { project.owner } let_it_be(:personal_access_token) { create(:personal_access_token, user: user) } let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') } @@ -19,7 +19,7 @@ RSpec.describe 'Upload a git lfs object', :js do HTTParty.put( url, headers: headers, - basic_auth: { user: user.username, password: personal_access_token.token }, + basic_auth: { username: user.username, password: personal_access_token.token }, body: file.read ) end diff --git a/spec/features/file_uploads/multipart_invalid_uploads_spec.rb b/spec/features/file_uploads/multipart_invalid_uploads_spec.rb index b3ace2e30ff..91c8e100e6a 100644 --- a/spec/features/file_uploads/multipart_invalid_uploads_spec.rb +++ b/spec/features/file_uploads/multipart_invalid_uploads_spec.rb @@ -17,7 +17,7 @@ RSpec.describe 'Invalid uploads that must be rejected', :api, :js do subject do HTTParty.put( url, - basic_auth: { user: user.username, password: personal_access_token.token }, + basic_auth: { username: user.username, password: personal_access_token.token }, body: body ) end diff --git a/spec/features/file_uploads/nuget_package_spec.rb b/spec/features/file_uploads/nuget_package_spec.rb index fb1e0a54744..6e05e5d1a6e 100644 --- a/spec/features/file_uploads/nuget_package_spec.rb +++ b/spec/features/file_uploads/nuget_package_spec.rb @@ -16,7 +16,7 @@ RSpec.describe 'Upload a nuget package', :api, :js do subject do HTTParty.put( url, - basic_auth: { user: user.username, password: personal_access_token.token }, + basic_auth: { username: user.username, password: personal_access_token.token }, body: { package: file } ) end diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index e6e4a55c1bb..19fb8e5f52c 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Global search' do + include AfterNextHelpers + let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } @@ -22,9 +24,7 @@ RSpec.describe 'Global search' do describe 'I search through the issues and I see pagination' do before do - allow_next_instance_of(SearchService) do |instance| - allow(instance).to receive(:per_page).and_return(1) - end + allow_next(SearchService).to receive(:per_page).and_return(1) create_list(:issue, 2, project: project, title: 'initial') end diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb index 29d0347086c..b25aa26d906 100644 --- a/spec/features/groups/board_spec.rb +++ b/spec/features/groups/board_spec.rb @@ -16,7 +16,7 @@ RSpec.describe 'Group Boards' do visit group_boards_path(group) end - it 'Adds an issue to the backlog' do + it 'adds an issue to the backlog' do page.within(find('.board', match: :first)) do issue_title = 'New Issue' find(:css, '.issue-count-badge-add-button').click diff --git a/spec/features/groups/container_registry_spec.rb b/spec/features/groups/container_registry_spec.rb index 1b23b8b4bf9..cacabdda22d 100644 --- a/spec/features/groups/container_registry_spec.rb +++ b/spec/features/groups/container_registry_spec.rb @@ -51,13 +51,6 @@ RSpec.describe 'Container Registry', :js do expect(page).to have_content 'my/image' end - it 'image repository delete is disabled' do - visit_container_registry - - delete_btn = find('[title="Remove repository"]') - expect(delete_btn).to be_disabled - end - it 'navigates to repo details' do visit_container_registry_details('my/image') diff --git a/spec/features/groups/dependency_proxy_spec.rb b/spec/features/groups/dependency_proxy_spec.rb index 9bbfdc488fb..51371ddc532 100644 --- a/spec/features/groups/dependency_proxy_spec.rb +++ b/spec/features/groups/dependency_proxy_spec.rb @@ -79,13 +79,19 @@ RSpec.describe 'Group Dependency Proxy' do sign_in(developer) end - context 'group is private' do - let(:group) { create(:group, :private) } + context 'feature flag is disabled' do + before do + stub_feature_flags(dependency_proxy_for_private_groups: false) + end - it 'informs user that feature is only available for public groups' do - visit path + context 'group is private' do + let(:group) { create(:group, :private) } - expect(page).to have_content('Dependency proxy feature is limited to public groups for now.') + it 'informs user that feature is only available for public groups' do + visit path + + expect(page).to have_content('Dependency proxy feature is limited to public groups for now.') + end end end diff --git a/spec/features/groups/import_export/connect_instance_spec.rb b/spec/features/groups/import_export/connect_instance_spec.rb new file mode 100644 index 00000000000..c0f967fd0b9 --- /dev/null +++ b/spec/features/groups/import_export/connect_instance_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Import/Export - Connect to another instance', :js do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + + before_all do + group.add_owner(user) + end + + before do + gitlab_sign_in(user) + + visit new_group_path + + find('#import-group-tab').click + end + + context 'when the user provides valid credentials' do + it 'successfully connects to remote instance' do + source_url = 'https://gitlab.com' + pat = 'demo-pat' + stub_path = 'stub-group' + + stub_request(:get, "%{url}/api/v4/groups?page=1&per_page=30&top_level_only=true" % { url: source_url }).to_return( + body: [{ + id: 2595438, + web_url: 'https://gitlab.com/groups/auto-breakfast', + name: 'Stub', + path: stub_path, + full_name: 'Stub', + full_path: stub_path + }].to_json, + headers: { 'Content-Type' => 'application/json' } + ) + + expect(page).to have_content 'Import groups from another instance of GitLab' + + fill_in :bulk_import_gitlab_url, with: source_url + fill_in :bulk_import_gitlab_access_token, with: pat + + click_on 'Connect instance' + + expect(page).to have_content 'Importing groups from %{url}' % { url: source_url } + expect(page).to have_content stub_path + end + end + + context 'when the user provides invalid url' do + it 'reports an error' do + source_url = 'invalid-url' + pat = 'demo-pat' + + fill_in :bulk_import_gitlab_url, with: source_url + fill_in :bulk_import_gitlab_access_token, with: pat + + click_on 'Connect instance' + + expect(page).to have_content 'Specified URL cannot be used' + end + end + + context 'when the user does not fill in source URL' do + it 'reports an error' do + pat = 'demo-pat' + + fill_in :bulk_import_gitlab_access_token, with: pat + + click_on 'Connect instance' + + expect(page).to have_content 'Please fill in GitLab source URL' + end + end + + context 'when the user does not fill in access token' do + it 'reports an error' do + source_url = 'https://gitlab.com' + + fill_in :bulk_import_gitlab_url, with: source_url + + click_on 'Connect instance' + + expect(page).to have_content 'Please fill in your personal access token' + end + end +end diff --git a/spec/features/groups/import_export/import_file_spec.rb b/spec/features/groups/import_export/import_file_spec.rb index f117b5d56e9..7018f3b1086 100644 --- a/spec/features/groups/import_export/import_file_spec.rb +++ b/spec/features/groups/import_export/import_file_spec.rb @@ -32,12 +32,12 @@ RSpec.describe 'Import/Export - Group Import', :js do fill_in :group_name, with: group_name find('#import-group-tab').click - expect(page).to have_content 'Import a GitLab group export file' + expect(page).to have_content 'Import group from file' attach_file(file) do find('.js-filepicker-button').click end - expect { click_on 'Import group' }.to change { Group.count }.by 1 + expect { click_on 'Import' }.to change { Group.count }.by 1 group = Group.find_by(name: group_name) @@ -60,7 +60,7 @@ RSpec.describe 'Import/Export - Group Import', :js do find('.js-filepicker-button').click end - expect { click_on 'Import group' }.to change { Group.count }.by 1 + expect { click_on 'Import' }.to change { Group.count }.by 1 group = Group.find_by(name: 'Test Group Import') expect(group.path).to eq 'custom-path' @@ -94,7 +94,7 @@ RSpec.describe 'Import/Export - Group Import', :js do find('.js-filepicker-button').click end - expect { click_on 'Import group' }.not_to change { Group.count } + expect { click_on 'Import' }.not_to change { Group.count } page.within('.flash-container') do expect(page).to have_content('Unable to process group import file') diff --git a/spec/features/groups/members/filter_members_spec.rb b/spec/features/groups/members/filter_members_spec.rb index b6d33b3f4aa..917b35659a6 100644 --- a/spec/features/groups/members/filter_members_spec.rb +++ b/spec/features/groups/members/filter_members_spec.rb @@ -11,8 +11,7 @@ RSpec.describe 'Groups > Members > Filter members', :js do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } - two_factor_auth_dropdown_toggle_selector = '[data-testid="member-filter-2fa-dropdown"] [data-testid="dropdown-toggle"]' - active_inherited_members_filter_selector = '[data-testid="filter-members-with-inherited-permissions"] a.is-active' + filtered_search_bar_selector = '[data-testid="members-filtered-search-bar"]' before do group.add_owner(user) @@ -27,7 +26,6 @@ RSpec.describe 'Groups > Members > Filter members', :js do expect(member(0)).to include(user.name) expect(member(1)).to include(user_with_2fa.name) - expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Everyone') end it 'shows only 2FA members' do @@ -35,7 +33,10 @@ RSpec.describe 'Groups > Members > Filter members', :js do expect(member(0)).to include(user_with_2fa.name) expect(all_rows.size).to eq(1) - expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Enabled') + + within filtered_search_bar_selector do + expect(page).to have_content '2FA = Enabled' + end end it 'shows only non 2FA members' do @@ -43,7 +44,10 @@ RSpec.describe 'Groups > Members > Filter members', :js do expect(member(0)).to include(user.name) expect(all_rows.size).to eq(1) - expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Disabled') + + within filtered_search_bar_selector do + expect(page).to have_content '2FA = Disabled' + end end it 'shows inherited members by default' do @@ -53,15 +57,16 @@ RSpec.describe 'Groups > Members > Filter members', :js do expect(member(1)).to include(user_with_2fa.name) expect(member(2)).to include(nested_group_user.name) expect(all_rows.size).to eq(3) - - expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show all members', visible: false) end it 'shows only group members' do visit_members_list(nested_group, with_inherited_permissions: 'exclude') expect(member(0)).to include(nested_group_user.name) expect(all_rows.size).to eq(1) - expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show only direct members', visible: false) + + within filtered_search_bar_selector do + expect(page).to have_content 'Membership = Direct' + end end it 'shows only inherited members' do @@ -69,7 +74,10 @@ RSpec.describe 'Groups > Members > Filter members', :js do expect(member(0)).to include(user.name) expect(member(1)).to include(user_with_2fa.name) expect(all_rows.size).to eq(2) - expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show only inherited members', visible: false) + + within filtered_search_bar_selector do + expect(page).to have_content 'Membership = Inherited' + end end def visit_members_list(group, options = {}) diff --git a/spec/features/groups/members/search_members_spec.rb b/spec/features/groups/members/search_members_spec.rb index 0b2d2fd478d..fe5fed307d7 100644 --- a/spec/features/groups/members/search_members_spec.rb +++ b/spec/features/groups/members/search_members_spec.rb @@ -21,9 +21,10 @@ RSpec.describe 'Search group member', :js do end it 'renders member users' do - page.within '[data-testid="user-search-form"]' do - fill_in 'search', with: member.name - find('[data-testid="user-search-submit"]').click + page.within '[data-testid="members-filtered-search-bar"]' do + find_field('Filter members').click + find('input').native.send_keys(member.name) + click_button 'Search' end expect(members_table).to have_content(member.name) diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb index f03cc36df18..68a748aa76a 100644 --- a/spec/features/groups/members/sort_members_spec.rb +++ b/spec/features/groups/members/sort_members_spec.rb @@ -9,8 +9,6 @@ RSpec.describe 'Groups > Members > Sort members', :js do let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) } let(:group) { create(:group) } - dropdown_toggle_selector = '[data-testid="user-sort-dropdown"] [data-testid="dropdown-toggle"]' - before do create(:group_member, :owner, user: owner, group: group, created_at: 5.days.ago) create(:group_member, :developer, user: developer, group: group, created_at: 3.days.ago) @@ -18,76 +16,174 @@ RSpec.describe 'Groups > Members > Sort members', :js do sign_in(owner) end - it 'sorts alphabetically by default' do - visit_members_list(sort: nil) + context 'when `group_members_filtered_search` feature flag is enabled' do + def expect_sort_by(text, sort_direction) + within('[data-testid="members-sort-dropdown"]') do + expect(page).to have_css('button[aria-haspopup="true"]', text: text) + expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}") + end + end - expect(first_row.text).to include(owner.name) - expect(second_row.text).to include(developer.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending') - end + it 'sorts by account by default' do + visit_members_list(sort: nil) - it 'sorts by access level ascending' do - visit_members_list(sort: :access_level_asc) + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) - expect(first_row.text).to include(developer.name) - expect(second_row.text).to include(owner.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, ascending') - end + expect_sort_by('Account', :asc) + end - it 'sorts by access level descending' do - visit_members_list(sort: :access_level_desc) + it 'sorts by max role ascending' do + visit_members_list(sort: :access_level_asc) - expect(first_row.text).to include(owner.name) - expect(second_row.text).to include(developer.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, descending') - end + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) - it 'sorts by last joined' do - visit_members_list(sort: :last_joined) + expect_sort_by('Max role', :asc) + end - expect(first_row.text).to include(developer.name) - expect(second_row.text).to include(owner.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Last joined') - end + it 'sorts by max role descending' do + visit_members_list(sort: :access_level_desc) - it 'sorts by oldest joined' do - visit_members_list(sort: :oldest_joined) + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) - expect(first_row.text).to include(owner.name) - expect(second_row.text).to include(developer.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest joined') - end + expect_sort_by('Max role', :desc) + end - it 'sorts by name ascending' do - visit_members_list(sort: :name_asc) + it 'sorts by access granted ascending' do + visit_members_list(sort: :last_joined) - expect(first_row.text).to include(owner.name) - expect(second_row.text).to include(developer.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending') - end + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) - it 'sorts by name descending' do - visit_members_list(sort: :name_desc) + expect_sort_by('Access granted', :asc) + end - expect(first_row.text).to include(developer.name) - expect(second_row.text).to include(owner.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Name, descending') - end + it 'sorts by access granted descending' do + visit_members_list(sort: :oldest_joined) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + + expect_sort_by('Access granted', :desc) + end + + it 'sorts by account ascending' do + visit_members_list(sort: :name_asc) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + + expect_sort_by('Account', :asc) + end + + it 'sorts by account descending' do + visit_members_list(sort: :name_desc) + + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) + + expect_sort_by('Account', :desc) + end + + it 'sorts by last sign-in ascending', :clean_gitlab_redis_shared_state do + visit_members_list(sort: :recent_sign_in) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + + expect_sort_by('Last sign-in', :asc) + end - it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do - visit_members_list(sort: :recent_sign_in) + it 'sorts by last sign-in descending', :clean_gitlab_redis_shared_state do + visit_members_list(sort: :oldest_sign_in) - expect(first_row.text).to include(owner.name) - expect(second_row.text).to include(developer.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Recent sign in') + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) + + expect_sort_by('Last sign-in', :desc) + end end - it 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do - visit_members_list(sort: :oldest_sign_in) + context 'when `group_members_filtered_search` feature flag is disabled' do + dropdown_toggle_selector = '[data-testid="user-sort-dropdown"] [data-testid="dropdown-toggle"]' + + before do + stub_feature_flags(group_members_filtered_search: false) + end + + it 'sorts alphabetically by default' do + visit_members_list(sort: nil) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending') + end + + it 'sorts by access level ascending' do + visit_members_list(sort: :access_level_asc) + + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, ascending') + end + + it 'sorts by access level descending' do + visit_members_list(sort: :access_level_desc) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, descending') + end + + it 'sorts by last joined' do + visit_members_list(sort: :last_joined) + + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Last joined') + end + + it 'sorts by oldest joined' do + visit_members_list(sort: :oldest_joined) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest joined') + end + + it 'sorts by name ascending' do + visit_members_list(sort: :name_asc) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending') + end + + it 'sorts by name descending' do + visit_members_list(sort: :name_desc) + + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Name, descending') + end + + it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do + visit_members_list(sort: :recent_sign_in) + + expect(first_row.text).to include(owner.name) + expect(second_row.text).to include(developer.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Recent sign in') + end + + it 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do + visit_members_list(sort: :oldest_sign_in) - expect(first_row.text).to include(developer.name) - expect(second_row.text).to include(owner.name) - expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest sign in') + expect(first_row.text).to include(developer.name) + expect(second_row.text).to include(owner.name) + expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest sign in') + end end def visit_members_list(sort:) diff --git a/spec/features/groups/members/tabs_spec.rb b/spec/features/groups/members/tabs_spec.rb index fa77d1a2ff8..2f95e9fa6d3 100644 --- a/spec/features/groups/members/tabs_spec.rb +++ b/spec/features/groups/members/tabs_spec.rb @@ -62,9 +62,10 @@ RSpec.describe 'Groups > Members > Tabs' do click_link 'Invited' - page.within '[data-testid="user-search-form"]' do - fill_in 'search_invited', with: 'email' - find('button[type="submit"]').click + page.within '[data-testid="members-filtered-search-bar"]' do + find_field('Search invited').click + find('input').native.send_keys('email') + click_button 'Search' end end @@ -74,9 +75,10 @@ RSpec.describe 'Groups > Members > Tabs' do before do click_link 'Members' - page.within '[data-testid="user-search-form"]' do - fill_in 'search', with: 'test' - find('button[type="submit"]').click + page.within '[data-testid="members-filtered-search-bar"]' do + find_field('Filter members').click + find('input').native.send_keys('test') + click_button 'Search' end end diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb index dec07eb3783..a4c450c9a2c 100644 --- a/spec/features/groups/navbar_spec.rb +++ b/spec/features/groups/navbar_spec.rb @@ -33,6 +33,7 @@ RSpec.describe 'Group navbar' do nav_item: _('Merge Requests'), nav_sub_items: [] }, + (security_and_compliance_nav_item if Gitlab.ee?), (push_rules_nav_item if Gitlab.ee?), { nav_item: _('Kubernetes'), diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index 97732374eb9..3a42fd508b4 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -193,4 +193,69 @@ RSpec.describe 'Group show page' do it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet' end + + context 'structured schema markup' do + let_it_be(:group) { create(:group, :public, :with_avatar, description: 'foo') } + let_it_be(:subgroup) { create(:group, :public, :with_avatar, parent: group, description: 'bar') } + let_it_be_with_reload(:project) { create(:project, :public, :with_avatar, namespace: group, description: 'foo') } + let_it_be(:subproject) { create(:project, :public, :with_avatar, namespace: subgroup, description: 'bar') } + + it 'shows Organization structured markup', :js do + visit path + wait_for_all_requests + + aggregate_failures do + expect(page).to have_selector('.content[itemscope][itemtype="https://schema.org/Organization"]') + + page.within('.group-home-panel') do + expect(page).to have_selector('img.avatar[itemprop="logo"]') + expect(page).to have_selector('[itemprop="name"]', text: group.name) + expect(page).to have_selector('[itemprop="description"]', text: group.description) + end + + page.within('[itemprop="owns"][itemtype="https://schema.org/SoftwareSourceCode"]') do + expect(page).to have_selector('img.avatar[itemprop="image"]') + expect(page).to have_selector('[itemprop="name"]', text: project.name) + expect(page).to have_selector('[itemprop="description"]', text: project.description) + end + + # Finding the subgroup row and expanding it + el = find('[itemprop="subOrganization"][itemtype="https://schema.org/Organization"]') + el.click + wait_for_all_requests + page.within(el) do + expect(page).to have_selector('img.avatar[itemprop="logo"]') + expect(page).to have_selector('[itemprop="name"]', text: subgroup.name) + expect(page).to have_selector('[itemprop="description"]', text: subgroup.description) + + page.within('[itemprop="owns"][itemtype="https://schema.org/SoftwareSourceCode"]') do + expect(page).to have_selector('img.avatar[itemprop="image"]') + expect(page).to have_selector('[itemprop="name"]', text: subproject.name) + expect(page).to have_selector('[itemprop="description"]', text: subproject.description) + end + end + end + end + + it 'does not include structured markup in shared projects tab', :js do + other_project = create(:project, :public) + other_project.project_group_links.create!(group: group) + + visit group_shared_path(group) + wait_for_all_requests + + expect(page).to have_selector('li.group-row') + expect(page).not_to have_selector('[itemprop="owns"][itemtype="https://schema.org/SoftwareSourceCode"]') + end + + it 'does not include structured markup in archived projects tab', :js do + project.update!(archived: true) + + visit group_archived_path(group) + wait_for_all_requests + + expect(page).to have_selector('li.group-row') + expect(page).not_to have_selector('[itemprop="owns"][itemtype="https://schema.org/SoftwareSourceCode"]') + end + end end diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index b9fd3a1a5cc..c9a0844932a 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Group' do - let(:user) { create(:admin) } + let_it_be(:user) { create(:user) } before do sign_in(user) @@ -21,8 +21,6 @@ RSpec.describe 'Group' do end describe 'as a non-admin' do - let(:user) { create(:user) } - it 'creates a group and persists visibility radio selection', :js do stub_application_setting(default_group_visibility: :private) @@ -38,6 +36,15 @@ RSpec.describe 'Group' do end end + describe 'with expected fields' do + it 'renders from as expected', :aggregate_failures do + expect(page).to have_field('name') + expect(page).to have_field('group_path') + expect(page).to have_field('group_visibility_level_0') + expect(page).not_to have_field('description') + end + end + describe 'with space in group path' do it 'renders new group form with validation errors' do fill_in 'Group URL', with: 'space group' @@ -137,9 +144,11 @@ RSpec.describe 'Group' do end describe 'create a nested group', :js do - let(:group) { create(:group, path: 'foo') } + let_it_be(:group) { create(:group, path: 'foo') } context 'as admin' do + let(:user) { create(:admin) } + before do visit new_group_path(group, parent_id: group.id) end @@ -185,11 +194,13 @@ RSpec.describe 'Group' do end describe 'group edit', :js do - let(:group) { create(:group, :public) } - let(:path) { edit_group_path(group) } + let_it_be(:group) { create(:group, :public) } + let(:path) { edit_group_path(group) } let(:new_name) { 'new-name' } before do + group.add_owner(user) + visit path end @@ -200,6 +211,8 @@ RSpec.describe 'Group' do it 'saves new settings' do page.within('.gs-general') do + # Have to reset it to '' so it overwrites rather than appends + fill_in('group_name', with: '') fill_in 'group_name', with: new_name click_button 'Save changes' end @@ -226,8 +239,12 @@ RSpec.describe 'Group' do end describe 'group page with markdown description' do - let(:group) { create(:group) } - let(:path) { group_path(group) } + let_it_be(:group) { create(:group) } + let(:path) { group_path(group) } + + before do + group.add_owner(user) + end it 'parses Markdown' do group.update_attribute(:description, 'This is **my** group') @@ -263,9 +280,13 @@ RSpec.describe 'Group' do end describe 'group page with nested groups', :js do - let!(:group) { create(:group) } - let!(:nested_group) { create(:group, parent: group) } - let!(:project) { create(:project, namespace: group) } + let_it_be(:group) { create(:group) } + let_it_be(:nested_group) { create(:group, parent: group) } + let_it_be(:project) { create(:project, namespace: group) } + + before do + group.add_owner(user) + end it 'renders projects and groups on the page' do visit group_path(group) @@ -292,7 +313,15 @@ RSpec.describe 'Group' do end describe 'new subgroup / project button' do - let(:group) { create(:group, project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS, subgroup_creation_level: Gitlab::Access::OWNER_SUBGROUP_ACCESS) } + let_it_be(:group, reload: true) do + create(:group, + project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS, + subgroup_creation_level: Gitlab::Access::OWNER_SUBGROUP_ACCESS) + end + + before do + group.add_owner(user) + end context 'when user has subgroup creation permissions but not project creation permissions' do it 'only displays "New subgroup" button' do @@ -325,6 +354,7 @@ RSpec.describe 'Group' do context 'when user has project and subgroup creation permissions' do it 'displays "New subgroup" and "New project" buttons' do group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) + visit group_path(group) page.within '[data-testid="group-buttons"]' do diff --git a/spec/features/ide/user_sees_editor_info_spec.rb b/spec/features/ide/user_sees_editor_info_spec.rb deleted file mode 100644 index 3760d6bd435..00000000000 --- a/spec/features/ide/user_sees_editor_info_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'IDE user sees editor info', :js do - include WebIdeSpecHelpers - - let_it_be(:project) { create(:project, :public, :repository) } - let_it_be(:user) { project.owner } - - before do - sign_in(user) - - ide_visit(project) - end - - it 'shows line position' do - ide_open_file('README.md') - - within find('.ide-status-bar') do - expect(page).to have_content('1:1') - end - - ide_set_editor_position(4, 10) - - within find('.ide-status-bar') do - expect(page).not_to have_content('1:1') - expect(page).to have_content('4:10') - end - end - - it 'updates after rename' do - ide_open_file('README.md') - ide_set_editor_position(4, 10) - - within find('.ide-status-bar') do - expect(page).to have_content('markdown') - expect(page).to have_content('4:10') - end - - ide_rename_file('README.md', 'READMEZ.txt') - - within find('.ide-status-bar') do - expect(page).to have_content('plaintext') - expect(page).to have_content('1:1') - end - end - - it 'persists position after rename' do - ide_open_file('README.md') - ide_set_editor_position(4, 10) - - ide_open_file('files/js/application.js') - ide_rename_file('README.md', 'READING_RAINBOW.md') - - ide_open_file('READING_RAINBOW.md') - - within find('.ide-status-bar') do - expect(page).to have_content('4:10') - end - end - - it 'persists position' do - ide_open_file('README.md') - ide_set_editor_position(4, 10) - - ide_close_file('README.md') - ide_open_file('README.md') - - within find('.ide-status-bar') do - expect(page).to have_content('markdown') - expect(page).to have_content('4:10') - end - end - - it 'persists viewer' do - ide_open_file('README.md') - click_link('Preview Markdown') - - within find('.md-previewer') do - expect(page).to have_content('testme') - end - - # Switch away from and back to the file - ide_open_file('.gitignore') - ide_open_file('README.md') - - # Preview is still enabled - within find('.md-previewer') do - expect(page).to have_content('testme') - end - end -end diff --git a/spec/features/incidents/user_views_incident_spec.rb b/spec/features/incidents/user_views_incident_spec.rb index 3595f5c03ec..b94ce3cd06f 100644 --- a/spec/features/incidents/user_views_incident_spec.rb +++ b/spec/features/incidents/user_views_incident_spec.rb @@ -13,8 +13,6 @@ RSpec.describe "User views incident" do end before do - stub_feature_flags(vue_issue_header: false) - sign_in(user) visit(project_issues_incident_path(project, incident)) @@ -24,10 +22,12 @@ RSpec.describe "User views incident" do it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet' - it 'shows the merge request and incident actions', :aggregate_failures do - expect(page).to have_link('New incident') + it 'shows the merge request and incident actions', :js, :aggregate_failures do + click_button 'Incident actions' + + expect(page).to have_link('New incident', href: new_project_issue_path(project, { issuable_template: 'incident', issue: { issue_type: 'incident' } })) expect(page).to have_button('Create merge request') - expect(page).to have_link('Close incident') + expect(page).to have_button('Close incident') end context 'when the project is archived' do diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index 0f0146a26a2..d773126e00c 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -105,7 +105,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j visit new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) end - it 'Shows a notice to ask someone else to resolve the threads' do + it 'shows a notice to ask someone else to resolve the threads' do expect(page).to have_content("The threads at #{merge_request.to_reference} will stay unresolved. Ask someone with permission to resolve them.") end end diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb index b449939a70c..99dc71f0559 100644 --- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb @@ -31,7 +31,8 @@ RSpec.describe 'Resolve an open thread in a merge request by creating an issue', visit project_merge_request_path(project, merge_request) end - it 'does not show a link to create a new issue' do + # https://gitlab.com/gitlab-org/gitlab/-/issues/285453 + xit 'does not show a link to create a new issue' do expect(page).not_to have_css resolve_discussion_selector end end @@ -81,7 +82,7 @@ RSpec.describe 'Resolve an open thread in a merge request by creating an issue', discussion_to_resolve: discussion.id) end - it 'Shows a notice to ask someone else to resolve the threads' do + it 'shows a notice to ask someone else to resolve the threads' do expect(page).to have_content("The thread at #{merge_request.to_reference}"\ " (discussion #{discussion.first_note.id}) will stay unresolved."\ " Ask someone with permission to resolve it.") diff --git a/spec/features/issuables/discussion_lock_spec.rb b/spec/features/issues/discussion_lock_spec.rb index 13f1742fbf6..13f1742fbf6 100644 --- a/spec/features/issuables/discussion_lock_spec.rb +++ b/spec/features/issues/discussion_lock_spec.rb diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 080943da185..4f4584e7dce 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -153,6 +153,14 @@ RSpec.describe 'Filter issues', :js do end end + describe 'filter by reviewer' do + it 'does not allow filtering by reviewer' do + find('.filtered-search').click + + expect(page).not_to have_button('Reviewer') + end + end + describe 'filter issues by label' do context 'only label' do it 'filters issues by searched label' do diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 06f79f94e8d..07bf821a590 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -418,6 +418,46 @@ RSpec.describe 'GFM autocomplete', :js do end end + context 'when other notes are destroyed' do + let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) } + + # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729 + it 'keeps autocomplete key listeners' do + visit project_issue_path(project, issue) + note = find('#note-body') + + start_comment_with_emoji(note) + + start_and_cancel_discussion + + note.fill_in(with: '') + start_comment_with_emoji(note) + note.native.send_keys(:enter) + + expect(note.value).to eql('Hello :100: ') + end + + def start_comment_with_emoji(note) + note.native.send_keys('Hello :10') + + wait_for_requests + + find('.atwho-view li', text: '100') + end + + def start_and_cancel_discussion + click_button('Reply...') + + fill_in('note_note', with: 'Whoops!') + + page.accept_alert 'Are you sure you want to cancel creating this comment?' do + click_button('Cancel') + end + + wait_for_requests + end + end + shared_examples 'autocomplete suggestions' do it 'suggests objects correctly' do page.within '.timeline-content-form' do @@ -550,6 +590,15 @@ RSpec.describe 'GFM autocomplete', :js do expect(find('.tribute-container ul', visible: true)).to have_text('alert milestone') end + it 'does not open autocomplete menu when trigger character is prefixed with text' do + page.within '.timeline-content-form' do + find('#note-body').native.send_keys('testing') + find('#note-body').native.send_keys('@') + end + + expect(page).not_to have_selector('.tribute-container', visible: true) + end + it 'selects the first item for assignee dropdowns' do page.within '.timeline-content-form' do find('#note-body').native.send_keys('@') @@ -618,21 +667,6 @@ RSpec.describe 'GFM autocomplete', :js do expect(page).to have_selector('.tribute-container', visible: true) end - it "does not show dropdown when preceded with a special character" do - note = find('#note-body') - page.within '.timeline-content-form' do - note.native.send_keys("@") - end - - expect(page).to have_selector('.tribute-container', visible: true) - - page.within '.timeline-content-form' do - note.native.send_keys("@") - end - - expect(page).not_to have_selector('.tribute-container') - end - it "does not throw an error if no labels exist" do note = find('#note-body') page.within '.timeline-content-form' do @@ -653,14 +687,6 @@ RSpec.describe 'GFM autocomplete', :js do expect_to_wrap(false, user_item, note, user.username) end - it 'doesn\'t open autocomplete after non-word character' do - page.within '.timeline-content-form' do - find('#note-body').native.send_keys("@#{user.username[0..2]}!") - end - - expect(page).not_to have_selector('.tribute-container') - end - it 'triggers autocomplete after selecting a quick action' do note = find('#note-body') page.within '.timeline-content-form' do @@ -848,46 +874,6 @@ RSpec.describe 'GFM autocomplete', :js do it_behaves_like 'autocomplete suggestions' end - - context 'when other notes are destroyed' do - let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) } - - # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729 - it 'keeps autocomplete key listeners' do - visit project_issue_path(project, issue) - note = find('#note-body') - - start_comment_with_emoji(note) - - start_and_cancel_discussion - - note.fill_in(with: '') - start_comment_with_emoji(note) - note.native.send_keys(:enter) - - expect(note.value).to eql('Hello :100: ') - end - - def start_comment_with_emoji(note) - note.native.send_keys('Hello :10') - - wait_for_requests - - find('.atwho-view li', text: '100') - end - - def start_and_cancel_discussion - click_button('Reply...') - - fill_in('note_note', with: 'Whoops!') - - page.accept_alert 'Are you sure you want to cancel creating this comment?' do - click_button('Cancel') - end - - wait_for_requests - end - end end private diff --git a/spec/features/issues/issue_header_spec.rb b/spec/features/issues/issue_header_spec.rb new file mode 100644 index 00000000000..cf375d8fb67 --- /dev/null +++ b/spec/features/issues/issue_header_spec.rb @@ -0,0 +1,164 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'issue header', :js do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:closed_issue) { create(:issue, :closed, project: project) } + let_it_be(:closed_locked_issue) { create(:issue, :closed, :locked, project: project) } + let_it_be(:authored_issue) { create(:issue, project: project, author: user) } + + context 'when user has permission to update' do + before do + project.add_maintainer(user) + sign_in(user) + end + + context 'within the issue actions dropdown menu' do + before do + visit project_issue_path(project, issue) + + # Click on the ellipsis icon + click_button 'Issue actions' + end + + it 'only shows the "New issue" and "Report abuse" items', :aggregate_failures do + expect(page).to have_link 'New issue' + expect(page).to have_link 'Report abuse' + expect(page).not_to have_link 'Submit as spam' + end + end + + context 'when the issue is open' do + before do + visit project_issue_path(project, issue) + end + + it 'has a "Close issue" button' do + expect(page).to have_button 'Close issue' + end + end + + context 'when the issue is closed' do + before do + visit project_issue_path(project, closed_issue) + end + + it 'has a "Reopen issue" button' do + expect(page).to have_button 'Reopen issue' + end + end + + context 'when the issue is closed and locked' do + before do + visit project_issue_path(project, closed_locked_issue) + end + + it 'does not have a "Reopen issue" button' do + expect(page).not_to have_button 'Reopen issue' + end + end + + context 'when the current user is the issue author' do + before do + visit project_issue_path(project, authored_issue) + end + + it 'does not show "Report abuse" link in dropdown' do + click_button 'Issue actions' + + expect(page).not_to have_link 'Report abuse' + end + end + end + + context 'when user is admin and the project is set up for spam' do + let_it_be(:admin) { create(:admin) } + let_it_be(:user_agent_detail) { create(:user_agent_detail, subject: issue) } + + before do + stub_application_setting(akismet_enabled: true) + project.add_maintainer(admin) + sign_in(admin) + end + + context 'within the issue actions dropdown menu' do + before do + visit project_issue_path(project, issue) + + # Click on the ellipsis icon + click_button 'Issue actions' + end + + it 'has "Submit as spam" item' do + expect(page).to have_link 'Submit as spam' + end + end + end + + context 'when user does not have permission to update' do + before do + project.add_guest(user) + sign_in(user) + end + + context 'within the issue actions dropdown menu' do + before do + visit project_issue_path(project, issue) + + # Click on the ellipsis icon + click_button 'Issue actions' + end + + it 'only shows the "New issue" and "Report abuse" items', :aggregate_failures do + expect(page).to have_link 'New issue' + expect(page).to have_link 'Report abuse' + expect(page).not_to have_link 'Submit as spam' + end + end + + context 'when the issue is open' do + before do + visit project_issue_path(project, issue) + end + + it 'does not have a "Close issue" button' do + expect(page).not_to have_button 'Close issue' + end + end + + context 'when the issue is closed' do + before do + visit project_issue_path(project, closed_issue) + end + + it 'does not have a "Reopen issue" button' do + expect(page).not_to have_button 'Reopen issue' + end + end + + context 'when the issue is closed and locked' do + before do + visit project_issue_path(project, closed_locked_issue) + end + + it 'does not have a "Reopen issue" button' do + expect(page).not_to have_button 'Reopen issue' + end + end + + context 'when the current user is the issue author' do + before do + visit project_issue_path(project, authored_issue) + end + + it 'does not show "Report abuse" link in dropdown' do + click_button 'Issue actions' + + expect(page).not_to have_link 'Report abuse' + end + end + end +end diff --git a/spec/features/issues/issue_state_spec.rb b/spec/features/issues/issue_state_spec.rb new file mode 100644 index 00000000000..0ef6eb56dff --- /dev/null +++ b/spec/features/issues/issue_state_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'issue state', :js do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + before do + project.add_developer(user) + sign_in(user) + end + + shared_examples 'issue closed' do |selector| + it 'can close an issue' do + expect(find('.status-box')).to have_content 'Open' + + within selector do + click_button 'Close issue' + end + + expect(find('.status-box')).to have_content 'Closed' + end + end + + shared_examples 'issue reopened' do |selector| + it 'can reopen an issue' do + expect(find('.status-box')).to have_content 'Closed' + + within selector do + click_button 'Reopen issue' + end + + expect(find('.status-box')).to have_content 'Open' + end + end + + describe 'when open' do + context 'when clicking the top `Close issue` button', :aggregate_failures do + let(:open_issue) { create(:issue, project: project) } + + before do + visit project_issue_path(project, open_issue) + end + + it_behaves_like 'issue closed', '.detail-page-header' + end + + context 'when clicking the bottom `Close issue` button', :aggregate_failures do + let(:open_issue) { create(:issue, project: project) } + + before do + visit project_issue_path(project, open_issue) + end + + it_behaves_like 'issue closed', '.timeline-content-form' + end + end + + describe 'when closed' do + context 'when clicking the top `Reopen issue` button', :aggregate_failures do + let(:closed_issue) { create(:issue, project: project, state: 'closed') } + + before do + visit project_issue_path(project, closed_issue) + end + + it_behaves_like 'issue reopened', '.detail-page-header' + end + + context 'when clicking the bottom `Reopen issue` button', :aggregate_failures do + let(:closed_issue) { create(:issue, project: project, state: 'closed') } + + before do + visit project_issue_path(project, closed_issue) + end + + it_behaves_like 'issue reopened', '.timeline-content-form' + end + end +end diff --git a/spec/features/issues/keyboard_shortcut_spec.rb b/spec/features/issues/keyboard_shortcut_spec.rb index ab40f124257..502412bab5d 100644 --- a/spec/features/issues/keyboard_shortcut_spec.rb +++ b/spec/features/issues/keyboard_shortcut_spec.rb @@ -8,7 +8,7 @@ RSpec.describe 'Issues shortcut', :js do let(:project) { create(:project) } before do - sign_in(create(:admin)) + sign_in(project.owner) visit project_path(project) end @@ -23,7 +23,7 @@ RSpec.describe 'Issues shortcut', :js do let(:project) { create(:project, :issues_disabled) } before do - sign_in(create(:admin)) + sign_in(project.owner) visit project_path(project) end diff --git a/spec/features/issuables/related_issues_spec.rb b/spec/features/issues/related_issues_spec.rb index 837859bbe26..837859bbe26 100644 --- a/spec/features/issuables/related_issues_spec.rb +++ b/spec/features/issues/related_issues_spec.rb diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb index 1512d539dec..02804d84a21 100644 --- a/spec/features/issues/service_desk_spec.rb +++ b/spec/features/issues/service_desk_spec.rb @@ -4,7 +4,9 @@ require 'spec_helper' RSpec.describe 'Service Desk Issue Tracker', :js do let(:project) { create(:project, :private, service_desk_enabled: true) } - let(:user) { create(:user) } + + let_it_be(:user) { create(:user) } + let_it_be(:support_bot) { User.support_bot } before do # The following two conditions equate to Gitlab::ServiceDesk.supported == true @@ -27,6 +29,16 @@ RSpec.describe 'Service Desk Issue Tracker', :js do end end + context 'issue page' do + let(:service_desk_issue) { create(:issue, project: project, author: support_bot, service_desk_reply_to: 'service.desk@example.com') } + + it 'shows service_desk_reply_to in issue header' do + visit project_issue_path(project, service_desk_issue) + + expect(page).to have_text('by service.desk@example.com via GitLab Support Bot') + end + end + describe 'issues list' do context 'when service desk is supported' do context 'when there are no issues' do @@ -66,10 +78,10 @@ RSpec.describe 'Service Desk Issue Tracker', :js do end context 'when there are issues' do - let(:support_bot) { User.support_bot } - let(:other_user) { create(:user) } - let!(:service_desk_issue) { create(:issue, project: project, author: support_bot) } - let!(:other_user_issue) { create(:issue, project: project, author: other_user) } + let_it_be(:project) { create(:project, :private, service_desk_enabled: true) } + let_it_be(:other_user) { create(:user) } + let_it_be(:service_desk_issue) { create(:issue, project: project, author: support_bot, service_desk_reply_to: 'service.desk@example.com') } + let_it_be(:other_user_issue) { create(:issue, project: project, author: other_user) } describe 'service desk info content' do before do @@ -94,6 +106,10 @@ RSpec.describe 'Service Desk Issue Tracker', :js do it 'only displays issues created by support bot' do expect(page).to have_selector('.issues-list .issue', count: 1) end + + it 'shows service_desk_reply_to in issues list' do + expect(page).to have_text('by service.desk@example.com via GitLab Support Bot') + end end describe 'search box' do diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb index 11b905735de..9d4a6cdb522 100644 --- a/spec/features/issues/user_edits_issue_spec.rb +++ b/spec/features/issues/user_edits_issue_spec.rb @@ -22,6 +22,7 @@ RSpec.describe "Issues > User edits issue", :js do context "from edit page" do before do + stub_licensed_features(multiple_issue_assignees: false) visit edit_project_issue_path(project, issue) end diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb index c5eb3f415ff..d88b816b186 100644 --- a/spec/features/issues/user_uses_quick_actions_spec.rb +++ b/spec/features/issues/user_uses_quick_actions_spec.rb @@ -43,5 +43,6 @@ RSpec.describe 'Issues > User uses quick actions', :js do it_behaves_like 'create_merge_request quick action' it_behaves_like 'move quick action' it_behaves_like 'zoom quick actions' + it_behaves_like 'clone quick action' end end diff --git a/spec/features/issues/user_views_issue_spec.rb b/spec/features/issues/user_views_issue_spec.rb index 4128f3478bb..8792d76981f 100644 --- a/spec/features/issues/user_views_issue_spec.rb +++ b/spec/features/issues/user_views_issue_spec.rb @@ -13,8 +13,6 @@ RSpec.describe "User views issue" do end before do - stub_feature_flags(vue_issue_header: false) - sign_in(user) visit(project_issue_path(project, issue)) @@ -24,10 +22,12 @@ RSpec.describe "User views issue" do it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet' - it 'shows the merge request and issue actions', :aggregate_failures do - expect(page).to have_link('New issue') + it 'shows the merge request and issue actions', :js, :aggregate_failures do + click_button 'Issue actions' + + expect(page).to have_link('New issue', href: new_project_issue_path(project)) expect(page).to have_button('Create merge request') - expect(page).to have_link('Close issue') + expect(page).to have_button('Close issue') end context 'when the project is archived' do diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb index fbf4e531db1..c9dc764f93b 100644 --- a/spec/features/markdown/copy_as_gfm_spec.rb +++ b/spec/features/markdown/copy_as_gfm_spec.rb @@ -7,10 +7,6 @@ RSpec.describe 'Copy as GFM', :js do include RepoHelpers include ActionView::Helpers::JavaScriptHelper - before do - sign_in(create(:admin)) - end - describe 'Copying rendered GFM' do before do @feat = MarkdownFeature.new @@ -18,6 +14,9 @@ RSpec.describe 'Copy as GFM', :js do # `markdown` helper expects a `@project` variable @project = @feat.project + user = create(:user) + @project.add_maintainer(user) + sign_in(user) visit project_issue_path(@project, @feat.issue) end @@ -650,6 +649,10 @@ RSpec.describe 'Copy as GFM', :js do describe 'Copying code' do let(:project) { create(:project, :repository) } + before do + sign_in(project.owner) + end + context 'from a diff' do shared_examples 'copying code from a diff' do context 'selecting one word of text' do diff --git a/spec/features/markdown/mermaid_spec.rb b/spec/features/markdown/mermaid_spec.rb index 58314a49c4b..23cdd9d2ce5 100644 --- a/spec/features/markdown/mermaid_spec.rb +++ b/spec/features/markdown/mermaid_spec.rb @@ -48,7 +48,7 @@ RSpec.describe 'Mermaid rendering', :js do expect(page.html.scan(expected).count).to be(4) end - it 'renders only 2 Mermaid blocks and ', :js, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/234081' } do + it 'renders only 2 Mermaid blocks and', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/234081' do description = <<~MERMAID ```mermaid graph LR @@ -78,7 +78,7 @@ RSpec.describe 'Mermaid rendering', :js do end end - it 'correctly sizes mermaid diagram inside <details> block', :js do + it 'correctly sizes mermaid diagram inside <details> block' do description = <<~MERMAID <details> <summary>Click to show diagram</summary> @@ -112,7 +112,7 @@ RSpec.describe 'Mermaid rendering', :js do end end - it 'correctly sizes mermaid diagram block', :js do + it 'correctly sizes mermaid diagram block' do description = <<~MERMAID ```mermaid graph TD; @@ -134,7 +134,7 @@ RSpec.describe 'Mermaid rendering', :js do expect(page).to have_css('svg.mermaid[style*="max-width"][width="100%"]') end - it 'display button when diagram exceeds length', :js do + it 'display button when diagram exceeds length', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/287806' do graph_edges = "A-->B;B-->A;" * 420 description = <<~MERMAID diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/merge_request/close_reopen_report_toggle_spec.rb index 867d2ff7aae..8a4277d87c9 100644 --- a/spec/features/issuables/close_reopen_report_toggle_spec.rb +++ b/spec/features/merge_request/close_reopen_report_toggle_spec.rb @@ -7,51 +7,10 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do let(:user) { create(:user) } - before do - stub_feature_flags(vue_issue_header: false) - end - - shared_examples 'an issuable close/reopen/report toggle' do - let(:container) { find('.issuable-close-dropdown') } - let(:human_model_name) { issuable.model_name.human.downcase } - - it 'shows toggle' do - expect(page).to have_button("Close #{human_model_name}") - expect(page).to have_selector('.issuable-close-dropdown') - end - - it 'opens a dropdown when toggle is clicked' do - container.find('.dropdown-toggle').click - - expect(container).to have_selector('.dropdown-menu') - expect(container).to have_content("Close #{human_model_name}") - expect(container).to have_content('Report abuse') - expect(container).to have_content("Report #{human_model_name.pluralize} that are abusive, inappropriate or spam.") - - if issuable.is_a?(MergeRequest) - page.within('.js-issuable-close-dropdown') do - expect(page).to have_link('Close merge request') - end - else - expect(container).to have_selector('.close-item.droplab-item-selected') - end - - expect(container).to have_selector('.report-item') - expect(container).not_to have_selector('.report-item.droplab-item-selected') - expect(container).not_to have_selector('.reopen-item') - end - - it 'links to Report Abuse' do - container.find('.dropdown-toggle').click - container.find('.report-abuse-link').click - - expect(page).to have_content('Report abuse to admin') - end - end - - context 'on an issue' do - let(:project) { create(:project) } - let(:issuable) { create(:issue, project: project) } + context 'on a merge request' do + let(:container) { find('.detail-page-header-actions') } + let(:project) { create(:project, :repository) } + let(:issuable) { create(:merge_request, source_project: project) } before do project.add_maintainer(user) @@ -60,67 +19,38 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do context 'when user has permission to update', :js do before do - visit project_issue_path(project, issuable) + visit project_merge_request_path(project, issuable) end - it_behaves_like 'an issuable close/reopen/report toggle' - - context 'when the issue is closed and locked' do - let(:issuable) { create(:issue, :closed, :locked, project: project) } + context 'close/reopen/report toggle' do + it 'opens a dropdown when toggle is clicked' do + click_button 'Toggle dropdown' - it 'hides the reopen button' do - expect(page).not_to have_button('Reopen issue') + expect(container).to have_link("Close merge request") + expect(container).to have_link('Report abuse') + expect(container).to have_text("Report merge requests that are abusive, inappropriate or spam.") end - context 'when the issue author is the current user' do - before do - issuable.update(author: user) - end + it 'links to Report Abuse' do + click_button 'Toggle dropdown' + click_link 'Report abuse' - it 'hides the reopen button' do - expect(page).not_to have_button('Reopen issue') - end + expect(page).to have_content('Report abuse to admin') end end - end - - context 'when user doesnt have permission to update' do - let(:cant_project) { create(:project) } - let(:cant_issuable) { create(:issue, project: cant_project) } - - before do - cant_project.add_guest(user) - - visit project_issue_path(cant_project, cant_issuable) - end - - it 'only shows the `Report abuse` and `New issue` buttons' do - expect(page).to have_link('Report abuse') - expect(page).to have_link('New issue') - expect(page).not_to have_button('Close issue') - expect(page).not_to have_button('Reopen issue') - expect(page).not_to have_link(title: 'Edit title and description') - end - end - end - - context 'on a merge request' do - let(:container) { find('.detail-page-header-actions') } - let(:project) { create(:project, :repository) } - let(:issuable) { create(:merge_request, source_project: project) } - before do - project.add_maintainer(user) - login_as user - end + context 'when the merge request is open' do + let(:issuable) { create(:merge_request, :opened, source_project: project) } - context 'when user has permission to update', :js do - before do - visit project_merge_request_path(project, issuable) + it 'shows the `Edit` and `Mark as draft` buttons' do + expect(container).to have_link('Edit') + expect(container).to have_link('Mark as draft') + expect(container).not_to have_button('Report abuse') + expect(container).not_to have_button('Close merge request') + expect(container).not_to have_link('Reopen merge request') + end end - it_behaves_like 'an issuable close/reopen/report toggle' - context 'when the merge request is closed' do let(:issuable) { create(:merge_request, :closed, source_project: project) } diff --git a/spec/features/issuables/merge_request_discussion_lock_spec.rb b/spec/features/merge_request/merge_request_discussion_lock_spec.rb index 4e0265839f6..4e0265839f6 100644 --- a/spec/features/issuables/merge_request_discussion_lock_spec.rb +++ b/spec/features/merge_request/merge_request_discussion_lock_spec.rb diff --git a/spec/features/merge_request/user_closes_merge_request_spec.rb b/spec/features/merge_request/user_closes_merge_request_spec.rb deleted file mode 100644 index e6b6778c76e..00000000000 --- a/spec/features/merge_request/user_closes_merge_request_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User closes a merge requests', :js do - let(:project) { create(:project, :repository) } - let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - let(:user) { create(:user) } - - before do - project.add_maintainer(user) - sign_in(user) - - visit(merge_request_path(merge_request)) - end - - it 'closes a merge request' do - click_button('Close merge request', match: :first) - - expect(page).to have_content(merge_request.title) - expect(page).to have_content('Closed by') - end -end diff --git a/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb b/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb new file mode 100644 index 00000000000..6376f9ab5fd --- /dev/null +++ b/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User closes/reopens a merge request', :js do + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user) } + + before do + project.add_developer(user) + sign_in(user) + end + + describe 'when open' do + context 'when clicking the top `Close merge request` link', :aggregate_failures do + let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) } + + before do + visit merge_request_path(open_merge_request) + end + + it 'can close a merge request' do + expect(find('.status-box')).to have_content 'Open' + + within '.detail-page-header' do + click_button 'Toggle dropdown' + click_link 'Close merge request' + end + + wait_for_requests + + expect(find('.status-box')).to have_content 'Closed' + end + end + + context 'when clicking the bottom `Close merge request` button', :aggregate_failures do + let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) } + + before do + visit merge_request_path(open_merge_request) + end + + it 'can close a merge request' do + expect(find('.status-box')).to have_content 'Open' + + within '.timeline-content-form' do + click_button 'Close merge request' + + # Clicking the bottom `Close merge request` button does not yet update + # the header status so for now we'll check that the button text changes + expect(page).not_to have_button 'Close merge request' + expect(page).to have_button 'Reopen merge request' + end + end + end + end + + describe 'when closed' do + context 'when clicking the top `Reopen merge request` link', :aggregate_failures do + let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') } + + before do + visit merge_request_path(closed_merge_request) + end + + it 'can reopen a merge request' do + expect(find('.status-box')).to have_content 'Closed' + + within '.detail-page-header' do + click_button 'Toggle dropdown' + click_link 'Reopen merge request' + end + + wait_for_requests + + expect(find('.status-box')).to have_content 'Open' + end + end + + context 'when clicking the bottom `Reopen merge request` button', :aggregate_failures do + let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') } + + before do + visit merge_request_path(closed_merge_request) + end + + it 'can reopen a merge request' do + expect(find('.status-box')).to have_content 'Closed' + + within '.timeline-content-form' do + click_button 'Reopen merge request' + + # Clicking the bottom `Reopen merge request` button does not yet update + # the header status so for now we'll check that the button text changes + expect(page).not_to have_button 'Reopen merge request' + expect(page).to have_button 'Close merge request' + end + end + end + end +end diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb index c452408cff2..0fd140a00bd 100644 --- a/spec/features/merge_request/user_comments_on_diff_spec.rb +++ b/spec/features/merge_request/user_comments_on_diff_spec.rb @@ -31,7 +31,7 @@ RSpec.describe 'User comments on a diff', :js do click_button('Add comment now') end - page.within('.diff-files-holder > div:nth-child(3)') do + page.within('.diff-files-holder > div:nth-child(6)') do expect(page).to have_content('Line is wrong') find('.js-diff-more-actions').click @@ -53,7 +53,7 @@ RSpec.describe 'User comments on a diff', :js do wait_for_requests - page.within('.diff-files-holder > div:nth-child(2) .note-body > .note-text') do + page.within('.diff-files-holder > div:nth-child(5) .note-body > .note-text') do expect(page).to have_content('Line is correct') end @@ -67,7 +67,7 @@ RSpec.describe 'User comments on a diff', :js do wait_for_requests # Hide the comment. - page.within('.diff-files-holder > div:nth-child(3)') do + page.within('.diff-files-holder > div:nth-child(6)') do find('.js-diff-more-actions').click click_button 'Hide comments on this file' @@ -76,22 +76,22 @@ RSpec.describe 'User comments on a diff', :js do # At this moment a user should see only one comment. # The other one should be hidden. - page.within('.diff-files-holder > div:nth-child(2) .note-body > .note-text') do + page.within('.diff-files-holder > div:nth-child(5) .note-body > .note-text') do expect(page).to have_content('Line is correct') end # Show the comment. - page.within('.diff-files-holder > div:nth-child(3)') do + page.within('.diff-files-holder > div:nth-child(6)') do find('.js-diff-more-actions').click click_button 'Show comments on this file' end # Now both the comments should be shown. - page.within('.diff-files-holder > div:nth-child(3) .note-body > .note-text') do + page.within('.diff-files-holder > div:nth-child(6) .note-body > .note-text') do expect(page).to have_content('Line is wrong') end - page.within('.diff-files-holder > div:nth-child(2) .note-body > .note-text') do + page.within('.diff-files-holder > div:nth-child(5) .note-body > .note-text') do expect(page).to have_content('Line is correct') end @@ -102,11 +102,11 @@ RSpec.describe 'User comments on a diff', :js do wait_for_requests - page.within('.diff-files-holder > div:nth-child(3) .parallel .note-body > .note-text') do + page.within('.diff-files-holder > div:nth-child(6) .parallel .note-body > .note-text') do expect(page).to have_content('Line is wrong') end - page.within('.diff-files-holder > div:nth-child(2) .parallel .note-body > .note-text') do + page.within('.diff-files-holder > div:nth-child(5) .parallel .note-body > .note-text') do expect(page).to have_content('Line is correct') end end @@ -136,7 +136,7 @@ RSpec.describe 'User comments on a diff', :js do add_comment('-13', '+15') end - it 'allows comments on previously hidden lines at the top of a file' do + it 'allows comments on previously hidden lines at the top of a file', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/285294' do # Click -9, expand up, select 1 add and verify comment page.within('[data-path="files/ruby/popen.rb"]') do all('.js-unfold-all')[0].click @@ -204,7 +204,7 @@ RSpec.describe 'User comments on a diff', :js do click_button('Add comment now') end - page.within('.diff-file:nth-of-type(5) .discussion .note') do + page.within('.diff-file:nth-of-type(1) .discussion .note') do find('.js-note-edit').click page.within('.current-note-edit-form') do @@ -215,7 +215,7 @@ RSpec.describe 'User comments on a diff', :js do expect(page).not_to have_button('Save comment', disabled: true) end - page.within('.diff-file:nth-of-type(5) .discussion .note') do + page.within('.diff-file:nth-of-type(1) .discussion .note') do expect(page).to have_content('Typo, please fix').and have_no_content('Line is wrong') end end @@ -234,7 +234,7 @@ RSpec.describe 'User comments on a diff', :js do expect(page).to have_content('1') end - page.within('.diff-file:nth-of-type(5) .discussion .note') do + page.within('.diff-file:nth-of-type(1) .discussion .note') do find('.more-actions').click find('.more-actions .dropdown-menu li', match: :first) diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb index 9556142ecb8..794dfd7c8da 100644 --- a/spec/features/merge_request/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb @@ -74,7 +74,10 @@ RSpec.describe 'Merge request > User posts diff notes', :js do context 'with an unfolded line' do before do - find('.js-unfold', match: :first).click + page.within('.file-holder[id="a5cc2925ca8258af241be7e5b0381edf30266302"]') do + find('.js-unfold', match: :first).click + end + wait_for_requests end @@ -137,7 +140,10 @@ RSpec.describe 'Merge request > User posts diff notes', :js do context 'with an unfolded line' do before do - find('.js-unfold', match: :first).click + page.within('.file-holder[id="a5cc2925ca8258af241be7e5b0381edf30266302"]') do + find('.js-unfold', match: :first).click + end + wait_for_requests end diff --git a/spec/features/merge_request/user_reopens_merge_request_spec.rb b/spec/features/merge_request/user_reopens_merge_request_spec.rb deleted file mode 100644 index 4a05a3be59a..00000000000 --- a/spec/features/merge_request/user_reopens_merge_request_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User reopens a merge requests', :js do - let(:project) { create(:project, :public, :repository) } - let!(:merge_request) { create(:closed_merge_request, source_project: project, target_project: project) } - let(:user) { create(:user) } - - before do - project.add_maintainer(user) - sign_in(user) - - visit(merge_request_path(merge_request)) - end - - it 'reopens a merge request' do - find('.js-issuable-close-dropdown .dropdown-toggle').click - - click_link('Reopen merge request', match: :first) - - wait_for_requests - - page.within('.status-box') do - expect(page).to have_content('Open') - end - end -end diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb index 06405232462..1b1152897fc 100644 --- a/spec/features/merge_request/user_resolves_conflicts_spec.rb +++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb @@ -8,11 +8,6 @@ RSpec.describe 'Merge request > User resolves conflicts', :js do let(:project) { create(:project, :repository) } let(:user) { project.creator } - before do - # In order to have the diffs collapsed, we need to disable the increase feature - stub_feature_flags(gitlab_git_diff_size_limit_increase: false) - end - def create_merge_request(source_branch) create(:merge_request, source_branch: source_branch, target_branch: 'conflict-start', source_project: project, merge_status: :unchecked) do |mr| mr.mark_as_unmergeable diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb index 00f0c88497b..cb7c952dfe4 100644 --- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb +++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb @@ -111,7 +111,6 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do it 'shows resolved thread when toggled' do find(".timeline-content .discussion[data-discussion-id='#{note.discussion_id}'] .discussion-toggle-button").click - expect(page.find(".line-holder-placeholder")).to be_visible expect(page.find(".timeline-content #note_#{note.id}")).to be_visible end diff --git a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb index e47f9ff2660..38546fd629d 100644 --- a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb +++ b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb @@ -18,8 +18,8 @@ RSpec.describe 'Merge request > User sees check out branch modal', :js do expect(page).to have_content('Check out, review, and merge locally') end - it 'closes the check out branch modal with escape keypress' do - find('#modal_merge_info').send_keys(:escape) + it 'closes the check out branch modal with the close action' do + find('.modal button[aria-label="Close"]').click expect(page).not_to have_content('Check out, review, and merge locally') end diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb index 7b319f6aff8..6647a4e9291 100644 --- a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb +++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb @@ -27,7 +27,6 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', before do stub_application_setting(auto_devops_enabled: false) - stub_feature_flags(ci_merge_request_pipeline: true) stub_ci_pipeline_yaml_file(YAML.dump(config)) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index fb616ceae9d..8930c55a28c 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -17,6 +17,8 @@ RSpec.describe 'Merge request > User sees versions', :js do let!(:params) { {} } before do + stub_feature_flags(diffs_gradual_load: false) + project.add_maintainer(user) sign_in(user) visit diffs_project_merge_request_path(project, merge_request, params) @@ -73,12 +75,12 @@ RSpec.describe 'Merge request > User sees versions', :js do it 'shows the commit SHAs for every version in the dropdown' do page.within '.mr-version-dropdown' do - find('.btn-default').click + find('.gl-dropdown-toggle').click + end - page.within('.dropdown-content') do - shas = merge_request.merge_request_diffs.map { |diff| Commit.truncate_sha(diff.head_commit_sha) } - shas.each { |sha| expect(page).to have_content(sha) } - end + page.within '.mr-version-dropdown' do + shas = merge_request.merge_request_diffs.map { |diff| Commit.truncate_sha(diff.head_commit_sha) } + shas.each { |sha| expect(page).to have_content(sha) } end end @@ -182,7 +184,7 @@ RSpec.describe 'Merge request > User sees versions', :js do it 'has 0 chages between versions' do page.within '.mr-version-compare-dropdown' do - expect(find('.dropdown-menu-toggle')).to have_content 'version 1' + expect(find('.gl-dropdown-toggle')).to have_content 'version 1' end page.within '.mr-version-dropdown' do @@ -203,7 +205,7 @@ RSpec.describe 'Merge request > User sees versions', :js do it 'sets the compared versions to be the same' do page.within '.mr-version-compare-dropdown' do - expect(find('.dropdown-menu-toggle')).to have_content 'version 2' + expect(find('.gl-dropdown-toggle')).to have_content 'version 2' end page.within '.mr-version-dropdown' do diff --git a/spec/features/merge_requests/user_squashes_merge_request_spec.rb b/spec/features/merge_request/user_squashes_merge_request_spec.rb index 84964bd0637..84964bd0637 100644 --- a/spec/features/merge_requests/user_squashes_merge_request_spec.rb +++ b/spec/features/merge_request/user_squashes_merge_request_spec.rb diff --git a/spec/features/merge_requests/user_views_diffs_commit_spec.rb b/spec/features/merge_request/user_views_diffs_commit_spec.rb index cf92603972e..cf92603972e 100644 --- a/spec/features/merge_requests/user_views_diffs_commit_spec.rb +++ b/spec/features/merge_request/user_views_diffs_commit_spec.rb diff --git a/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb b/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb index bb4bf0864c9..ad9c342df3e 100644 --- a/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb +++ b/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb @@ -23,12 +23,12 @@ RSpec.describe 'User views diffs file-by-file', :js do it 'shows diffs file-by-file' do page.within('#diffs') do expect(page).to have_selector('.file-holder', count: 1) - expect(page).to have_selector('.diff-file .file-title', text: '.DS_Store') + expect(page).to have_selector('.diff-file .file-title', text: 'files/ruby/popen.rb') find('.page-link.next-page-item').click expect(page).to have_selector('.file-holder', count: 1) - expect(page).to have_selector('.diff-file .file-title', text: '.gitignore') + expect(page).to have_selector('.diff-file .file-title', text: 'files/ruby/regex.rb') end end end diff --git a/spec/features/merge_request/user_views_diffs_spec.rb b/spec/features/merge_request/user_views_diffs_spec.rb index e1865fe2e14..a0b3067994c 100644 --- a/spec/features/merge_request/user_views_diffs_spec.rb +++ b/spec/features/merge_request/user_views_diffs_spec.rb @@ -22,8 +22,8 @@ RSpec.describe 'User views diffs', :js do it 'unfolds diffs upwards' do first('.js-unfold').click - page.within('.file-holder[id="a5cc2925ca8258af241be7e5b0381edf30266302"]') do - expect(find('.text-file')).to have_content('.bundle') + page.within('.file-holder[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd"]') do + expect(find('.text-file')).to have_content('fileutils') expect(page).to have_selector('.new_line [data-linenumber="1"]', count: 1) end end diff --git a/spec/features/merge_request/user_sees_empty_state_spec.rb b/spec/features/merge_requests/user_sees_empty_state_spec.rb index ac07b31731d..ac07b31731d 100644 --- a/spec/features/merge_request/user_sees_empty_state_spec.rb +++ b/spec/features/merge_requests/user_sees_empty_state_spec.rb diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index dce76e4df6d..b9594293996 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -101,7 +101,7 @@ RSpec.describe 'Milestone' do end describe 'Deleting a milestone' do - it "The delete milestone button does not show for unauthorized users" do + it "the delete milestone button does not show for unauthorized users" do create(:milestone, project: project, title: 8.7) sign_out(user) diff --git a/spec/features/operations_sidebar_link_spec.rb b/spec/features/operations_sidebar_link_spec.rb index 32e2833dafb..798f9092db0 100644 --- a/spec/features/operations_sidebar_link_spec.rb +++ b/spec/features/operations_sidebar_link_spec.rb @@ -2,31 +2,88 @@ require 'spec_helper' -RSpec.describe 'Operations dropdown sidebar' do - let_it_be(:project) { create(:project, :repository) } +RSpec.describe 'Operations dropdown sidebar', :aggregate_failures do + let_it_be_with_reload(:project) { create(:project, :internal, :repository) } let(:user) { create(:user) } + let(:access_level) { ProjectFeature::PUBLIC } + let(:role) { nil } before do - project.add_role(user, role) + project.add_role(user, role) if role + project.project_feature.update_attribute(:operations_access_level, access_level) + sign_in(user) visit project_issues_path(project) end + shared_examples 'shows Operations menu based on the access level' do + context 'when operations project feature is PRIVATE' do + let(:access_level) { ProjectFeature::PRIVATE } + + it 'shows the `Operations` menu' do + expect(page).to have_selector('a.shortcuts-operations', text: 'Operations') + end + end + + context 'when operations project feature is DISABLED' do + let(:access_level) { ProjectFeature::DISABLED } + + it 'does not show the `Operations` menu' do + expect(page).not_to have_selector('a.shortcuts-operations') + end + end + end + + context 'user is not a member' do + it 'has the correct `Operations` menu items', :aggregate_failures do + expect(page).to have_selector('a.shortcuts-operations', text: 'Operations') + expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project)) + expect(page).to have_link(title: 'Environments', href: project_environments_path(project)) + + expect(page).not_to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project)) + expect(page).not_to have_link(title: 'Alerts', href: project_alert_management_index_path(project)) + expect(page).not_to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project)) + expect(page).not_to have_link(title: 'Product Analytics', href: project_product_analytics_path(project)) + expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project)) + expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project)) + expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project)) + end + + context 'when operations project feature is PRIVATE' do + let(:access_level) { ProjectFeature::PRIVATE } + + it 'does not show the `Operations` menu' do + expect(page).not_to have_selector('a.shortcuts-operations') + end + end + + context 'when operations project feature is DISABLED' do + let(:access_level) { ProjectFeature::DISABLED } + + it 'does not show the `Operations` menu' do + expect(page).not_to have_selector('a.shortcuts-operations') + end + end + end + context 'user has guest role' do let(:role) { :guest } it 'has the correct `Operations` menu items' do + expect(page).to have_selector('a.shortcuts-operations', text: 'Operations') expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project)) + expect(page).to have_link(title: 'Environments', href: project_environments_path(project)) expect(page).not_to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project)) expect(page).not_to have_link(title: 'Alerts', href: project_alert_management_index_path(project)) - expect(page).not_to have_link(title: 'Environments', href: project_environments_path(project)) expect(page).not_to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project)) expect(page).not_to have_link(title: 'Product Analytics', href: project_product_analytics_path(project)) expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project)) expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project)) expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project)) end + + it_behaves_like 'shows Operations menu based on the access level' end context 'user has reporter role' do @@ -44,6 +101,8 @@ RSpec.describe 'Operations dropdown sidebar' do expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project)) expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project)) end + + it_behaves_like 'shows Operations menu based on the access level' end context 'user has developer role' do @@ -61,6 +120,8 @@ RSpec.describe 'Operations dropdown sidebar' do expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project)) expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project)) end + + it_behaves_like 'shows Operations menu based on the access level' end context 'user has maintainer role' do @@ -77,5 +138,7 @@ RSpec.describe 'Operations dropdown sidebar' do expect(page).to have_link(title: 'Logs', href: project_logs_path(project)) expect(page).to have_link(title: 'Kubernetes', href: project_clusters_path(project)) end + + it_behaves_like 'shows Operations menu based on the access level' end end diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index 62d8a96c1b2..2e8d9ef80cd 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -78,14 +78,14 @@ RSpec.describe 'Profile > Account', :js do update_username(new_username) visit new_project_path expect(current_path).to eq(new_project_path) - expect(find('.breadcrumbs-sub-title')).to have_content('Details') + expect(find('.breadcrumbs')).to have_content(user.name) end it 'the old project path redirects to the new path' do update_username(new_username) visit old_project_path expect(current_path).to eq(new_project_path) - expect(find('.breadcrumbs-sub-title')).to have_content('Details') + expect(find('.breadcrumbs')).to have_content(user.name) end end end diff --git a/spec/features/profiles/active_sessions_spec.rb b/spec/features/profiles/active_sessions_spec.rb index 75531d43df2..fd64704b7c8 100644 --- a/spec/features/profiles/active_sessions_spec.rb +++ b/spec/features/profiles/active_sessions_spec.rb @@ -11,8 +11,8 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do let(:admin) { create(:admin) } - it 'User sees their active sessions' do - Timecop.freeze(Time.zone.parse('2018-03-12 09:06')) do + it 'user sees their active sessions' do + travel_to(Time.zone.parse('2018-03-12 09:06')) do Capybara::Session.new(:session1) Capybara::Session.new(:session2) Capybara::Session.new(:session3) @@ -45,6 +45,7 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do ) gitlab_sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) visit admin_user_path(user) @@ -55,8 +56,8 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do visit profile_active_sessions_path expect(page).to( - have_selector('ul.list-group li.list-group-item', { text: 'Signed in on', - count: 2 })) + have_selector('ul.list-group li.list-group-item', text: 'Signed in on', + count: 2)) expect(page).to have_content( '127.0.0.1 ' \ @@ -81,7 +82,7 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do end end - it 'User can revoke a session', :js do + it 'user can revoke a session', :js do Capybara::Session.new(:session1) Capybara::Session.new(:session2) diff --git a/spec/features/profiles/emails_spec.rb b/spec/features/profiles/emails_spec.rb index fc7de6d8b23..bdf1f8b022a 100644 --- a/spec/features/profiles/emails_spec.rb +++ b/spec/features/profiles/emails_spec.rb @@ -42,7 +42,7 @@ RSpec.describe 'Profile > Emails' do end end - it 'User removes email' do + it 'user removes email' do user.emails.create(email: 'my@email.com') visit profile_emails_path expect(page).to have_content("my@email.com") @@ -51,7 +51,7 @@ RSpec.describe 'Profile > Emails' do expect(page).not_to have_content("my@email.com") end - it 'User confirms email' do + it 'user confirms email' do email = user.emails.create(email: 'my@email.com') visit profile_emails_path expect(page).to have_content("#{email.email} Unverified") @@ -63,7 +63,7 @@ RSpec.describe 'Profile > Emails' do expect(page).to have_content("#{email.email} Verified") end - it 'User re-sends confirmation email' do + it 'user re-sends confirmation email' do email = user.emails.create(email: 'my@email.com') visit profile_emails_path diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb index 18ed4e646b3..4eedeeac262 100644 --- a/spec/features/profiles/gpg_keys_spec.rb +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -36,7 +36,7 @@ RSpec.describe 'Profile > GPG Keys' do end end - it 'User sees their key' do + it 'user sees their key' do create(:gpg_key, user: user, key: GpgHelpers::User2.public_key) visit profile_gpg_keys_path @@ -45,7 +45,7 @@ RSpec.describe 'Profile > GPG Keys' do expect(page).to have_content(GpgHelpers::User2.fingerprint) end - it 'User removes a key via the key index' do + it 'user removes a key via the key index' do create(:gpg_key, user: user, key: GpgHelpers::User2.public_key) visit profile_gpg_keys_path @@ -54,7 +54,7 @@ RSpec.describe 'Profile > GPG Keys' do expect(page).to have_content('Your GPG keys (0)') end - it 'User revokes a key via the key index' do + it 'user revokes a key via the key index' do gpg_key = create :gpg_key, user: user, key: GpgHelpers::User2.public_key gpg_signature = create :gpg_signature, gpg_key: gpg_key, verification_status: :verified diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb index 23bbe9c1587..c1e2d19ad9a 100644 --- a/spec/features/profiles/keys_spec.rb +++ b/spec/features/profiles/keys_spec.rb @@ -64,7 +64,7 @@ RSpec.describe 'Profile > SSH Keys' do end end - it 'User sees their keys' do + it 'user sees their keys' do key = create(:key, user: user) visit profile_keys_path diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index de5a594aca6..88bfc71cfbe 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -18,6 +18,10 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do find("#created-personal-access-token").value end + def feed_token + find("#feed_token").value + end + def disallow_personal_access_token_saves! allow(PersonalAccessTokens::CreateService).to receive(:new).and_return(pat_create_service) @@ -112,4 +116,26 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do end end end + + describe "feed token" do + context "when enabled" do + it "displays feed token" do + allow(Gitlab::CurrentSettings).to receive(:disable_feed_token).and_return(false) + visit profile_personal_access_tokens_path + + expect(page).to have_content("Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar, and is included in those feed URLs.") + expect(feed_token).to eq(user.feed_token) + end + end + + context "when disabled" do + it "does not display feed token" do + allow(Gitlab::CurrentSettings).to receive(:disable_feed_token).and_return(true) + visit profile_personal_access_tokens_path + + expect(page).not_to have_content("Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar, and is included in those feed URLs.") + expect(page).not_to have_css("#feed_token") + end + end + end end diff --git a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb index a5b7b1fba9d..1b6215c1308 100644 --- a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb +++ b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb @@ -9,7 +9,7 @@ RSpec.describe 'Profile > Notifications > User changes notified_of_own_activity sign_in(user) end - it 'User opts into receiving notifications about their own activity' do + it 'user opts into receiving notifications about their own activity' do visit profile_notifications_path expect(page).not_to have_checked_field('user[notified_of_own_activity]') @@ -20,7 +20,7 @@ RSpec.describe 'Profile > Notifications > User changes notified_of_own_activity expect(page).to have_checked_field('user[notified_of_own_activity]') end - it 'User opts out of receiving notifications about their own activity' do + it 'user opts out of receiving notifications about their own activity' do user.update!(notified_of_own_activity: true) visit profile_notifications_path diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb index d0340dfc880..239bc04a9cb 100644 --- a/spec/features/profiles/user_edit_profile_spec.rb +++ b/spec/features/profiles/user_edit_profile_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'User edit profile' do + include Spec::Support::Helpers::Features::NotesHelpers + let(:user) { create(:user) } before do @@ -226,7 +228,7 @@ RSpec.describe 'User edit profile' do end def open_edit_status_modal - open_modal 'Edit status' + open_modal 'Edit status' end def set_user_status_in_modal @@ -289,6 +291,10 @@ RSpec.describe 'User edit profile' do toggle_busy_status set_user_status_in_modal + + wait_for_requests + visit root_path(user) + open_edit_status_modal expect(busy_status.checked?).to eq(true) @@ -366,26 +372,37 @@ RSpec.describe 'User edit profile' do expect(page).not_to have_selector '.cover-status' end - it 'clears the user status with the "Remove status" button' do - user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread') + context 'Remove status button' do + before do + user.status = UserStatus.new(message: 'Eating bread', emoji: 'stuffed_flatbread') - visit_user - wait_for_requests + visit_user + wait_for_requests - within('.cover-status') do - expect(page).to have_emoji(user_status.emoji) - expect(page).to have_content user_status.message + open_edit_status_modal + + page.within "#set-user-status-modal" do + click_button 'Remove status' + end + + wait_for_requests end - open_edit_status_modal + it 'clears the user status with the "Remove status" button' do + visit_user - page.within "#set-user-status-modal" do - click_button 'Remove status' + expect(page).not_to have_selector '.cover-status' end - visit_user + it 'shows the "Set status" menu item in the user menu' do + visit root_path(user) - expect(page).not_to have_selector '.cover-status' + find('.header-user-dropdown-toggle').click + + page.within ".header-user" do + expect(page).to have_content('Set status') + end + end end it 'displays a default emoji if only message is entered' do @@ -398,6 +415,45 @@ RSpec.describe 'User edit profile' do end end + context 'note header' do + let(:project) { create(:project_empty_repo, :public) } + let(:issue) { create(:issue, project: project) } + let(:emoji) { "stuffed_flatbread" } + + before do + project.add_guest(user) + create(:user_status, user: user, message: 'Taking notes', emoji: emoji) + + visit(project_issue_path(project, issue)) + + add_note("This is a comment") + visit(project_issue_path(project, issue)) + + wait_for_requests + end + + it 'displays the status emoji' do + first_note = page.find_all(".main-notes-list .timeline-entry").first + + expect(first_note).to have_emoji(emoji) + end + + it 'clears the status emoji' do + open_edit_status_modal + + page.within "#set-user-status-modal" do + click_button 'Remove status' + end + + visit(project_issue_path(project, issue)) + wait_for_requests + + first_note = page.find_all(".main-notes-list .timeline-entry").first + + expect(first_note).not_to have_css('.user-status-emoji') + end + end + context 'with set_user_availability_status feature flag disabled' do before do stub_feature_flags(set_user_availability_status: false) diff --git a/spec/features/projects/active_tabs_spec.rb b/spec/features/projects/active_tabs_spec.rb index 349e5f5e177..8001ce0f454 100644 --- a/spec/features/projects/active_tabs_spec.rb +++ b/spec/features/projects/active_tabs_spec.rb @@ -124,15 +124,15 @@ RSpec.describe 'Project active tab' do context 'on project Analytics' do before do - visit charts_project_graph_path(project, 'master') + visit project_cycle_analytics_path(project) end - context 'on project Analytics/Repository Analytics' do + context 'on project Analytics/Value Stream Analytics' do it_behaves_like 'page has active tab', _('Analytics') - it_behaves_like 'page has active sub tab', _('Repository') + it_behaves_like 'page has active sub tab', _('Value Stream') end - context 'on project Analytics/Cycle Analytics' do + context 'on project Analytics/"CI / CD"' do before do click_tab(_('CI / CD')) end diff --git a/spec/features/projects/blobs/balsamiq_spec.rb b/spec/features/projects/blobs/balsamiq_spec.rb new file mode 100644 index 00000000000..bce60856544 --- /dev/null +++ b/spec/features/projects/blobs/balsamiq_spec.rb @@ -0,0 +1,17 @@ +# 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/user_creates_new_blob_in_new_project_spec.rb b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb index 6b9fd41059d..484f740faee 100644 --- a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb +++ b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb @@ -9,12 +9,9 @@ RSpec.describe 'User creates new blob', :js do let(:project) { create(:project, :empty_repo) } shared_examples 'creating a file' do - before do - sign_in(user) + it 'allows the user to add a new file in Web IDE' do visit project_path(project) - end - it 'allows the user to add a new file in Web IDE' do click_link 'New file' wait_for_requests @@ -31,6 +28,7 @@ RSpec.describe 'User creates new blob', :js do describe 'as a maintainer' do before do project.add_maintainer(user) + sign_in(user) end it_behaves_like 'creating a file' @@ -39,6 +37,11 @@ RSpec.describe 'User creates new blob', :js do describe 'as an admin' do let(:user) { create(:user, :admin) } + before do + sign_in(user) + gitlab_enable_admin_mode_sign_in(user) + end + it_behaves_like 'creating a file' end diff --git a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb index 3069405ba63..1c79b2ddc38 100644 --- a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb +++ b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb @@ -5,8 +5,8 @@ require 'spec_helper' RSpec.describe 'User follows pipeline suggest nudge spec when feature is enabled', :js do include CookieHelper - let(:user) { create(:user, :admin) } let(:project) { create(:project, :empty_repo) } + let(:user) { project.owner } describe 'viewing the new blob page' do before do diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index a0519d88532..d34dde6a8f2 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do +RSpec.describe 'Gcp Cluster', :js do include GoogleApi::CloudPlatformHelpers let(:project) { create(:project) } diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index 6c6e65005f6..6da66989b09 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -110,7 +110,7 @@ RSpec.describe 'Clusters', :js do visit project_clusters_path(project) end - it 'user sees a add cluster button ' do + it 'user sees a add cluster button' do expect(page).to have_selector('.js-add-cluster:not(.readonly)') end diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb index 45bf35a6aab..ee453aa7bbf 100644 --- a/spec/features/projects/container_registry_spec.rb +++ b/spec/features/projects/container_registry_spec.rb @@ -94,7 +94,8 @@ RSpec.describe 'Container Registry', :js do end it('pagination navigate to the second page') do - visit_second_page + visit_next_page + expect(page).to have_content '20' end end @@ -116,22 +117,23 @@ RSpec.describe 'Container Registry', :js do context 'when there are more than 10 images' do before do - create_list(:container_repository, 12, project: project) project.container_repositories << container_repository + create_list(:container_repository, 12, project: project) + visit_container_registry end it 'shows pagination' do - expect(page).to have_css '.gl-pagination' + expect(page).to have_css '.gl-keyset-pagination' end it 'pagination goes to second page' do - visit_second_page + visit_next_page expect(page).to have_content 'my/image' end it 'pagination is preserved after navigating back from details' do - visit_second_page + visit_next_page click_link 'my/image' breadcrumb = find '.breadcrumbs' breadcrumb.click_link 'Container Registry' @@ -148,8 +150,8 @@ RSpec.describe 'Container Registry', :js do click_link name end - def visit_second_page - pagination = find '.gl-pagination' - pagination.click_link '2' + def visit_next_page + pagination = find '.gl-keyset-pagination' + pagination.click_button 'Next' end end diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb index 19f111a727b..747277e2562 100644 --- a/spec/features/projects/diffs/diff_show_spec.rb +++ b/spec/features/projects/diffs/diff_show_spec.rb @@ -155,10 +155,6 @@ RSpec.describe 'Diff file viewer', :js do context 'binary file that appears to be text in the first 1024 bytes' do before do - # The file we're visiting is smaller than 10 KB and we want it collapsed - # so we need to disable the size increase feature. - stub_feature_flags(gitlab_git_diff_size_limit_increase: false) - visit_commit('7b1cf4336b528e0f3d1d140ee50cafdbc703597c') end diff --git a/spec/features/projects/environments/environment_metrics_spec.rb b/spec/features/projects/environments/environment_metrics_spec.rb index 8315c821b6d..e8f197b67c2 100644 --- a/spec/features/projects/environments/environment_metrics_spec.rb +++ b/spec/features/projects/environments/environment_metrics_spec.rb @@ -22,7 +22,7 @@ RSpec.describe 'Environment > Metrics' do end around do |example| - Timecop.freeze(current_time) { example.run } + travel_to(current_time) { example.run } end shared_examples 'has environment selector' do diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 8c032660726..27167f95104 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -12,8 +12,20 @@ RSpec.describe 'Environments page', :js do sign_in(user) end + def actions_button_selector + '[data-testid="environment-actions-button"]' + end + + def action_link_selector + '[data-testid="manual-action-link"]' + end + def stop_button_selector - %q{button[title="Stop environment"]} + 'button[title="Stop environment"]' + end + + def upcoming_deployment_content_selector + '[data-testid="upcoming-deployment-content"]' end describe 'page tabs' do @@ -187,18 +199,17 @@ RSpec.describe 'Environments page', :js do end it 'shows a play button' do - find('.js-environment-actions-dropdown').click - + find(actions_button_selector).click expect(page).to have_content(action.name) end it 'allows to play a manual action', :js do expect(action).to be_manual - find('.js-environment-actions-dropdown').click + find(actions_button_selector).click expect(page).to have_content(action.name) - expect { find('.js-manual-action-link').click } + expect { find(action_link_selector).click } .not_to change { Ci::Pipeline.count } end @@ -301,11 +312,11 @@ RSpec.describe 'Environments page', :js do end it 'has a dropdown for actionable jobs' do - expect(page).to have_selector('.dropdown-new.btn.btn-default [data-testid="play-icon"]') + expect(page).to have_selector("#{actions_button_selector} [data-testid=\"play-icon\"]") end it "has link to the delayed job's action" do - find('.js-environment-actions-dropdown').click + find(actions_button_selector).click expect(page).to have_button('delayed job') expect(page).to have_content(/\d{2}:\d{2}:\d{2}/) @@ -320,7 +331,7 @@ RSpec.describe 'Environments page', :js do end it "shows 00:00:00 as the remaining time" do - find('.js-environment-actions-dropdown').click + find(actions_button_selector).click expect(page).to have_content("00:00:00") end @@ -328,8 +339,8 @@ RSpec.describe 'Environments page', :js do context 'when user played a delayed job immediately' do before do - find('.js-environment-actions-dropdown').click - page.accept_confirm { click_button('delayed job') } + find(actions_button_selector).click + accept_confirm { find(action_link_selector).click } wait_for_requests end @@ -355,6 +366,26 @@ RSpec.describe 'Environments page', :js do expect(page).to have_content('No deployments yet') end end + + context 'when there is an upcoming deployment' do + let_it_be(:project) { create(:project, :repository) } + + let!(:deployment) do + create(:deployment, :running, + environment: environment, + sha: project.commit.id) + end + + it "renders the upcoming deployment", :aggregate_failures do + visit_environments(project) + + within(upcoming_deployment_content_selector) do + expect(page).to have_content("##{deployment.iid}") + expect(page).to have_selector("a[href=\"#{project_job_path(project, deployment.deployable)}\"]") + expect(page).to have_link(href: /#{deployment.user.username}/) + end + end + end end it 'does have a new environment button' do @@ -423,10 +454,10 @@ RSpec.describe 'Environments page', :js do expect(page).to have_content 'review-1' expect(page).to have_content 'review-2' within('.ci-table') do - within('.gl-responsive-table-row:nth-child(3)') do + within('[data-qa-selector="environment_item"]', text: 'review-1') do expect(find('.js-auto-stop').text).not_to be_empty end - within('.gl-responsive-table-row:nth-child(4)') do + within('[data-qa-selector="environment_item"]', text: 'review-2') do expect(find('.js-auto-stop').text).not_to be_empty end end diff --git a/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb index 830dda737b0..eaafc7e607b 100644 --- a/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb +++ b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb @@ -67,118 +67,6 @@ RSpec.describe 'User creates feature flag', :js do end end - context 'with new version flags disabled' do - before do - stub_feature_flags(feature_flags_new_version: false) - end - - context 'when creates without changing scopes' do - before do - visit(new_project_feature_flag_path(project)) - set_feature_flag_info('ci_live_trace', 'For live trace') - click_button 'Create feature flag' - expect(page).to have_current_path(project_feature_flags_path(project)) - end - - it 'shows the created feature flag' do - within_feature_flag_row(1) do - expect(page.find('.feature-flag-name')).to have_content('ci_live_trace') - expect_status_toggle_button_to_be_checked - - within_feature_flag_scopes do - expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*') - end - end - end - end - - context 'when creates with disabling the default scope' do - before do - visit(new_project_feature_flag_path(project)) - set_feature_flag_info('ci_live_trace', 'For live trace') - - within_scope_row(1) do - within_status { find('.project-feature-toggle').click } - end - - click_button 'Create feature flag' - end - - it 'shows the created feature flag' do - within_feature_flag_row(1) do - expect(page.find('.feature-flag-name')).to have_content('ci_live_trace') - expect_status_toggle_button_to_be_checked - - within_feature_flag_scopes do - expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(1)')).to have_content('*') - end - end - end - end - - context 'when creates with an additional scope' do - before do - visit(new_project_feature_flag_path(project)) - set_feature_flag_info('mr_train', '') - - within_scope_row(2) do - within_environment_spec do - find('.js-env-search > input').set("review/*") - find('.js-create-button').click - end - end - - within_scope_row(2) do - within_status { find('.project-feature-toggle').click } - end - - click_button 'Create feature flag' - end - - it 'shows the created feature flag' do - within_feature_flag_row(1) do - expect(page.find('.feature-flag-name')).to have_content('mr_train') - expect_status_toggle_button_to_be_checked - - within_feature_flag_scopes do - expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*') - expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(2)')).to have_content('review/*') - end - end - end - end - - context 'when searches an environment name for scope creation' do - let!(:environment) { create(:environment, name: 'production', project: project) } - - before do - visit(new_project_feature_flag_path(project)) - set_feature_flag_info('mr_train', '') - - within_scope_row(2) do - within_environment_spec do - find('.js-env-search > input').set('prod') - click_button 'production' - end - end - - click_button 'Create feature flag' - end - - it 'shows the created feature flag' do - within_feature_flag_row(1) do - expect(page.find('.feature-flag-name')).to have_content('mr_train') - expect_status_toggle_button_to_be_checked - - within_feature_flag_scopes do - expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*') - expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(2)')).to have_content('production') - end - end - end - end - end - private def set_feature_flag_info(name, description) diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 467adb25a17..2f0fbd29cb5 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -14,7 +14,7 @@ RSpec.describe 'Edit Project Settings' do sign_in(member) end - tools = { builds: "pipelines", issues: "issues", wiki: "wiki", snippets: "snippets", merge_requests: "merge_requests" } + tools = { builds: "pipelines", issues: "issues", wiki: "wiki", snippets: "snippets", merge_requests: "merge_requests", analytics: "analytics" } tools.each do |tool_name, shortcut_name| describe "feature #{tool_name}" do @@ -150,6 +150,7 @@ RSpec.describe 'Edit Project Settings' do before do non_member.update_attribute(:admin, true) sign_in(non_member) + gitlab_enable_admin_mode_sign_in(non_member) end it 'renders 404 if feature is disabled' do diff --git a/spec/features/projects/gfm_autocomplete_load_spec.rb b/spec/features/projects/gfm_autocomplete_load_spec.rb index b02483be489..f4cd65bcba1 100644 --- a/spec/features/projects/gfm_autocomplete_load_spec.rb +++ b/spec/features/projects/gfm_autocomplete_load_spec.rb @@ -6,7 +6,7 @@ RSpec.describe 'GFM autocomplete loading', :js do let(:project) { create(:project) } before do - sign_in(create(:admin)) + sign_in(project.owner) visit project_path(project) end diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index 83ceffa621c..af228764c17 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -28,73 +28,40 @@ RSpec.describe 'Import/Export - project import integration test', :js do let(:project_name) { 'Test Project Name' + randomHex } let(:project_path) { 'test-project-name' + randomHex } - context 'prefilled the path' do - it 'user imports an exported project successfully', :sidekiq_might_not_need_inline do - visit new_project_path + it 'user imports an exported project successfully', :sidekiq_might_not_need_inline do + visit new_project_path + click_import_project_tab + click_link 'GitLab export' - fill_in :project_name, with: project_name, visible: true - click_import_project_tab - click_link 'GitLab export' + fill_in :name, with: 'Test Project Name', visible: true + fill_in :path, with: 'test-project-path', visible: true + attach_file('file', file) - expect(page).to have_content('Import an exported GitLab project') - expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&name=#{ERB::Util.url_encode(project_name)}&path=#{project_path}") + expect { click_on 'Import project' }.to change { Project.count }.by(1) - attach_file('file', file) - click_on 'Import project' - - expect(Project.count).to eq(1) - - project = Project.last - expect(project).not_to be_nil - expect(project.description).to eq("Foo Bar") - expect(project.issues).not_to be_empty - expect(project.merge_requests).not_to be_empty - expect(wiki_exists?(project)).to be true - expect(project.import_state.status).to eq('finished') - end + project = Project.last + expect(project).not_to be_nil + expect(page).to have_content("Project 'test-project-path' is being imported") end - context 'path is not prefilled' do - it 'user imports an exported project successfully', :sidekiq_might_not_need_inline do - visit new_project_path - click_import_project_tab - click_link 'GitLab export' + it 'invalid project' do + project = create(:project, namespace: user.namespace) - fill_in :name, with: 'Test Project Name', visible: true - fill_in :path, with: 'test-project-path', visible: true - attach_file('file', file) + visit new_project_path - expect { click_on 'Import project' }.to change { Project.count }.by(1) + click_import_project_tab + click_link 'GitLab export' + fill_in :name, with: project.name, visible: true + attach_file('file', file) + click_on 'Import project' - project = Project.last - expect(project).not_to be_nil - expect(page).to have_content("Project 'test-project-path' is being imported") + page.within('.flash-container') do + expect(page).to have_content('Project could not be imported') end end end - it 'invalid project' do - project = create(:project, namespace: user.namespace) - - visit new_project_path - - fill_in :project_name, with: project.name, visible: true - click_import_project_tab - click_link 'GitLab export' - attach_file('file', file) - click_on 'Import project' - - page.within('.flash-container') do - expect(page).to have_content('Project could not be imported') - end - end - - def wiki_exists?(project) - wiki = ProjectWiki.new(project) - wiki.repository.exists? && !wiki.repository.empty? - end - def click_import_project_tab - find('#import-project-tab').click + find('[data-qa-selector="import_project_link"]').click end end diff --git a/spec/features/projects/jobs/permissions_spec.rb b/spec/features/projects/jobs/permissions_spec.rb index 7f46a369dd6..b1e8127c54c 100644 --- a/spec/features/projects/jobs/permissions_spec.rb +++ b/spec/features/projects/jobs/permissions_spec.rb @@ -3,11 +3,13 @@ require 'spec_helper' RSpec.describe 'Project Jobs Permissions' do - let(:user) { create(:user) } - let(:group) { create(:group, name: 'some group') } - let(:project) { create(:project, :repository, namespace: group) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } - let!(:job) { create(:ci_build, :running, :coverage, :trace_artifact, pipeline: pipeline) } + using RSpec::Parameterized::TableSyntax + + let_it_be_with_reload(:group) { create(:group, name: 'some group') } + let_it_be_with_reload(:project) { create(:project, :repository, namespace: group) } + let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } + let_it_be(:user) { create(:user) } + let_it_be(:job) { create(:ci_build, :running, :coverage, :trace_artifact, pipeline: pipeline) } before do sign_in(user) @@ -34,7 +36,7 @@ RSpec.describe 'Project Jobs Permissions' do context 'when public access for jobs is disabled' do before do - project.update(public_builds: false) + project.update!(public_builds: false) end context 'when user is a guest' do @@ -48,7 +50,7 @@ RSpec.describe 'Project Jobs Permissions' do context 'when project is internal' do before do - project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) end it_behaves_like 'recent job page details responds with status', 404 @@ -58,12 +60,30 @@ RSpec.describe 'Project Jobs Permissions' do context 'when public access for jobs is enabled' do before do - project.update(public_builds: true) + project.update!(public_builds: true) + end + + context 'when user is a guest' do + before do + project.add_guest(user) + end + + it_behaves_like 'recent job page details responds with status', 200 + it_behaves_like 'project jobs page responds with status', 200 + end + + context 'when user is a developer' do + before do + project.add_developer(user) + end + + it_behaves_like 'recent job page details responds with status', 200 + it_behaves_like 'project jobs page responds with status', 200 end context 'when project is internal' do before do - project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) end it_behaves_like 'recent job page details responds with status', 200 do @@ -89,7 +109,7 @@ RSpec.describe 'Project Jobs Permissions' do describe 'artifacts page' do context 'when recent job has artifacts available' do - before do + before_all do archive = fixture_file_upload('spec/fixtures/ci_build_artifacts.zip') create(:ci_job_artifact, :archive, file: archive, job: job) @@ -97,7 +117,7 @@ RSpec.describe 'Project Jobs Permissions' do context 'when public access for jobs is disabled' do before do - project.update(public_builds: false) + project.update!(public_builds: false) end context 'when user with guest role' do @@ -128,4 +148,124 @@ RSpec.describe 'Project Jobs Permissions' do end end end + + context 'with CI_DEBUG_TRACE' do + let_it_be(:ci_instance_variable) { create(:ci_instance_variable, key: 'CI_DEBUG_TRACE') } + + describe 'trace endpoint' do + let_it_be(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) } + + where(:public_builds, :user_project_role, :ci_debug_trace, :expected_status_code) do + true | 'developer' | true | 200 + true | 'guest' | true | 403 + true | 'developer' | false | 200 + true | 'guest' | false | 200 + false | 'developer' | true | 200 + false | 'guest' | true | 403 + false | 'developer' | false | 200 + false | 'guest' | false | 403 + end + + with_them do + before do + ci_instance_variable.update!(value: ci_debug_trace) + project.update!(public_builds: public_builds) + project.add_role(user, user_project_role) + end + + it 'renders trace to authorized users' do + visit trace_project_job_path(project, job) + + expect(status_code).to eq(expected_status_code) + end + end + + context 'when restrict_access_to_build_debug_mode feature not enabled' do + where(:public_builds, :user_project_role, :ci_debug_trace, :expected_status_code) do + true | 'developer' | true | 200 + true | 'guest' | true | 200 + true | 'developer' | false | 200 + true | 'guest' | false | 200 + false | 'developer' | true | 200 + false | 'guest' | true | 403 + false | 'developer' | false | 200 + false | 'guest' | false | 403 + end + + with_them do + before do + stub_feature_flags(restrict_access_to_build_debug_mode: false) + ci_instance_variable.update!(value: ci_debug_trace) + project.update!(public_builds: public_builds) + project.add_role(user, user_project_role) + end + + it 'renders trace to authorized users' do + visit trace_project_job_path(project, job) + + expect(status_code).to eq(expected_status_code) + end + end + end + end + + describe 'raw page' do + let_it_be(:job) { create(:ci_build, :running, :coverage, :trace_artifact, pipeline: pipeline) } + + where(:public_builds, :user_project_role, :ci_debug_trace, :expected_status_code, :expected_msg) do + true | 'developer' | true | 200 | nil + true | 'guest' | true | 403 | 'You must have developer or higher permissions' + true | 'developer' | false | 200 | nil + true | 'guest' | false | 200 | nil + false | 'developer' | true | 200 | nil + false | 'guest' | true | 403 | 'You must have developer or higher permissions' + false | 'developer' | false | 200 | nil + false | 'guest' | false | 403 | 'The current user is not authorized to access the job log' + end + + with_them do + before do + ci_instance_variable.update!(value: ci_debug_trace) + project.update!(public_builds: public_builds) + project.add_role(user, user_project_role) + end + + it 'renders raw trace to authorized users' do + visit raw_project_job_path(project, job) + + expect(status_code).to eq(expected_status_code) + expect(page).to have_content(expected_msg) + end + end + + context 'when restrict_access_to_build_debug_mode feature not enabled' do + where(:public_builds, :user_project_role, :ci_debug_trace, :expected_status_code, :expected_msg) do + true | 'developer' | true | 200 | nil + true | 'guest' | true | 200 | nil + true | 'developer' | false | 200 | nil + true | 'guest' | false | 200 | nil + false | 'developer' | true | 200 | nil + false | 'guest' | true | 403 | 'The current user is not authorized to access the job log' + false | 'developer' | false | 200 | nil + false | 'guest' | false | 403 | 'The current user is not authorized to access the job log' + end + + with_them do + before do + stub_feature_flags(restrict_access_to_build_debug_mode: false) + ci_instance_variable.update!(value: ci_debug_trace) + project.update!(public_builds: public_builds) + project.add_role(user, user_project_role) + end + + it 'renders raw trace to authorized users' do + visit raw_project_job_path(project, job) + + expect(status_code).to eq(expected_status_code) + expect(page).to have_content(expected_msg) + end + end + end + end + end end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index e19337e1ff5..4edda9febbe 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -25,72 +25,113 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do end describe "GET /:project/jobs" do - let!(:job) { create(:ci_build, pipeline: pipeline) } - - context "Pending scope" do + context 'with no jobs' do before do - visit project_jobs_path(project, scope: :pending) - end + stub_experiment(jobs_empty_state: experiment_active) + stub_experiment_for_subject(jobs_empty_state: in_experiment_group) - it "shows Pending tab jobs" do - expect(page).to have_selector('.nav-links li.active', text: 'Pending') - expect(page).to have_content job.short_sha - expect(page).to have_content job.ref - expect(page).to have_content job.name + visit project_jobs_path(project) end - end - context "Running scope" do - before do - job.run! - visit project_jobs_path(project, scope: :running) - end + context 'when experiment not active' do + let(:experiment_active) { false } + let(:in_experiment_group) { false } - it "shows Running tab jobs" do - expect(page).to have_selector('.nav-links li.active', text: 'Running') - expect(page).to have_content job.short_sha - expect(page).to have_content job.ref - expect(page).to have_content job.name + it 'shows the empty state control page' do + expect(page).to have_content('No jobs to show') + expect(page).to have_link('Get started with Pipelines') + end end - end - context "Finished scope" do - before do - job.run! - visit project_jobs_path(project, scope: :finished) + context 'when experiment active and user in control group' do + let(:experiment_active) { true } + let(:in_experiment_group) { false } + + it 'shows the empty state control page' do + expect(page).to have_content('No jobs to show') + expect(page).to have_link('Get started with Pipelines') + end end - it "shows Finished tab jobs" do - expect(page).to have_selector('.nav-links li.active', text: 'Finished') - expect(page).to have_content 'No jobs to show' + context 'when experiment active and user in experimental group' do + let(:experiment_active) { true } + let(:in_experiment_group) { true } + + it 'shows the empty state experiment page' do + expect(page).to have_content('Use jobs to automate your tasks') + expect(page).to have_link('Create CI/CD configuration file') + end end end - context "All jobs" do - before do - project.builds.running_or_pending.each(&:success) - visit project_jobs_path(project) + context 'with a job' do + let!(:job) { create(:ci_build, pipeline: pipeline) } + + context "Pending scope" do + before do + visit project_jobs_path(project, scope: :pending) + end + + it "shows Pending tab jobs" do + expect(page).to have_selector('.nav-links li.active', text: 'Pending') + expect(page).to have_content job.short_sha + expect(page).to have_content job.ref + expect(page).to have_content job.name + end end - it "shows All tab jobs" do - expect(page).to have_selector('.nav-links li.active', text: 'All') - expect(page).to have_content job.short_sha - expect(page).to have_content job.ref - expect(page).to have_content job.name + context "Running scope" do + before do + job.run! + visit project_jobs_path(project, scope: :running) + end + + it "shows Running tab jobs" do + expect(page).to have_selector('.nav-links li.active', text: 'Running') + expect(page).to have_content job.short_sha + expect(page).to have_content job.ref + expect(page).to have_content job.name + end end - end - context "when visiting old URL" do - let(:jobs_url) do - project_jobs_path(project) + context "Finished scope" do + before do + job.run! + visit project_jobs_path(project, scope: :finished) + end + + it "shows Finished tab jobs" do + expect(page).to have_selector('.nav-links li.active', text: 'Finished') + expect(page).to have_content 'No jobs to show' + end end - before do - visit jobs_url.sub('/-/jobs', '/builds') + context "All jobs" do + before do + project.builds.running_or_pending.each(&:success) + visit project_jobs_path(project) + end + + it "shows All tab jobs" do + expect(page).to have_selector('.nav-links li.active', text: 'All') + expect(page).to have_content job.short_sha + expect(page).to have_content job.ref + expect(page).to have_content job.name + end end - it "redirects to new URL" do - expect(page.current_path).to eq(jobs_url) + context "when visiting old URL" do + let(:jobs_url) do + project_jobs_path(project) + end + + before do + visit jobs_url.sub('/-/jobs', '/builds') + end + + it "redirects to new URL" do + expect(page.current_path).to eq(jobs_url) + end end end end diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb index 85a08c441ca..0a373b0d51a 100644 --- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb +++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Issue prioritization' do # According to https://gitlab.com/gitlab-org/gitlab-foss/issues/14189#note_4360653 context 'when issues have one label', :js do - it 'Are sorted properly' do + it 'are sorted properly' do # Issues issue_1 = create(:issue, title: 'issue_1', project: project) issue_2 = create(:issue, title: 'issue_2', project: project) @@ -45,7 +45,7 @@ RSpec.describe 'Issue prioritization' do end context 'when issues have multiple labels', :js do - it 'Are sorted properly' do + it 'are sorted properly' do # Issues issue_1 = create(:issue, title: 'issue_1', project: project) issue_2 = create(:issue, title: 'issue_2', project: project) diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index 6a2ec9aa4a8..4aabf040655 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'New project' do +RSpec.describe 'New project', :js do include Select2Helper context 'as a user' do @@ -18,6 +18,7 @@ RSpec.describe 'New project' do ) visit new_project_path + find('[data-qa-selector="blank_project_link"]').click expect(page).to have_content 'Other visibility settings have been disabled by the administrator.' end @@ -28,6 +29,7 @@ RSpec.describe 'New project' do ) visit new_project_path + find('[data-qa-selector="blank_project_link"]').click expect(page).to have_content 'Visibility settings have been disabled by the administrator.' end @@ -42,17 +44,18 @@ RSpec.describe 'New project' do it 'shows "New project" page', :js do visit new_project_path + find('[data-qa-selector="blank_project_link"]').click expect(page).to have_content('Project name') expect(page).to have_content('Project URL') expect(page).to have_content('Project slug') - find('#import-project-tab').click + click_link('New project') + find('[data-qa-selector="import_project_link"]').click expect(page).to have_link('GitHub') expect(page).to have_link('Bitbucket') expect(page).to have_link('GitLab.com') - expect(page).to have_link('Google Code') expect(page).to have_button('Repo by URL') expect(page).to have_link('GitLab export') end @@ -61,7 +64,7 @@ RSpec.describe 'New project' do before do visit new_project_path - find('#import-project-tab').click + find('[data-qa-selector="import_project_link"]').click end it { expect(page).to have_link('Manifest file') } @@ -73,6 +76,7 @@ RSpec.describe 'New project' do stub_application_setting(default_project_visibility: level) visit new_project_path + find('[data-qa-selector="blank_project_link"]').click page.within('#blank-project-pane') do expect(find_field("project_visibility_level_#{level}")).to be_checked end @@ -80,6 +84,7 @@ RSpec.describe 'New project' do it "saves visibility level #{level} on validation error" do visit new_project_path + find('[data-qa-selector="blank_project_link"]').click choose(s_(key)) click_button('Create project') @@ -97,6 +102,7 @@ RSpec.describe 'New project' do it 'has private selected' do group = create(:group, visibility_level: Gitlab::VisibilityLevel::PRIVATE) visit new_project_path(namespace_id: group.id) + find('[data-qa-selector="blank_project_link"]').click page.within('#blank-project-pane') do expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked @@ -112,6 +118,7 @@ RSpec.describe 'New project' do it 'has private selected' do group = create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) + find('[data-qa-selector="blank_project_link"]').click page.within('#blank-project-pane') do expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked @@ -123,6 +130,7 @@ RSpec.describe 'New project' do context 'Readme selector' do it 'shows the initialize with Readme checkbox on "Blank project" tab' do visit new_project_path + find('[data-qa-selector="blank_project_link"]').click expect(page).to have_css('input#project_initialize_with_readme') expect(page).to have_content('Initialize repository with a README') @@ -130,7 +138,7 @@ RSpec.describe 'New project' do it 'does not show the initialize with Readme checkbox on "Create from template" tab' do visit new_project_path - find('#create-from-template-pane').click + find('[data-qa-selector="create_from_template_link"]').click first('.choose-template').click page.within '.project-fields-form' do @@ -141,7 +149,7 @@ RSpec.describe 'New project' do it 'does not show the initialize with Readme checkbox on "Import project" tab' do visit new_project_path - find('#import-project-tab').click + find('[data-qa-selector="import_project_link"]').click first('.js-import-git-toggle-button').click page.within '.toggle-import-form' do @@ -155,13 +163,12 @@ RSpec.describe 'New project' do context 'with user namespace' do before do visit new_project_path + find('[data-qa-selector="blank_project_link"]').click end it 'selects the user namespace' do page.within('#blank-project-pane') do - namespace = find('#project_namespace_id') - - expect(namespace.text).to eq user.username + expect(page).to have_select('project[namespace_id]', visible: false, selected: user.username) end end end @@ -172,13 +179,12 @@ RSpec.describe 'New project' do before do group.add_owner(user) visit new_project_path(namespace_id: group.id) + find('[data-qa-selector="blank_project_link"]').click end it 'selects the group namespace' do page.within('#blank-project-pane') do - namespace = find('#project_namespace_id option[selected]') - - expect(namespace.text).to eq group.name + expect(page).to have_select('project[namespace_id]', visible: false, selected: group.name) end end end @@ -190,13 +196,12 @@ RSpec.describe 'New project' do before do group.add_maintainer(user) visit new_project_path(namespace_id: subgroup.id) + find('[data-qa-selector="blank_project_link"]').click end it 'selects the group namespace' do page.within('#blank-project-pane') do - namespace = find('#project_namespace_id option[selected]') - - expect(namespace.text).to eq subgroup.full_path + expect(page).to have_select('project[namespace_id]', visible: false, selected: subgroup.full_path) end end end @@ -211,6 +216,7 @@ RSpec.describe 'New project' do internal_group.add_owner(user) private_group.add_owner(user) visit new_project_path(namespace_id: public_group.id) + find('[data-qa-selector="blank_project_link"]').click end it 'enables the correct visibility options' do @@ -240,7 +246,7 @@ RSpec.describe 'New project' do context 'Import project options', :js do before do visit new_project_path - find('#import-project-tab').click + find('[data-qa-selector="import_project_link"]').click end context 'from git repository url, "Repo by URL"' do @@ -285,17 +291,6 @@ RSpec.describe 'New project' do end end - context 'from Google Code' do - before do - first('.import_google_code').click - end - - it 'shows import instructions' do - expect(page).to have_content('Import projects from Google Code') - expect(current_path).to eq new_import_google_code_path - end - end - context 'from manifest file' do before do first('.import_manifest').click @@ -315,13 +310,12 @@ RSpec.describe 'New project' do before do group.add_developer(user) visit new_project_path(namespace_id: group.id) + find('[data-qa-selector="blank_project_link"]').click end it 'selects the group namespace' do page.within('#blank-project-pane') do - namespace = find('#project_namespace_id option[selected]') - - expect(namespace.text).to eq group.full_path + expect(page).to have_select('project[namespace_id]', visible: false, selected: group.full_path) end end end diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb index de7251db5c9..1d9f256a819 100644 --- a/spec/features/projects/settings/operations_settings_spec.rb +++ b/spec/features/projects/settings/operations_settings_spec.rb @@ -23,7 +23,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do describe 'Settings > Operations' do describe 'Incidents' do - let(:create_issue) { 'Create an issue. Issues are created for each alert triggered.' } + let(:create_issue) { 'Create an incident. Incidents are created for each alert triggered.' } let(:send_email) { 'Send a separate email notification to Developers.' } before do diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb index cb333bdb428..2b03ecf5af1 100644 --- a/spec/features/projects/settings/registry_settings_spec.rb +++ b/spec/features/projects/settings/registry_settings_spec.rb @@ -26,20 +26,20 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p subject settings_block = find('#js-registry-policies') - expect(settings_block).to have_text 'Cleanup policy for tags' + expect(settings_block).to have_text 'Clean up image tags' end it 'saves cleanup policy submit the form' do subject within '#js-registry-policies' do - within '.gl-card-body' do - select('7 days until tags are automatically removed', from: 'Expiration interval:') - select('Every day', from: 'Expiration schedule:') - select('50 tags per image name', from: 'Number of tags to retain:') - fill_in('Tags with names matching this regex pattern will expire:', with: '.*-production') - end - submit_button = find('.gl-card-footer .btn.btn-success') + select('Every day', from: 'Run cleanup') + select('50 tags per image name', from: 'Keep the most recent:') + fill_in('Keep tags matching:', with: 'stable') + select('7 days', from: 'Remove tags older than:') + fill_in('Remove tags matching:', with: '.*-production') + + submit_button = find('.btn.btn-success') expect(submit_button).not_to be_disabled submit_button.click end @@ -51,10 +51,9 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p subject within '#js-registry-policies' do - within '.gl-card-body' do - fill_in('Tags with names matching this regex pattern will expire:', with: '*-production') - end - submit_button = find('.gl-card-footer .btn.btn-success') + fill_in('Remove tags matching:', with: '*-production') + + submit_button = find('.btn.btn-success') expect(submit_button).not_to be_disabled submit_button.click end @@ -85,7 +84,7 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p within '#js-registry-policies' do case result when :available_section - expect(find('.gl-card-header')).to have_content('Tag expiration policy') + expect(find('[data-testid="enable-toggle"]')).to have_content('Disabled - Tags will not be automatically deleted.') when :disabled_message expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled') end diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 8c7b7bc70a2..3e520142117 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -289,13 +289,13 @@ RSpec.describe 'Projects > Settings > Repository settings' do visit project_settings_repository_path(project) end - context 'when project mirroring is enabled' do + context 'when project mirroring is enabled', :enable_admin_mode do let(:mirror_available) { true } include_examples 'shows mirror settings' end - context 'when project mirroring is disabled' do + context 'when project mirroring is disabled', :enable_admin_mode do let(:mirror_available) { false } include_examples 'shows mirror settings' diff --git a/spec/features/projects/settings/service_desk_setting_spec.rb b/spec/features/projects/settings/service_desk_setting_spec.rb index 59e6f54da2f..d31913d2dcf 100644 --- a/spec/features/projects/settings/service_desk_setting_spec.rb +++ b/spec/features/projects/settings/service_desk_setting_spec.rb @@ -14,20 +14,57 @@ RSpec.describe 'Service Desk Setting', :js do allow_any_instance_of(Project).to receive(:present).with(current_user: user).and_return(presenter) allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true } allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true } - - visit edit_project_path(project) end it 'shows activation checkbox' do + visit edit_project_path(project) + expect(page).to have_selector("#service-desk-checkbox") end - it 'shows incoming email after activating' do - find("#service-desk-checkbox").click - wait_for_requests - project.reload - expect(project.service_desk_enabled).to be_truthy - expect(project.service_desk_address).to be_present - expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_address) + context 'when service_desk_email is disabled' do + before do + allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?).and_return(false) + + visit edit_project_path(project) + end + + it 'shows incoming email but not project name suffix after activating' do + find("#service-desk-checkbox").click + + wait_for_requests + + project.reload + expect(project.service_desk_enabled).to be_truthy + expect(project.service_desk_address).to be_present + expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_incoming_address) + expect(page).not_to have_selector('#service-desk-project-suffix') + end + end + + context 'when service_desk_email is enabled' do + before do + allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?) { true } + allow(::Gitlab::ServiceDeskEmail).to receive(:address_for_key) { 'address-suffix@example.com' } + + visit edit_project_path(project) + end + + it 'allows setting of custom address suffix' do + find("#service-desk-checkbox").click + wait_for_requests + + project.reload + expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_incoming_address) + + page.within '#js-service-desk' do + fill_in('service-desk-project-suffix', with: 'foo') + click_button 'Save changes' + end + + wait_for_requests + + expect(find('[data-testid="incoming-email"]').value).to eq('address-suffix@example.com') + end end end diff --git a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb index ba504624823..91a7753fe6d 100644 --- a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb +++ b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb @@ -19,7 +19,7 @@ RSpec.describe "User interacts with deploy keys", :js do click_button("Enable") - expect(page).not_to have_selector(".fa-spinner") + expect(page).not_to have_selector(".gl-spinner") expect(current_path).to eq(project_settings_repository_path(project)) find(".js-deployKeys-tab-enabled_keys").click diff --git a/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb deleted file mode 100644 index 8d239cb2cbf..00000000000 --- a/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Projects > Show > Developer views empty project instructions' do - let(:project) { create(:project, :empty_repo) } - let(:developer) { create(:user) } - - before do - project.add_developer(developer) - - sign_in(developer) - end - - it 'displays "git clone" instructions' do - visit project_path(project) - - expect(page).to have_content("git clone") - end -end diff --git a/spec/features/projects/show/no_password_spec.rb b/spec/features/projects/show/no_password_spec.rb index 79cd65e5406..d18ff75b324 100644 --- a/spec/features/projects/show/no_password_spec.rb +++ b/spec/features/projects/show/no_password_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'No Password Alert' do let(:user) { create(:user) } it 'shows no alert' do - expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account" + expect(page).not_to have_content "You won't be able to pull or push repositories via HTTP until you set a password on your account" end end @@ -23,7 +23,7 @@ RSpec.describe 'No Password Alert' do let(:user) { create(:user, password_automatically_set: true) } it 'shows a password alert' do - expect(page).to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account" + expect(page).to have_content "You won't be able to pull or push repositories via HTTP until you set a password on your account" end end end @@ -41,7 +41,7 @@ RSpec.describe 'No Password Alert' do gitlab_sign_in_via('saml', user, 'my-uid') visit project_path(project) - expect(page).to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account" + expect(page).to have_content "You won't be able to pull or push repositories via HTTP until you create a personal access token on your account" end end @@ -51,7 +51,7 @@ RSpec.describe 'No Password Alert' do gitlab_sign_in_via('saml', user, 'my-uid') visit project_path(project) - expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account" + expect(page).not_to have_content "You won't be able to pull or push repositories via HTTP until you create a personal access token on your account" end end end @@ -65,7 +65,7 @@ RSpec.describe 'No Password Alert' do end it 'shows no alert' do - expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you" + expect(page).not_to have_content "You won't be able to pull or push repositories via HTTP until you" end end end diff --git a/spec/features/projects/show/schema_markup_spec.rb b/spec/features/projects/show/schema_markup_spec.rb index e651798af23..1777b72cbf5 100644 --- a/spec/features/projects/show/schema_markup_spec.rb +++ b/spec/features/projects/show/schema_markup_spec.rb @@ -14,7 +14,7 @@ RSpec.describe 'Projects > Show > Schema Markup' do expect(page).to have_selector('img[itemprop="image"]') expect(page).to have_selector('[itemprop="name"]', text: project.name) expect(page).to have_selector('[itemprop="identifier"]', text: "Project ID: #{project.id}") - expect(page).to have_selector('[itemprop="abstract"]', text: project.description) + expect(page).to have_selector('[itemprop="description"]', text: project.description) expect(page).to have_selector('[itemprop="license"]', text: project.repository.license.name) expect(find_all('[itemprop="keywords"]').map(&:text)).to match_array(project.tag_list.map(&:capitalize)) expect(page).to have_selector('[itemprop="about"]') diff --git a/spec/features/projects/show/user_sees_git_instructions_spec.rb b/spec/features/projects/show/user_sees_git_instructions_spec.rb index 3b77fd7eebf..febdb70de86 100644 --- a/spec/features/projects/show/user_sees_git_instructions_spec.rb +++ b/spec/features/projects/show/user_sees_git_instructions_spec.rb @@ -122,13 +122,11 @@ RSpec.describe 'Projects > Show > User sees Git instructions' do context 'when project is not empty' do let_it_be(:project) { create(:project, :public, :repository) } - before do - visit(project_path(project)) - end - context 'when not signed in' do before do allow(Gitlab.config.gitlab).to receive(:host).and_return('www.example.com') + + visit(project_path(project)) end include_examples 'shows details of non empty project' diff --git a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb index 189aa45ff75..9b51e867156 100644 --- a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb +++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb @@ -22,7 +22,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do visit project_path(project) end - it 'Project buttons are not visible' do + it 'project buttons are not visible' do visit project_path(project) page.within('.project-buttons') do @@ -165,7 +165,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do context 'when the project does not have a README' do it 'shows the single file editor "Add README" button' do - allow(project.repository).to receive(:readme).and_return(nil) + allow(project.repository).to receive(:readme_path).and_return(nil) visit project_path(project) diff --git a/spec/features/projects/terraform_spec.rb b/spec/features/projects/terraform_spec.rb index 2680dfb2b13..dfa4dad8490 100644 --- a/spec/features/projects/terraform_spec.rb +++ b/spec/features/projects/terraform_spec.rb @@ -4,44 +4,94 @@ require 'spec_helper' RSpec.describe 'Terraform', :js do let_it_be(:project) { create(:project) } + let_it_be(:terraform_state) { create(:terraform_state, :locked, :with_version, project: project) } - let(:user) { project.creator } + context 'when user is a terraform administrator' do + let(:admin) { project.creator } - before do - gitlab_sign_in(user) - end - - context 'when user does not have any terraform states and visits index page' do before do - visit project_terraform_index_path(project) + gitlab_sign_in(admin) end - it 'sees an empty state' do - expect(page).to have_content('Get started with Terraform') + context 'when user does not have any terraform states and visits the index page' do + let(:empty_project) { create(:project) } + + before do + empty_project.add_maintainer(admin) + visit project_terraform_index_path(empty_project) + end + + it 'sees an empty state' do + expect(page).to have_content('Get started with Terraform') + end end - end - context 'when user has a terraform state' do - let_it_be(:terraform_state) { create(:terraform_state, :locked, project: project) } + context 'when user has a terraform state' do + context 'when user visits the index page' do + before do + visit project_terraform_index_path(project) + end - context 'when user visits the index page' do - before do - visit project_terraform_index_path(project) + it 'displays a tab with states count' do + expect(page).to have_content("States #{project.terraform_states.size}") + end + + it 'displays a table with terraform states' do + expect(page).to have_selector( + '[data-testid="terraform-states-table-name"]', + count: project.terraform_states.size + ) + end + + it 'displays terraform actions dropdown' do + expect(page).to have_selector( + '[data-testid*="terraform-state-actions"]', + count: project.terraform_states.size + ) + end + + it 'displays terraform information' do + expect(page).to have_content(terraform_state.name) + end end - it 'displays a tab with states count' do - expect(page).to have_content("States #{project.terraform_states.size}") + context 'when clicking on the delete button' do + let(:additional_state) { create(:terraform_state, project: project) } + + it 'removes the state', :aggregate_failures do + visit project_terraform_index_path(project) + + expect(page).to have_content(additional_state.name) + + find("[data-testid='terraform-state-actions-#{additional_state.name}']").click + find('[data-testid="terraform-state-remove"]').click + fill_in "terraform-state-remove-input-#{additional_state.name}", with: additional_state.name + click_button 'Remove' + + expect(page).not_to have_content(additional_state.name) + expect { additional_state.reload }.to raise_error ActiveRecord::RecordNotFound + end end + end + end + + context 'when user is a terraform developer' do + let_it_be(:developer) { create(:user) } - it 'displays a table with terraform states' do + before do + project.add_developer(developer) + gitlab_sign_in(developer) + visit project_terraform_index_path(project) + end + + context 'when user visits the index page' do + it 'displays a table without an action dropdown', :aggregate_failures do expect(page).to have_selector( - '[data-testid="terraform-states-table"] tbody tr', + '[data-testid="terraform-states-table-name"]', count: project.terraform_states.size ) - end - it 'displays terraform information' do - expect(page).to have_content(terraform_state.name) + expect(page).not_to have_selector('[data-testid*="terraform-state-actions"]') end end end diff --git a/spec/features/projects/user_creates_project_spec.rb b/spec/features/projects/user_creates_project_spec.rb index b204ae76e07..feb5f348256 100644 --- a/spec/features/projects/user_creates_project_spec.rb +++ b/spec/features/projects/user_creates_project_spec.rb @@ -13,6 +13,7 @@ RSpec.describe 'User creates a project', :js do it 'creates a new project' do visit(new_project_path) + find('[data-qa-selector="blank_project_link"]').click fill_in(:project_name, with: 'Empty') page.within('#content-body') do @@ -39,6 +40,7 @@ RSpec.describe 'User creates a project', :js do it 'creates a new project' do visit(new_project_path) + find('[data-qa-selector="blank_project_link"]').click fill_in :project_name, with: 'A Subgroup Project' fill_in :project_path, with: 'a-subgroup-project' @@ -67,6 +69,7 @@ RSpec.describe 'User creates a project', :js do it 'creates a new project' do visit(new_project_path) + find('[data-qa-selector="blank_project_link"]').click fill_in :project_name, with: 'a-new-project' fill_in :project_path, with: 'a-new-project' diff --git a/spec/features/projects/user_sorts_projects_spec.rb b/spec/features/projects/user_sorts_projects_spec.rb new file mode 100644 index 00000000000..6a5ed49f1a6 --- /dev/null +++ b/spec/features/projects/user_sorts_projects_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User sorts projects and order persists' do + include CookieHelper + + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:group_member) { create(:group_member, :maintainer, user: user, group: group) } + let_it_be(:project) { create(:project, :public, group: group) } + + shared_examples_for "sort order persists across all views" do |project_paths_label, group_paths_label| + 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) + 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) + 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) + 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) + end + end + + context "from explore projects" do + before do + sign_in(user) + visit(explore_projects_path) + find('#sort-projects-dropdown').click + first(:link, 'Last updated').click + end + + it_behaves_like "sort order persists across all views", "Last updated", "Last updated" + end + + context 'from dashboard projects' do + before do + sign_in(user) + visit(dashboard_projects_path) + find('#sort-projects-dropdown').click + first(:link, 'Name').click + end + + it_behaves_like "sort order persists across all views", "Name", "Name" + end + + context 'from group homepage' do + before do + sign_in(user) + visit(group_canonical_path(group)) + find('button.dropdown-menu-toggle').click + first(:link, 'Last created').click + end + + it_behaves_like "sort order persists across all views", "Created date", "Last created" + end + + context 'from group details' do + before do + sign_in(user) + visit(details_group_path(group)) + find('button.dropdown-menu-toggle').click + first(:link, 'Most stars').click + end + + it_behaves_like "sort order persists across all views", "Stars", "Most stars" + end +end diff --git a/spec/features/projects/user_views_empty_project_spec.rb b/spec/features/projects/user_views_empty_project_spec.rb index 9202d18b86f..3d4d9a7ea96 100644 --- a/spec/features/projects/user_views_empty_project_spec.rb +++ b/spec/features/projects/user_views_empty_project_spec.rb @@ -7,12 +7,9 @@ RSpec.describe 'User views an empty project' do let(:user) { create(:user) } shared_examples 'allowing push to default branch' do - before do - sign_in(user) + it 'shows push-to-master instructions' do visit project_path(project) - end - it 'shows push-to-master instructions' do expect(page).to have_content('git push -u origin master') end end @@ -20,6 +17,7 @@ RSpec.describe 'User views an empty project' do describe 'as a maintainer' do before do project.add_maintainer(user) + sign_in(user) end it_behaves_like 'allowing push to default branch' @@ -28,17 +26,33 @@ RSpec.describe 'User views an empty project' do describe 'as an admin' do let(:user) { create(:user, :admin) } - it_behaves_like 'allowing push to default branch' + context 'when admin mode is enabled' do + before do + sign_in(user) + gitlab_enable_admin_mode_sign_in(user) + end + + it_behaves_like 'allowing push to default branch' + end + + context 'when admin mode is disabled' do + it 'does not show push-to-master instructions' do + visit project_path(project) + + expect(page).not_to have_content('git push -u origin master') + end + end end describe 'as a developer' do before do project.add_developer(user) sign_in(user) - visit project_path(project) end it 'does not show push-to-master instructions' do + visit project_path(project) + expect(page).not_to have_content('git push -u origin master') end end diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb deleted file mode 100644 index 83679c6bd1d..00000000000 --- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Projects > Wiki > User views Git access wiki page' do - let(:user) { create(:user) } - let(:project) { create(:project, :wiki_repo, :public) } - let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') } - - before do - sign_in(user) - end - - it 'Visit Wiki Page Current Commit' do - visit project_wiki_path(project, wiki_page) - - click_link 'Clone repository' - expect(page).to have_text("Clone repository #{project.wiki.full_path}") - expect(page).to have_text(project.wiki.http_url_to_repo) - end -end diff --git a/spec/features/projects/wikis_spec.rb b/spec/features/projects/wikis_spec.rb index 1c66ad81145..621f8c71b20 100644 --- a/spec/features/projects/wikis_spec.rb +++ b/spec/features/projects/wikis_spec.rb @@ -17,4 +17,5 @@ RSpec.describe 'Project wikis' do it_behaves_like 'User views a wiki page' it_behaves_like 'User views wiki pages' it_behaves_like 'User views wiki sidebar' + it_behaves_like 'User views Git access wiki page' end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 9b5f4ca6d48..618a256d4fb 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -16,7 +16,7 @@ RSpec.describe 'Project' do shared_examples 'creates from template' do |template, sub_template_tab = nil| it "is created from template", :js do - find('#create-from-template-tab').click + find('[data-qa-selector="create_from_template_link"]').click find(".project-template #{sub_template_tab}").click if sub_template_tab find("label[for=#{template.name}]").click fill_in("project_name", with: template.name) @@ -34,7 +34,7 @@ RSpec.describe 'Project' do end context 'create with sample data template' do - it_behaves_like 'creates from template', Gitlab::SampleDataTemplate.find(:basic), '.sample-data-templates-tab' + it_behaves_like 'creates from template', Gitlab::SampleDataTemplate.find(:sample) end end @@ -47,9 +47,7 @@ RSpec.describe 'Project' do end it 'shows the command in a popover', :js do - page.within '.profile-settings-sidebar' do - click_link 'Show command' - end + click_link 'Show command' expect(page).to have_css('.popover .push-to-create-popover #push_to_create_tip') expect(page).to have_content 'Private projects can be created in your personal namespace with:' @@ -61,7 +59,7 @@ RSpec.describe 'Project' do let(:path) { project_path(project) } before do - sign_in(create(:admin)) + sign_in(project.owner) end it 'parses Markdown' do @@ -125,7 +123,7 @@ RSpec.describe 'Project' do let(:path) { project_path(project) } before do - sign_in(create(:admin)) + sign_in(project.owner) visit path end @@ -156,7 +154,7 @@ RSpec.describe 'Project' do let(:path) { project_path(project) } before do - sign_in(create(:admin)) + sign_in(project.owner) visit path end diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 3be01595502..95d268ab1be 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -73,6 +73,7 @@ RSpec.describe 'Protected Branches', :js do context 'logged in as admin' do before do sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end describe "explicit protected branches" do diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb index 12e4bbde293..25447db3c8d 100644 --- a/spec/features/protected_tags_spec.rb +++ b/spec/features/protected_tags_spec.rb @@ -5,8 +5,8 @@ require 'spec_helper' RSpec.describe 'Protected Tags', :js do include ProtectedTagHelpers - let(:user) { create(:user, :admin) } let(:project) { create(:project, :repository) } + let(:user) { project.owner } before do sign_in(user) diff --git a/spec/features/registrations/experience_level_spec.rb b/spec/features/registrations/experience_level_spec.rb index 06d380926cd..25496e2fef1 100644 --- a/spec/features/registrations/experience_level_spec.rb +++ b/spec/features/registrations/experience_level_spec.rb @@ -9,7 +9,7 @@ RSpec.describe 'Experience level screen' do before do group.add_owner(user) gitlab_sign_in(user) - stub_experiment_for_user(onboarding_issues: true) + stub_experiment_for_subject(onboarding_issues: true) visit users_sign_up_experience_level_path(namespace_path: group.to_param) end @@ -23,14 +23,14 @@ RSpec.describe 'Experience level screen' do it 'shows the option for novice' do is_expected.to have_content('Novice') - is_expected.to have_content('I’m not very familiar with the basics of project management and DevOps') - is_expected.to have_content('Show me everything') + is_expected.to have_content('I’m not familiar with the basics of DevOps') + is_expected.to have_content('Show me the basics') end it 'shows the option for experienced' do is_expected.to have_content('Experienced') - is_expected.to have_content('I’m familiar with the basics of project management and DevOps') - is_expected.to have_content('Show me more advanced stuff') + is_expected.to have_content('I’m familiar with the basics of DevOps') + is_expected.to have_content('Show me advanced features') end it 'does not display any flash messages' do diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 9697e10c3d1..5cddad81927 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -179,16 +179,32 @@ RSpec.describe 'Runners' do context 'when a project has disabled shared_runners' do let(:project) { create(:project, shared_runners_enabled: false) } - before do - project.add_maintainer(user) + context 'when feature flag: vueify_shared_runners_toggle is disabled' do + before do + stub_feature_flags(vueify_shared_runners_toggle: false) + project.add_maintainer(user) + end + + it 'user enables shared runners' do + visit project_runners_path(project) + + click_on 'Enable shared runners' + + expect(page.find('.shared-runners-description')).to have_content('Disable shared runners') + expect(page).not_to have_selector('#toggle-shared-runners-form') + end end - it 'user enables shared runners' do - visit project_runners_path(project) + context 'when feature flag: vueify_shared_runners_toggle is enabled' do + before do + project.add_maintainer(user) + end - click_on 'Enable shared runners' + it 'user enables shared runners' do + visit project_runners_path(project) - expect(page.find('.shared-runners-description')).to have_content('Disable shared runners') + expect(page).to have_selector('#toggle-shared-runners-form') + end end end diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb index f761bd30baf..ee3717b3e42 100644 --- a/spec/features/search/user_searches_for_code_spec.rb +++ b/spec/features/search/user_searches_for_code_spec.rb @@ -27,8 +27,13 @@ RSpec.describe 'User searches for code' do context 'when on a project page', :js do before do visit(search_path) - find('.js-search-project-dropdown').click - find('[data-testid="project-filter"]').click_link(project.full_name) + find('[data-testid="project-filter"]').click + + wait_for_requests + + page.within('[data-testid="project-filter"]') do + click_on(project.full_name) + end end include_examples 'top right search form' diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb index e2ae2738d2f..e253b9f2f7a 100644 --- a/spec/features/search/user_searches_for_issues_spec.rb +++ b/spec/features/search/user_searches_for_issues_spec.rb @@ -85,8 +85,13 @@ RSpec.describe 'User searches for issues', :js do context 'when on a project page' do it 'finds an issue' do - find('.js-search-project-dropdown').click - find('[data-testid="project-filter"]').click_link(project.full_name) + find('[data-testid="project-filter"]').click + + wait_for_requests + + page.within('[data-testid="project-filter"]') do + click_on(project.full_name) + end search_for_issue(issue1.title) diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb index 6f8f6303b66..21e8075739f 100644 --- a/spec/features/search/user_searches_for_merge_requests_spec.rb +++ b/spec/features/search/user_searches_for_merge_requests_spec.rb @@ -30,8 +30,13 @@ RSpec.describe 'User searches for merge requests', :js do context 'when on a project page' do it 'finds a merge request' do - find('.js-search-project-dropdown').click - find('[data-testid="project-filter"]').click_link(project.full_name) + find('[data-testid="project-filter"]').click + + wait_for_requests + + page.within('[data-testid="project-filter"]') do + click_on(project.full_name) + end fill_in('dashboard_search', with: merge_request1.title) find('.btn-search').click diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb index 1a2227db214..f4df91dbc08 100644 --- a/spec/features/search/user_searches_for_milestones_spec.rb +++ b/spec/features/search/user_searches_for_milestones_spec.rb @@ -30,8 +30,13 @@ RSpec.describe 'User searches for milestones', :js do context 'when on a project page' do it 'finds a milestone' do - find('.js-search-project-dropdown').click - find('[data-testid="project-filter"]').click_link(project.full_name) + find('[data-testid="project-filter"]').click + + wait_for_requests + + page.within('[data-testid="project-filter"]') do + click_on(project.full_name) + end fill_in('dashboard_search', with: milestone1.title) find('.btn-search').click diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb index 6bf1407fd4f..72bd1193fc9 100644 --- a/spec/features/search/user_searches_for_wiki_pages_spec.rb +++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb @@ -18,8 +18,13 @@ RSpec.describe 'User searches for wiki pages', :js do shared_examples 'search wiki blobs' do it 'finds a page' do - find('.js-search-project-dropdown').click - find('[data-testid="project-filter"]').click_link(project.full_name) + find('[data-testid="project-filter"]').click + + wait_for_requests + + page.within('[data-testid="project-filter"]') do + click_on(project.full_name) + end fill_in('dashboard_search', with: search_term) find('.btn-search').click diff --git a/spec/features/search/user_uses_search_filters_spec.rb b/spec/features/search/user_uses_search_filters_spec.rb index bd77e6003e3..86017ca64c5 100644 --- a/spec/features/search/user_uses_search_filters_spec.rb +++ b/spec/features/search/user_uses_search_filters_spec.rb @@ -28,13 +28,15 @@ RSpec.describe 'User uses search filters', :js do expect(find('[data-testid="group-filter"]')).to have_content(group.name) - page.within('[data-testid="project-filter"]') do - find('.js-search-project-dropdown').click + find('[data-testid="project-filter"]').click - wait_for_requests + wait_for_requests - expect(page).to have_link(group_project.full_name) + page.within('[data-testid="project-filter"]') do + click_on(group_project.full_name) end + + expect(find('[data-testid="project-filter"]')).to have_content(group_project.full_name) end context 'when the group filter is set' do @@ -58,15 +60,15 @@ RSpec.describe 'User uses search filters', :js do it 'shows a project' do visit search_path - page.within('[data-testid="project-filter"]') do - find('.js-search-project-dropdown').click + find('[data-testid="project-filter"]').click - wait_for_requests + wait_for_requests - click_link(project.full_name) + page.within('[data-testid="project-filter"]') do + click_on(project.full_name) end - expect(find('.js-search-project-dropdown')).to have_content(project.full_name) + expect(find('[data-testid="project-filter"]')).to have_content(project.full_name) end context 'when the project filter is set' do @@ -78,10 +80,10 @@ RSpec.describe 'User uses search filters', :js do describe 'clear filter button' do it 'removes Project filters' do - link = find('[data-testid="project-filter"] .js-search-clear') - params = CGI.parse(URI.parse(link[:href]).query) + find('[data-testid="project-filter"] [data-testid="clear-icon"]').click + wait_for_requests - expect(params).not_to include(:project_id) + expect(page).to have_current_path(search_path(search: "test")) end end end diff --git a/spec/features/security/admin_access_spec.rb b/spec/features/security/admin_access_spec.rb index 38f00f399f3..8070ae066e7 100644 --- a/spec/features/security/admin_access_spec.rb +++ b/spec/features/security/admin_access_spec.rb @@ -8,7 +8,14 @@ RSpec.describe "Admin::Projects" do describe "GET /admin/projects" do subject { admin_projects_path } - it { is_expected.to be_allowed_for :admin } + context 'when admin mode is enabled', :enable_admin_mode do + it { is_expected.to be_allowed_for :admin } + end + + context 'when admin mode is disabled' do + it { is_expected.to be_denied_for :admin } + end + it { is_expected.to be_denied_for :user } it { is_expected.to be_denied_for :visitor } end @@ -16,7 +23,14 @@ RSpec.describe "Admin::Projects" do describe "GET /admin/users" do subject { admin_users_path } - it { is_expected.to be_allowed_for :admin } + context 'when admin mode is enabled', :enable_admin_mode do + it { is_expected.to be_allowed_for :admin } + end + + context 'when admin mode is disabled' do + it { is_expected.to be_denied_for :admin } + end + it { is_expected.to be_denied_for :user } it { is_expected.to be_denied_for :visitor } end @@ -24,7 +38,14 @@ RSpec.describe "Admin::Projects" do describe "GET /admin/hooks" do subject { admin_hooks_path } - it { is_expected.to be_allowed_for :admin } + context 'when admin mode is enabled', :enable_admin_mode do + it { is_expected.to be_allowed_for :admin } + end + + context 'when admin mode is disabled' do + it { is_expected.to be_denied_for :admin } + end + it { is_expected.to be_denied_for :user } it { is_expected.to be_denied_for :visitor } end diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 051bd601c1d..cb9f9a6e680 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -102,7 +102,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/-/settings/ci_cd" do subject { project_settings_ci_cd_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -116,7 +117,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/-/settings/repository" do subject { project_settings_repository_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -146,7 +148,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/edit" do subject { edit_project_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -160,7 +163,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/deploy_keys" do subject { project_deploy_keys_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -190,7 +194,8 @@ RSpec.describe "Internal Project Access" do subject { edit_project_issue_path(project, issue) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -218,7 +223,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/snippets/new" do subject { new_project_snippet_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -246,7 +252,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/-/merge_requests/new" do subject { project_new_merge_request_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -302,7 +309,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/-/settings/integrations" do subject { project_settings_integrations_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -367,7 +375,8 @@ RSpec.describe "Internal Project Access" do project.update(public_builds: false) end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -406,7 +415,8 @@ RSpec.describe "Internal Project Access" do project.update(public_builds: false) end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -445,7 +455,8 @@ RSpec.describe "Internal Project Access" do project.update(public_builds: false) end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -460,7 +471,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/pipeline_schedules" do subject { project_pipeline_schedules_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -474,7 +486,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/-/environments" do subject { project_environments_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -490,7 +503,8 @@ RSpec.describe "Internal Project Access" do subject { project_environment_path(project, environment) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -506,7 +520,8 @@ RSpec.describe "Internal Project Access" do subject { project_environment_deployments_path(project, environment) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -520,7 +535,8 @@ RSpec.describe "Internal Project Access" do describe "GET /:project_path/-/environments/new" do subject { new_project_environment_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index e891e79db70..dda218c5de5 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -18,7 +18,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path" do subject { project_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -32,7 +33,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/tree/master" do subject { project_tree_path(project, project.repository.root_ref) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -46,7 +48,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/commits/master" do subject { project_commits_path(project, project.repository.root_ref, limit: 1) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -60,7 +63,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/commit/:sha" do subject { project_commit_path(project, project.repository.commit) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -74,7 +78,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/compare" do subject { project_compare_index_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -88,7 +93,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/project_members" do subject { project_project_members_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -102,7 +108,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/settings/ci_cd" do subject { project_settings_ci_cd_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -116,7 +123,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/settings/repository" do subject { project_settings_repository_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -132,7 +140,8 @@ RSpec.describe "Private Project Access" do subject { project_blob_path(project, File.join(commit.id, '.gitignore')) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -146,7 +155,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/edit" do subject { edit_project_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -160,7 +170,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/deploy_keys" do subject { project_deploy_keys_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -174,7 +185,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/issues" do subject { project_issues_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -190,7 +202,8 @@ RSpec.describe "Private Project Access" do subject { edit_project_issue_path(project, issue) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -204,7 +217,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/snippets" do subject { project_snippets_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -218,7 +232,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/merge_requests" do subject { project_merge_requests_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -239,7 +254,8 @@ RSpec.describe "Private Project Access" do end end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -260,7 +276,8 @@ RSpec.describe "Private Project Access" do end end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -274,7 +291,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/settings/integrations" do subject { project_settings_integrations_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -288,7 +306,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/pipelines" do subject { project_pipelines_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -316,7 +335,8 @@ RSpec.describe "Private Project Access" do subject { project_pipeline_path(project, pipeline) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -342,7 +362,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/builds" do subject { project_jobs_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -371,7 +392,8 @@ RSpec.describe "Private Project Access" do subject { project_job_path(project, build.id) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -405,7 +427,8 @@ RSpec.describe "Private Project Access" do subject { trace_project_job_path(project, build.id) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -435,7 +458,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/environments" do subject { project_environments_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -451,7 +475,8 @@ RSpec.describe "Private Project Access" do subject { project_environment_path(project, environment) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -467,7 +492,8 @@ RSpec.describe "Private Project Access" do subject { project_environment_deployments_path(project, environment) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -481,7 +507,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/environments/new" do subject { new_project_environment_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -495,7 +522,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/pipeline_schedules" do subject { project_pipeline_schedules_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -509,7 +537,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/pipeline_schedules/new" do subject { new_project_pipeline_schedule_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -523,7 +552,8 @@ RSpec.describe "Private Project Access" do describe "GET /:project_path/-/environments/new" do subject { new_project_pipeline_schedule_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -545,7 +575,8 @@ RSpec.describe "Private Project Access" do subject { project_container_registry_index_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 75993959f6e..f2dbab72a48 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -102,7 +102,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/-/settings/ci_cd" do subject { project_settings_ci_cd_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -116,7 +117,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/-/settings/repository" do subject { project_settings_repository_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -181,7 +183,8 @@ RSpec.describe "Public Project Access" do project.update(public_builds: false) end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -220,7 +223,8 @@ RSpec.describe "Public Project Access" do project.update(public_builds: false) end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -259,7 +263,8 @@ RSpec.describe "Public Project Access" do project.update(public_builds: false) end - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -274,7 +279,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/pipeline_schedules" do subject { project_pipeline_schedules_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -288,7 +294,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/-/environments" do subject { project_environments_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -304,7 +311,8 @@ RSpec.describe "Public Project Access" do subject { project_environment_path(project, environment) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -320,7 +328,8 @@ RSpec.describe "Public Project Access" do subject { project_environment_deployments_path(project, environment) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is disabled') { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -334,7 +343,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/-/environments/new" do subject { new_project_environment_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -363,7 +373,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/edit" do subject { edit_project_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -377,7 +388,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/deploy_keys" do subject { project_deploy_keys_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } @@ -407,7 +419,8 @@ RSpec.describe "Public Project Access" do subject { edit_project_issue_path(project, issue) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -435,7 +448,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/snippets/new" do subject { new_project_snippet_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -463,7 +477,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/-/merge_requests/new" do subject { project_new_merge_request_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -519,7 +534,8 @@ RSpec.describe "Public Project Access" do describe "GET /:project_path/-/settings/integrations" do subject { project_settings_integrations_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb index 0667a2fd48a..12237863188 100644 --- a/spec/features/security/project/snippet/internal_access_spec.rb +++ b/spec/features/security/project/snippet/internal_access_spec.rb @@ -26,7 +26,8 @@ RSpec.describe "Internal Project Snippets Access" do describe "GET /:project_path/snippets/new" do subject { new_project_snippet_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -55,7 +56,8 @@ RSpec.describe "Internal Project Snippets Access" do context "for a private snippet" do subject { project_snippet_path(project, private_snippet) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -85,7 +87,8 @@ RSpec.describe "Internal Project Snippets Access" do context "for a private snippet" do subject { raw_project_snippet_path(project, private_snippet) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb index 0c97b012ad1..0f7ae06a6c5 100644 --- a/spec/features/security/project/snippet/private_access_spec.rb +++ b/spec/features/security/project/snippet/private_access_spec.rb @@ -12,7 +12,8 @@ RSpec.describe "Private Project Snippets Access" do describe "GET /:project_path/snippets" do subject { project_snippets_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -26,7 +27,8 @@ RSpec.describe "Private Project Snippets Access" do describe "GET /:project_path/snippets/new" do subject { new_project_snippet_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -40,7 +42,8 @@ RSpec.describe "Private Project Snippets Access" do describe "GET /:project_path/snippets/:id for a private snippet" do subject { project_snippet_path(project, private_snippet) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -54,7 +57,8 @@ RSpec.describe "Private Project Snippets Access" do describe "GET /:project_path/snippets/:id/raw for a private snippet" do subject { raw_project_snippet_path(project, private_snippet) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb index 20a271f9c0e..2ae08205602 100644 --- a/spec/features/security/project/snippet/public_access_spec.rb +++ b/spec/features/security/project/snippet/public_access_spec.rb @@ -27,7 +27,8 @@ RSpec.describe "Public Project Snippets Access" do describe "GET /:project_path/snippets/new" do subject { new_project_snippet_path(project) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -70,7 +71,8 @@ RSpec.describe "Public Project Snippets Access" do context "for a private snippet" do subject { project_snippet_path(project, private_snippet) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } @@ -114,7 +116,8 @@ RSpec.describe "Public Project Snippets Access" do context "for a private snippet" do subject { raw_project_snippet_path(project, private_snippet) } - it { is_expected.to be_allowed_for(:admin) } + it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { is_expected.to be_allowed_for(:admin) } + it('is denied for admin when admin mode is disabled') { is_expected.to be_denied_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } diff --git a/spec/features/snippets/private_snippets_spec.rb b/spec/features/snippets/private_snippets_spec.rb index 03745c1025a..7ff27419cf7 100644 --- a/spec/features/snippets/private_snippets_spec.rb +++ b/spec/features/snippets/private_snippets_spec.rb @@ -11,7 +11,7 @@ RSpec.describe 'Private Snippets', :js do sign_in(user) end - it 'Private Snippet renders for creator' do + it 'private Snippet renders for creator' do visit snippet_path(private_snippet) wait_for_requests diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb index d2dc85a9614..0f27d96d8e9 100644 --- a/spec/features/snippets/public_snippets_spec.rb +++ b/spec/features/snippets/public_snippets_spec.rb @@ -6,7 +6,7 @@ RSpec.describe 'Public Snippets', :js do let(:public_snippet) { create(:personal_snippet, :public, :repository) } let(:content) { public_snippet.blobs.first.data.strip! } - it 'Unauthenticated user should see public snippets' do + it 'unauthenticated user should see public snippets' do url = Gitlab::UrlBuilder.build(public_snippet) visit snippet_path(public_snippet) @@ -18,7 +18,7 @@ RSpec.describe 'Public Snippets', :js do expect(page).to have_field('Share', readonly: true, with: url) end - it 'Unauthenticated user should see raw public snippets' do + it 'unauthenticated user should see raw public snippets' do visit raw_snippet_path(public_snippet) expect(page).to have_content(content) diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb index 4f299edc9da..46bc3b7caad 100644 --- a/spec/features/snippets/search_snippets_spec.rb +++ b/spec/features/snippets/search_snippets_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Search Snippets' do - it 'User searches for snippets by title' do + it 'user searches for snippets by title' do public_snippet = create(:personal_snippet, :public, title: 'Beginning and Middle') private_snippet = create(:personal_snippet, :private, title: 'Middle and End') diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index 1e51210c2b8..ca050daa62a 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -25,7 +25,7 @@ RSpec.describe 'User creates snippet', :js do snippet_fill_in_form(title: title, content: file_content, description: md_description) end - it 'Authenticated user creates a snippet' do + it 'authenticated user creates a snippet' do fill_form click_button('Create snippet') diff --git a/spec/features/snippets/user_snippets_spec.rb b/spec/features/snippets/user_snippets_spec.rb index a313dc3b26a..fe39208213a 100644 --- a/spec/features/snippets/user_snippets_spec.rb +++ b/spec/features/snippets/user_snippets_spec.rb @@ -13,13 +13,13 @@ RSpec.describe 'User Snippets' do visit dashboard_snippets_path end - it 'View all of my snippets' do + it 'view all of my snippets' do expect(page).to have_link(public_snippet.title, href: snippet_path(public_snippet)) expect(page).to have_link(internal_snippet.title, href: snippet_path(internal_snippet)) expect(page).to have_link(private_snippet.title, href: snippet_path(private_snippet)) end - it 'View my public snippets' do + it 'view my public snippets' do page.within('.snippet-scope-menu') do click_link "Public" end @@ -29,7 +29,7 @@ RSpec.describe 'User Snippets' do expect(page).not_to have_content(private_snippet.title) end - it 'View my internal snippets' do + it 'view my internal snippets' do page.within('.snippet-scope-menu') do click_link "Internal" end @@ -39,7 +39,7 @@ RSpec.describe 'User Snippets' do expect(page).not_to have_content(private_snippet.title) end - it 'View my private snippets' do + it 'view my private snippets' do page.within('.snippet-scope-menu') do click_link "Private" end diff --git a/spec/features/usage_stats_consent_spec.rb b/spec/features/usage_stats_consent_spec.rb index 04bdf25acc0..6fa1d7d76b5 100644 --- a/spec/features/usage_stats_consent_spec.rb +++ b/spec/features/usage_stats_consent_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'Usage stats consent' do end gitlab_sign_in(user) + gitlab_enable_admin_mode_sign_in(user) end it 'hides the banner permanently when sets usage stats' do diff --git a/spec/features/users/active_sessions_spec.rb b/spec/features/users/active_sessions_spec.rb index 8e2e16e555e..fab9f0884ae 100644 --- a/spec/features/users/active_sessions_spec.rb +++ b/spec/features/users/active_sessions_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Active user sessions', :clean_gitlab_redis_shared_state do - it 'Successful login adds a new active user login' do + it 'successful login adds a new active user login' do now = Time.zone.parse('2018-03-12 09:06') Timecop.freeze(now) do user = create(:user) @@ -26,7 +26,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_shared_state do end end - it 'Successful login cleans up obsolete entries' do + it 'successful login cleans up obsolete entries' do user = create(:user) Gitlab::Redis::SharedState.with do |redis| @@ -40,7 +40,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_shared_state do end end - it 'Sessionless login does not clean up obsolete entries' do + it 'sessionless login does not clean up obsolete entries' do user = create(:user) personal_access_token = create(:personal_access_token, user: user) @@ -56,7 +56,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_shared_state do end end - it 'Logout deletes the active user login' do + it 'logout deletes the active user login' do user = create(:user) gitlab_sign_in(user) expect(current_path).to eq root_path diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index 0761c1871d3..e4a8d836413 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -742,28 +742,65 @@ RSpec.describe 'Login' do end context 'when the user did not enable 2FA' do - it 'asks to set 2FA before asking to accept the terms' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) + context 'when `vue_2fa_recovery_codes` feature flag is disabled' do + before do + stub_feature_flags(vue_2fa_recovery_codes: false) + end - visit new_user_session_path + it 'asks to set 2FA before asking to accept the terms' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) - fill_in 'user_login', with: user.email - fill_in 'user_password', with: '12345678' + visit new_user_session_path - click_button 'Sign in' + fill_in 'user_login', with: user.email + fill_in 'user_password', with: '12345678' - expect_to_be_on_terms_page - click_button 'Accept terms' + click_button 'Sign in' + + expect_to_be_on_terms_page + click_button 'Accept terms' + + expect(current_path).to eq(profile_two_factor_auth_path) + + fill_in 'pin_code', with: user.reload.current_otp - expect(current_path).to eq(profile_two_factor_auth_path) + click_button 'Register with two-factor app' - fill_in 'pin_code', with: user.reload.current_otp + expect(page).to have_content('Congratulations! You have enabled Two-factor Authentication!') - click_button 'Register with two-factor app' - click_link 'Proceed' + click_link 'Proceed' - expect(current_path).to eq(profile_account_path) + expect(current_path).to eq(profile_account_path) + end + end + + context 'when `vue_2fa_recovery_codes` feature flag is enabled' do + it 'asks to set 2FA before asking to accept the terms', :js do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + + visit new_user_session_path + + fill_in 'user_login', with: user.email + fill_in 'user_password', with: '12345678' + + click_button 'Sign in' + + expect_to_be_on_terms_page + click_button 'Accept terms' + + expect(current_path).to eq(profile_two_factor_auth_path) + + fill_in 'pin_code', with: user.reload.current_otp + + click_button 'Register with two-factor app' + click_button 'Copy codes' + click_link 'Proceed' + + expect(current_path).to eq(profile_account_path) + expect(page).to have_content('Congratulations! You have enabled Two-factor Authentication!') + end end end diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb index aebe2cc602d..6aeb3023db8 100644 --- a/spec/features/users/show_spec.rb +++ b/spec/features/users/show_spec.rb @@ -7,7 +7,7 @@ RSpec.describe 'User page' do let_it_be(:user) { create(:user, bio: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') } - subject { visit(user_path(user)) } + subject(:visit_profile) { visit(user_path(user)) } context 'with public profile' do it 'shows all the tabs' do @@ -123,6 +123,47 @@ RSpec.describe 'User page' do end end + context 'with unconfirmed user' do + let_it_be(:user) { create(:user, :unconfirmed) } + + shared_examples 'unconfirmed user profile' do + before do + visit_profile + end + + it 'shows user name as unconfirmed' do + expect(page).to have_css(".cover-title", text: 'Unconfirmed user') + end + + it 'shows no tab' do + expect(page).to have_css("div.profile-header") + expect(page).not_to have_css("ul.nav-links") + end + + it 'shows no additional fields' do + expect(page).not_to have_css(".profile-user-bio") + expect(page).not_to have_css(".profile-link-holder") + end + + it 'shows private profile message' do + expect(page).to have_content("This user has a private profile") + end + end + + context 'when visited by an authenticated user' do + before do + authenticated_user = create(:user) + sign_in(authenticated_user) + end + + it_behaves_like 'unconfirmed user profile' + end + + context 'when visited by an unauthenticated user' do + it_behaves_like 'unconfirmed user profile' + end + end + it 'shows the status if there was one' do create(:user_status, user: user, message: "Working hard!") |