diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-19 18:15:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-19 18:15:54 +0300 |
commit | a4bc9e75d8078f37e9c196333a3a1484e97d6a71 (patch) | |
tree | afa40a4da70aaa3715a9e5f104ec9a36f15aede9 /spec/features | |
parent | a4db97517ad095914c0652a07486ac607d99dab4 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/features')
-rw-r--r-- | spec/features/admin/admin_appearance_spec.rb | 287 | ||||
-rw-r--r-- | spec/features/admin/admin_mode/login_spec.rb | 366 | ||||
-rw-r--r-- | spec/features/projects/work_items/linked_work_items_spec.rb | 54 | ||||
-rw-r--r-- | spec/features/users/signup_spec.rb | 501 |
4 files changed, 590 insertions, 618 deletions
diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 71c904b3a19..2a9bff55dce 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -10,189 +10,180 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do stub_feature_flags(edit_user_profile_vue: false) end - flag_values = [true, false] - flag_values.each do |val| - context "with #{val}" do - before do - stub_feature_flags(restyle_login_page: val) - end + it 'create new appearance' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path + + fill_in 'appearance_title', with: 'MyCompany' + fill_in 'appearance_description', with: 'dev server' + fill_in 'appearance_pwa_name', with: 'GitLab PWA' + fill_in 'appearance_pwa_short_name', with: 'GitLab' + fill_in 'appearance_pwa_description', with: 'GitLab as PWA' + fill_in 'appearance_new_project_guidelines', with: 'Custom project guidelines' + fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines' + click_button 'Update appearance settings' + + expect(page).to have_current_path admin_application_settings_appearances_path, ignore_query: true + expect(page).to have_content 'Appearance' + + expect(page).to have_field('appearance_title', with: 'MyCompany') + expect(page).to have_field('appearance_description', with: 'dev server') + expect(page).to have_field('appearance_pwa_name', with: 'GitLab PWA') + expect(page).to have_field('appearance_pwa_short_name', with: 'GitLab') + expect(page).to have_field('appearance_pwa_description', with: 'GitLab as PWA') + expect(page).to have_field('appearance_new_project_guidelines', with: 'Custom project guidelines') + expect(page).to have_field('appearance_profile_image_guidelines', with: 'Custom profile image guidelines') + expect(page).to have_content 'Last edit' + end - it 'create new appearance' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + it 'preview sign-in page appearance' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) - fill_in 'appearance_title', with: 'MyCompany' - fill_in 'appearance_description', with: 'dev server' - fill_in 'appearance_pwa_name', with: 'GitLab PWA' - fill_in 'appearance_pwa_short_name', with: 'GitLab' - fill_in 'appearance_pwa_description', with: 'GitLab as PWA' - fill_in 'appearance_new_project_guidelines', with: 'Custom project guidelines' - fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines' - click_button 'Update appearance settings' - - expect(page).to have_current_path admin_application_settings_appearances_path, ignore_query: true - expect(page).to have_content 'Appearance' - - expect(page).to have_field('appearance_title', with: 'MyCompany') - expect(page).to have_field('appearance_description', with: 'dev server') - expect(page).to have_field('appearance_pwa_name', with: 'GitLab PWA') - expect(page).to have_field('appearance_pwa_short_name', with: 'GitLab') - expect(page).to have_field('appearance_pwa_description', with: 'GitLab as PWA') - expect(page).to have_field('appearance_new_project_guidelines', with: 'Custom project guidelines') - expect(page).to have_field('appearance_profile_image_guidelines', with: 'Custom profile image guidelines') - expect(page).to have_content 'Last edit' - end + visit admin_application_settings_appearances_path + click_link "Sign-in page" - it 'preview sign-in page appearance' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) + expect(find('#login')).to be_disabled + expect(find('#password')).to be_disabled + expect(find('button')).to be_disabled - visit admin_application_settings_appearances_path - click_link "Sign-in page" + expect_custom_sign_in_appearance(appearance) + end - expect(find('#login')).to be_disabled - expect(find('#password')).to be_disabled - expect(find('button')).to be_disabled + it 'preview new project page appearance', :js do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) - expect_custom_sign_in_appearance(appearance) - end + visit admin_application_settings_appearances_path + click_link "New project page" + + expect_custom_new_project_appearance(appearance) + end - it 'preview new project page appearance', :js do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) + context 'Custom system header and footer' do + before do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + end + context 'when system header and footer messages are empty' do + it 'shows custom system header and footer fields' do visit admin_application_settings_appearances_path - click_link "New project page" - expect_custom_new_project_appearance(appearance) + expect(page).to have_field('appearance_header_message', with: '') + expect(page).to have_field('appearance_footer_message', with: '') + expect(page).to have_field('appearance_message_background_color') + expect(page).to have_field('appearance_message_font_color') end + end - context 'Custom system header and footer' do - before do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - end - - context 'when system header and footer messages are empty' do - it 'shows custom system header and footer fields' do - visit admin_application_settings_appearances_path - - expect(page).to have_field('appearance_header_message', with: '') - expect(page).to have_field('appearance_footer_message', with: '') - expect(page).to have_field('appearance_message_background_color') - expect(page).to have_field('appearance_message_font_color') - end - end - - context 'when system header and footer messages are not empty' do - before do - appearance.update!(header_message: 'Foo', footer_message: 'Bar') - end - - it 'shows custom system header and footer fields' do - visit admin_application_settings_appearances_path - - expect(page).to have_field('appearance_header_message', with: appearance.header_message) - expect(page).to have_field('appearance_footer_message', with: appearance.footer_message) - expect(page).to have_field('appearance_message_background_color') - expect(page).to have_field('appearance_message_font_color') - end - end + context 'when system header and footer messages are not empty' do + before do + appearance.update!(header_message: 'Foo', footer_message: 'Bar') end - it 'custom sign-in page' do - visit new_user_session_path + it 'shows custom system header and footer fields' do + visit admin_application_settings_appearances_path - expect_custom_sign_in_appearance(appearance) + expect(page).to have_field('appearance_header_message', with: appearance.header_message) + expect(page).to have_field('appearance_footer_message', with: appearance.footer_message) + expect(page).to have_field('appearance_message_background_color') + expect(page).to have_field('appearance_message_font_color') end + end + end - it 'custom new project page', :js do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit new_project_path - click_link 'Create blank project' + it 'custom sign-in page' do + visit new_user_session_path - expect_custom_new_project_appearance(appearance) - end + expect_custom_sign_in_appearance(appearance) + end - context 'Profile page with custom profile image guidelines' do - before do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path - fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!' - click_button 'Update appearance settings' - end - - it 'renders guidelines when set' do - sign_in create(:user) - visit profile_path - - expect(page).to have_content 'Custom profile image guidelines, please 😄!' - end - end + it 'custom new project page', :js do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit new_project_path + click_link 'Create blank project' - it 'appearance logo' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + expect_custom_new_project_appearance(appearance) + end - attach_file(:appearance_logo, logo_fixture) - click_button 'Update appearance settings' - expect(page).to have_css(logo_selector) + context 'Profile page with custom profile image guidelines' do + before do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path + fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!' + click_button 'Update appearance settings' + end - click_link 'Remove logo' - expect(page).not_to have_css(logo_selector) - end + it 'renders guidelines when set' do + sign_in create(:user) + visit profile_path - it 'appearance pwa icon' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + expect(page).to have_content 'Custom profile image guidelines, please 😄!' + end + end - attach_file(:appearance_pwa_icon, logo_fixture) - click_button 'Update appearance settings' - expect(page).to have_css(pwa_icon_selector) + it 'appearance logo' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - click_link 'Remove icon' - expect(page).not_to have_css(pwa_icon_selector) - end + attach_file(:appearance_logo, logo_fixture) + click_button 'Update appearance settings' + expect(page).to have_css(logo_selector) - it 'header logos' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + click_link 'Remove logo' + expect(page).not_to have_css(logo_selector) + end - attach_file(:appearance_header_logo, logo_fixture) - click_button 'Update appearance settings' - expect(page).to have_css(header_logo_selector) + it 'appearance pwa icon' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - click_link 'Remove header logo' - expect(page).not_to have_css(header_logo_selector) - end + attach_file(:appearance_pwa_icon, logo_fixture) + click_button 'Update appearance settings' + expect(page).to have_css(pwa_icon_selector) - it 'Favicon' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + click_link 'Remove icon' + expect(page).not_to have_css(pwa_icon_selector) + end - attach_file(:appearance_favicon, logo_fixture) - click_button 'Update appearance settings' + it 'header logos' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - expect(page).to have_css('.appearance-light-logo-preview') + attach_file(:appearance_header_logo, logo_fixture) + click_button 'Update appearance settings' + expect(page).to have_css(header_logo_selector) - click_link 'Remove favicon' + click_link 'Remove header logo' + expect(page).not_to have_css(header_logo_selector) + end - expect(page).not_to have_css('.appearance-light-logo-preview') + it 'Favicon' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - # allowed file types - attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg')) - click_button 'Update appearance settings' + attach_file(:appearance_favicon, logo_fixture) + click_button 'Update appearance settings' - expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, ico' - end - end + expect(page).to have_css('.appearance-light-logo-preview') + + click_link 'Remove favicon' + + expect(page).not_to have_css('.appearance-light-logo-preview') + + # allowed file types + attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg')) + click_button 'Update appearance settings' + + expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, ico' end def expect_custom_sign_in_appearance(appearance) diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb index f2262464386..5e4935ee4b1 100644 --- a/spec/features/admin/admin_mode/login_spec.rb +++ b/spec/features/admin/admin_mode/login_spec.rb @@ -13,256 +13,248 @@ RSpec.describe 'Admin Mode Login', feature_category: :system_access do click_button 'Verify code' end - flag_values = [true, false] - flag_values.each do |val| - context "with #{val}" do - before do - stub_feature_flags(restyle_login_page: val) - end - context 'with valid username/password' do - let(:user) { create(:admin, :two_factor) } + context 'with valid username/password' do + let(:user) { create(:admin, :two_factor) } - context 'using one-time code' do - it 'blocks login if we reuse the same code immediately' do - gitlab_sign_in(user, remember: true) + context 'using one-time code' do + it 'blocks login if we reuse the same code immediately' do + gitlab_sign_in(user, remember: true) - expect(page).to have_content(_('Enter verification code')) + expect(page).to have_content(_('Enter verification code')) - repeated_otp = user.current_otp - enter_code(repeated_otp) - gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: false) + repeated_otp = user.current_otp + enter_code(repeated_otp) + gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: false) - expect(page).to have_content(_('Enter verification code')) + expect(page).to have_content(_('Enter verification code')) - enter_code(repeated_otp) + enter_code(repeated_otp) - expect(page).to have_current_path admin_session_path, ignore_query: true - expect(page).to have_content('Invalid two-factor code') - end + expect(page).to have_current_path admin_session_path, ignore_query: true + expect(page).to have_content('Invalid two-factor code') + end - context 'not re-using codes' do - before do - gitlab_sign_in(user, remember: true) + context 'not re-using codes' do + before do + gitlab_sign_in(user, remember: true) - expect(page).to have_content('Enter verification code') + expect(page).to have_content('Enter verification code') - enter_code(user.current_otp) - gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: false) + enter_code(user.current_otp) + gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: false) - expect(page).to have_content(_('Enter verification code')) - end + expect(page).to have_content(_('Enter verification code')) + end - it 'allows login with valid code' do - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code(user.current_otp) + it 'allows login with valid code' do + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') - end - end + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end + end - it 'blocks login with invalid code' do - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code('foo') + it 'blocks login with invalid code' do + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code('foo') - expect(page).to have_content('Invalid two-factor code') - end - end + expect(page).to have_content('Invalid two-factor code') + end + end - it 'allows login with invalid code, then valid code' do - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code('foo') + it 'allows login with invalid code, then valid code' do + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code('foo') - expect(page).to have_content('Invalid two-factor code') + expect(page).to have_content('Invalid two-factor code') - enter_code(user.current_otp) + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') - end - end + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end + end - context 'using backup code' do - let(:codes) { user.generate_otp_backup_codes! } + context 'using backup code' do + let(:codes) { user.generate_otp_backup_codes! } - before do - expect(codes.size).to eq 10 + before do + expect(codes.size).to eq 10 - # Ensure the generated codes get saved - user.save! - end + # Ensure the generated codes get saved + user.save! + end - context 'with valid code' do - it 'allows login' do - enter_code(codes.sample) + context 'with valid code' do + it 'allows login' do + enter_code(codes.sample) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') - end + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end - it 'invalidates the used code' do - expect { enter_code(codes.sample) } - .to change { user.reload.otp_backup_codes.size }.by(-1) - end - end + it 'invalidates the used code' do + expect { enter_code(codes.sample) } + .to change { user.reload.otp_backup_codes.size }.by(-1) + end + end - context 'with invalid code' do - it 'blocks login' do - code = codes.sample - expect(user.invalidate_otp_backup_code!(code)).to eq true + context 'with invalid code' do + it 'blocks login' do + code = codes.sample + expect(user.invalidate_otp_backup_code!(code)).to eq true - user.save! - expect(user.reload.otp_backup_codes.size).to eq 9 + user.save! + expect(user.reload.otp_backup_codes.size).to eq 9 - enter_code(code) + enter_code(code) - expect(page).to have_content('Invalid two-factor code.') - end - end + expect(page).to have_content('Invalid two-factor code.') end end end + end + end - context 'when logging in via omniauth' do - let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: 'my-uid', provider: 'saml', password_automatically_set: false) } - let(:mock_saml_response) do - File.read('spec/fixtures/authentication/saml_response.xml') - end + context 'when logging in via omniauth' do + let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: 'my-uid', provider: 'saml', password_automatically_set: false) } + let(:mock_saml_response) do + File.read('spec/fixtures/authentication/saml_response.xml') + end - before do - stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config_with_upstream_two_factor_authn_contexts]) - end + before do + stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config_with_upstream_two_factor_authn_contexts]) + end - context 'when authn_context is worth two factors' do - let(:mock_saml_response) do - File.read('spec/fixtures/authentication/saml_response.xml') - .gsub( - 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password', - 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS' - ) - end + context 'when authn_context is worth two factors' do + let(:mock_saml_response) do + File.read('spec/fixtures/authentication/saml_response.xml') + .gsub( + 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password', + 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS' + ) + end - it 'signs user in without prompting for second factor' do - sign_in_using_saml! + it 'signs user in without prompting for second factor' do + sign_in_using_saml! - expect(page).not_to have_content(_('Enter verification code')) + expect(page).not_to have_content(_('Enter verification code')) - enable_admin_mode_using_saml! + enable_admin_mode_using_saml! - expect(page).not_to have_content(_('Enter verification code')) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') - end - end + expect(page).not_to have_content(_('Enter verification code')) + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end + end - context 'when two factor authentication is required' do - it 'shows 2FA prompt after omniauth login' do - sign_in_using_saml! + context 'when two factor authentication is required' do + it 'shows 2FA prompt after omniauth login' do + sign_in_using_saml! - expect(page).to have_content(_('Enter verification code')) - enter_code(user.current_otp) + expect(page).to have_content(_('Enter verification code')) + enter_code(user.current_otp) - enable_admin_mode_using_saml! + enable_admin_mode_using_saml! - expect(page).to have_content(_('Enter verification code')) + expect(page).to have_content(_('Enter verification code')) - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code(user.current_otp) + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') - end - end + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') end + end + end - def sign_in_using_saml! - gitlab_sign_in_via('saml', user, 'my-uid', mock_saml_response) - end + def sign_in_using_saml! + gitlab_sign_in_via('saml', user, 'my-uid', mock_saml_response) + end - def enable_admin_mode_using_saml! - gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response) - end - end + def enable_admin_mode_using_saml! + gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response) + end + end - context 'when logging in via ldap' do - let(:uid) { 'my-uid' } - let(:provider_label) { 'Main LDAP' } - let(:provider_name) { 'main' } - let(:provider) { "ldap#{provider_name}" } - let(:ldap_server_config) do - { - 'label' => provider_label, - 'provider_name' => provider, - 'attributes' => {}, - 'encryption' => 'plain', - 'uid' => 'uid', - 'base' => 'dc=example,dc=com' - } - end + context 'when logging in via ldap' do + let(:uid) { 'my-uid' } + let(:provider_label) { 'Main LDAP' } + let(:provider_name) { 'main' } + let(:provider) { "ldap#{provider_name}" } + let(:ldap_server_config) do + { + 'label' => provider_label, + 'provider_name' => provider, + 'attributes' => {}, + 'encryption' => 'plain', + 'uid' => 'uid', + 'base' => 'dc=example,dc=com' + } + end - let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) } + let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) } - before do - setup_ldap(provider, user, uid, ldap_server_config) - end + before do + setup_ldap(provider, user, uid, ldap_server_config) + end - context 'when two factor authentication is required' do - it 'shows 2FA prompt after ldap login' do - sign_in_using_ldap!(user, provider_label) - expect(page).to have_content(_('Enter verification code')) + context 'when two factor authentication is required' do + it 'shows 2FA prompt after ldap login' do + sign_in_using_ldap!(user, provider_label) + expect(page).to have_content(_('Enter verification code')) - enter_code(user.current_otp) - enable_admin_mode_using_ldap!(user) + enter_code(user.current_otp) + enable_admin_mode_using_ldap!(user) - expect(page).to have_content(_('Enter verification code')) + expect(page).to have_content(_('Enter verification code')) - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code(user.current_otp) + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') - end - end + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') end + end + end - def setup_ldap(provider, user, uid, ldap_server_config) - stub_ldap_setting(enabled: true) + def setup_ldap(provider, user, uid, ldap_server_config) + stub_ldap_setting(enabled: true) - allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config]) - allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym]) + allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config]) + allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym]) - Ldap::OmniauthCallbacksController.define_providers! - Rails.application.reload_routes! + Ldap::OmniauthCallbacksController.define_providers! + Rails.application.reload_routes! - mock_auth_hash(provider, uid, user.email) - allow(Gitlab::Auth::Ldap::Access).to receive(:allowed?).with(user).and_return(true) + mock_auth_hash(provider, uid, user.email) + allow(Gitlab::Auth::Ldap::Access).to receive(:allowed?).with(user).and_return(true) - allow_any_instance_of(ActionDispatch::Routing::RoutesProxy) - .to receive(:"user_#{provider}_omniauth_callback_path") - .and_return("/users/auth/#{provider}/callback") - end + allow_any_instance_of(ActionDispatch::Routing::RoutesProxy) + .to receive(:"user_#{provider}_omniauth_callback_path") + .and_return("/users/auth/#{provider}/callback") + end - def sign_in_using_ldap!(user, provider_label) - visit new_user_session_path - click_link provider_label - fill_in 'username', with: user.username - fill_in 'password', with: user.password - click_button 'Sign in' - end + def sign_in_using_ldap!(user, provider_label) + visit new_user_session_path + click_link provider_label + fill_in 'username', with: user.username + fill_in 'password', with: user.password + click_button 'Sign in' + end - def enable_admin_mode_using_ldap!(user) - visit new_admin_session_path - click_link provider_label - fill_in 'username', with: user.username - fill_in 'password', with: user.password - click_button 'Enter admin mode' - end - end + def enable_admin_mode_using_ldap!(user) + visit new_admin_session_path + click_link provider_label + fill_in 'username', with: user.username + fill_in 'password', with: user.password + click_button 'Enter admin mode' end end end diff --git a/spec/features/projects/work_items/linked_work_items_spec.rb b/spec/features/projects/work_items/linked_work_items_spec.rb index 49f723c3055..963be23e5a8 100644 --- a/spec/features/projects/work_items/linked_work_items_spec.rb +++ b/spec/features/projects/work_items/linked_work_items_spec.rb @@ -11,6 +11,8 @@ RSpec.describe 'Work item linked items', :js, feature_category: :team_planning d let_it_be(:task) { create(:work_item, :task, project: project, title: 'Task 1') } context 'for signed in user' do + let(:token_input_selector) { '[data-testid="work-item-token-select-input"] .gl-token-selector-input' } + before_all do project.add_developer(user) end @@ -62,25 +64,24 @@ RSpec.describe 'Work item linked items', :js, feature_category: :team_planning d end end - it 'links a new item', :aggregate_failures do - page.within('.work-item-relationships') do - click_button 'Add' - - within_testid('link-work-item-form') do - expect(page).to have_button('Add', disabled: true) - find_by_testid('work-item-token-select-input').set(task.title) - wait_for_all_requests - click_button task.title + it 'links a new item with work item text', :aggregate_failures do + verify_linked_item_added(task.title) + end - expect(page).to have_button('Add', disabled: false) + it 'links a new item with work item iid', :aggregate_failures do + verify_linked_item_added(task.iid) + end - click_button 'Add' + it 'links a new item with work item wildcard iid', :aggregate_failures do + verify_linked_item_added("##{task.iid}") + end - wait_for_all_requests - end + it 'links a new item with work item reference', :aggregate_failures do + verify_linked_item_added(task.to_reference(full: true)) + end - expect(find('.work-items-list')).to have_content('Task 1') - end + it 'links a new item with work item url', :aggregate_failures do + verify_linked_item_added("#{task.project.web_url}/-/work_items/#{task.iid}") end it 'removes a linked item', :aggregate_failures do @@ -111,4 +112,27 @@ RSpec.describe 'Work item linked items', :js, feature_category: :team_planning d end end end + + def verify_linked_item_added(input) + page.within('.work-item-relationships') do + click_button 'Add' + + within_testid('link-work-item-form') do + expect(page).to have_button('Add', disabled: true) + + find(token_input_selector).set(input) + wait_for_all_requests + + click_button task.title + + expect(page).to have_button('Add', disabled: false) + + click_button 'Add' + + wait_for_all_requests + end + + expect(find('.work-items-list')).to have_content('Task 1') + end + end end diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index bb08ed7d07d..6f13dfa08cc 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -3,54 +3,40 @@ require 'spec_helper' RSpec.shared_examples 'Signup name validation' do |field, max_length, label| - shared_examples 'signup validation' do - before do - visit new_user_registration_path - end - - describe "#{field} validation" do - it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do - fill_in field, with: 'u' * max_length - - expect(find('.name')).not_to have_css '.gl-field-error-outline' - end + before do + visit new_user_registration_path + end - it 'shows an error border if the user\'s fullname contains an emoji' do - simulate_input("##{field}", 'Ehsan 🦋') + describe "#{field} validation" do + it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do + fill_in field, with: 'u' * max_length - expect(find('.name')).to have_css '.gl-field-error-outline' - end + expect(find('.name')).not_to have_css '.gl-field-error-outline' + end - it "shows an error border if the user\'s fullname is longer than #{max_length} characters" do - fill_in field, with: 'n' * (max_length + 1) + it 'shows an error border if the user\'s fullname contains an emoji' do + simulate_input("##{field}", 'Ehsan 🦋') - expect(find('.name')).to have_css '.gl-field-error-outline' - end + expect(find('.name')).to have_css '.gl-field-error-outline' + end - it "shows an error message if the user\'s #{label} is longer than #{max_length} characters" do - fill_in field, with: 'n' * (max_length + 1) + it "shows an error border if the user\'s fullname is longer than #{max_length} characters" do + fill_in field, with: 'n' * (max_length + 1) - expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).") - end + expect(find('.name')).to have_css '.gl-field-error-outline' + end - it 'shows an error message if the username contains emojis' do - simulate_input("##{field}", 'Ehsan 🦋') + it "shows an error message if the user\'s #{label} is longer than #{max_length} characters" do + fill_in field, with: 'n' * (max_length + 1) - expect(page).to have_content("Invalid input, please avoid emoji") - end + expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).") end - end - include_examples 'signup validation' + it 'shows an error message if the username contains emojis' do + simulate_input("##{field}", 'Ehsan 🦋') - # Inline `shared_example 'signup validation'` again after feature flag - # `restyle_login_page` was removed. - context 'with feature flag restyle_login_page disabled' do - before do - stub_feature_flags(restyle_login_page: false) + expect(page).to have_content("Invalid input, please avoid emoji") end - - include_examples 'signup validation' end end @@ -66,344 +52,323 @@ RSpec.describe 'Signup', :js, feature_category: :user_management do TEXT end - shared_examples 'signup process' do + before do + stub_feature_flags(arkose_labs_signup_challenge: false) + stub_application_setting(require_admin_approval_after_user_signup: false) + end + + describe 'username validation' do before do - stub_feature_flags(arkose_labs_signup_challenge: false) - stub_application_setting(require_admin_approval_after_user_signup: false) + visit new_user_registration_path end - describe 'username validation' do - before do - visit new_user_registration_path - end + it 'does not show an error border if the username is available' do + fill_in 'new_user_username', with: 'new-user' + wait_for_requests - it 'does not show an error border if the username is available' do - fill_in 'new_user_username', with: 'new-user' - wait_for_requests + expect(find('.username')).not_to have_css '.gl-field-error-outline' + end - expect(find('.username')).not_to have_css '.gl-field-error-outline' - end + it 'does not show an error border if the username contains dots (.)' do + simulate_input('#new_user_username', 'new.user.username') + wait_for_requests - it 'does not show an error border if the username contains dots (.)' do - simulate_input('#new_user_username', 'new.user.username') - wait_for_requests + expect(find('.username')).not_to have_css '.gl-field-error-outline' + end - expect(find('.username')).not_to have_css '.gl-field-error-outline' - end + it 'does not show an error border if the username length is not longer than 255 characters' do + fill_in 'new_user_username', with: 'u' * 255 + wait_for_requests - it 'does not show an error border if the username length is not longer than 255 characters' do - fill_in 'new_user_username', with: 'u' * 255 - wait_for_requests + expect(find('.username')).not_to have_css '.gl-field-error-outline' + end - expect(find('.username')).not_to have_css '.gl-field-error-outline' - end + it 'shows an error border if the username already exists' do + existing_user = create(:user) - it 'shows an error border if the username already exists' do - existing_user = create(:user) + fill_in 'new_user_username', with: existing_user.username + wait_for_requests - fill_in 'new_user_username', with: existing_user.username - wait_for_requests + expect(find('.username')).to have_css '.gl-field-error-outline' + end - expect(find('.username')).to have_css '.gl-field-error-outline' - end + it 'shows a success border if the username is available' do + fill_in 'new_user_username', with: 'new-user' + wait_for_requests - it 'shows a success border if the username is available' do - fill_in 'new_user_username', with: 'new-user' - wait_for_requests + expect(find('.username')).to have_css '.gl-field-success-outline' + end - expect(find('.username')).to have_css '.gl-field-success-outline' - end + it 'shows an error border if the username contains special characters' do + fill_in 'new_user_username', with: 'new$user!username' + wait_for_requests - it 'shows an error border if the username contains special characters' do - fill_in 'new_user_username', with: 'new$user!username' - wait_for_requests + expect(find('.username')).to have_css '.gl-field-error-outline' + end - expect(find('.username')).to have_css '.gl-field-error-outline' - end + it 'shows an error border if the username is longer than 255 characters' do + fill_in 'new_user_username', with: 'u' * 256 + wait_for_requests - it 'shows an error border if the username is longer than 255 characters' do - fill_in 'new_user_username', with: 'u' * 256 - wait_for_requests + expect(find('.username')).to have_css '.gl-field-error-outline' + end - expect(find('.username')).to have_css '.gl-field-error-outline' - end + it 'shows an error message if the username is longer than 255 characters' do + fill_in 'new_user_username', with: 'u' * 256 + wait_for_requests - it 'shows an error message if the username is longer than 255 characters' do - fill_in 'new_user_username', with: 'u' * 256 - wait_for_requests + expect(page).to have_content("Username is too long (maximum is 255 characters).") + end - expect(page).to have_content("Username is too long (maximum is 255 characters).") - end + it 'shows an error message if the username is less than 2 characters' do + fill_in 'new_user_username', with: 'u' + wait_for_requests - it 'shows an error message if the username is less than 2 characters' do - fill_in 'new_user_username', with: 'u' - wait_for_requests + expect(page).to have_content("Username is too short (minimum is 2 characters).") + end - expect(page).to have_content("Username is too short (minimum is 2 characters).") - end + it 'shows an error message on submit if the username contains special characters' do + fill_in 'new_user_username', with: 'new$user!username' + wait_for_requests - it 'shows an error message on submit if the username contains special characters' do - fill_in 'new_user_username', with: 'new$user!username' - wait_for_requests + click_button "Register" - click_button "Register" + expect(page).to have_content("Please create a username with only alphanumeric characters.") + end - expect(page).to have_content("Please create a username with only alphanumeric characters.") - end + it 'shows an error border if the username contains emojis' do + simulate_input('#new_user_username', 'ehsan😀') - it 'shows an error border if the username contains emojis' do - simulate_input('#new_user_username', 'ehsan😀') + expect(find('.username')).to have_css '.gl-field-error-outline' + end - expect(find('.username')).to have_css '.gl-field-error-outline' - end + it 'shows an error message if the username contains emojis' do + simulate_input('#new_user_username', 'ehsan😀') - it 'shows an error message if the username contains emojis' do - simulate_input('#new_user_username', 'ehsan😀') + expect(page).to have_content("Invalid input, please avoid emoji") + end - expect(page).to have_content("Invalid input, please avoid emoji") - end + it 'shows a pending message if the username availability is being fetched', + quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/31484' do + fill_in 'new_user_username', with: 'new-user' - it 'shows a pending message if the username availability is being fetched', - quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/31484' do - fill_in 'new_user_username', with: 'new-user' + expect(find('.username > .validation-pending')).not_to have_css '.hide' + end - expect(find('.username > .validation-pending')).not_to have_css '.hide' - end + it 'shows a success message if the username is available' do + fill_in 'new_user_username', with: 'new-user' + wait_for_requests - it 'shows a success message if the username is available' do - fill_in 'new_user_username', with: 'new-user' - wait_for_requests + expect(find('.username > .validation-success')).not_to have_css '.hide' + end - expect(find('.username > .validation-success')).not_to have_css '.hide' - end + it 'shows an error message if the username is unavailable' do + existing_user = create(:user) - it 'shows an error message if the username is unavailable' do - existing_user = create(:user) + fill_in 'new_user_username', with: existing_user.username + wait_for_requests - fill_in 'new_user_username', with: existing_user.username - wait_for_requests + expect(find('.username > .validation-error')).not_to have_css '.hide' + end - expect(find('.username > .validation-error')).not_to have_css '.hide' - end + it 'shows a success message if the username is corrected and then available' do + fill_in 'new_user_username', with: 'new-user$' + wait_for_requests + fill_in 'new_user_username', with: 'new-user' + wait_for_requests - it 'shows a success message if the username is corrected and then available' do - fill_in 'new_user_username', with: 'new-user$' - wait_for_requests - fill_in 'new_user_username', with: 'new-user' - wait_for_requests + expect(page).to have_content("Username is available.") + end + end - expect(page).to have_content("Username is available.") + context 'with no errors' do + context 'when sending confirmation email' do + before do + stub_application_setting_enum('email_confirmation_setting', 'hard') end - end - context 'with no errors' do - context 'when sending confirmation email' do + context 'when email confirmation setting is not `soft`' do before do - stub_application_setting_enum('email_confirmation_setting', 'hard') + stub_feature_flags(identity_verification: false) end - context 'when email confirmation setting is not `soft`' do - before do - stub_feature_flags(identity_verification: false) - end - - it 'creates the user account and sends a confirmation email, and pre-fills email address after confirming' do - visit new_user_registration_path - - expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1) - expect(page).to have_current_path users_almost_there_path, ignore_query: true - expect(page).to have_content("Please check your email (#{new_user.email}) to confirm your account") - - confirm_email(new_user) - - expect(find_field('Username or primary email').value).to eq(new_user.email) - end - end + it 'creates the user account and sends a confirmation email, and pre-fills email address after confirming' do + visit new_user_registration_path - context 'when email confirmation setting is `soft`' do - before do - stub_application_setting_enum('email_confirmation_setting', 'soft') - end + expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1) + expect(page).to have_current_path users_almost_there_path, ignore_query: true + expect(page).to have_content("Please check your email (#{new_user.email}) to confirm your account") - it 'creates the user account and sends a confirmation email' do - visit new_user_registration_path + confirm_email(new_user) - expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1) - expect(page).to have_current_path dashboard_projects_path - end + expect(find_field('Username or primary email').value).to eq(new_user.email) end end - context "when not sending confirmation email" do + context 'when email confirmation setting is `soft`' do before do - stub_application_setting_enum('email_confirmation_setting', 'off') + stub_application_setting_enum('email_confirmation_setting', 'soft') end - it 'creates the user account and goes to dashboard' do + it 'creates the user account and sends a confirmation email' do visit new_user_registration_path - fill_in_sign_up_form(new_user) - + expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1) expect(page).to have_current_path dashboard_projects_path end end + end - context 'with required admin approval enabled' do - before do - stub_application_setting(require_admin_approval_after_user_signup: true) - end + context "when not sending confirmation email" do + before do + stub_application_setting_enum('email_confirmation_setting', 'off') + end - it 'creates the user but does not sign them in' do - visit new_user_registration_path + it 'creates the user account and goes to dashboard' do + visit new_user_registration_path - expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1) - expect(page).to have_current_path new_user_session_path, ignore_query: true - expect(page).to have_content(<<~TEXT.squish) + fill_in_sign_up_form(new_user) + + expect(page).to have_current_path dashboard_projects_path + end + end + + context 'with required admin approval enabled' do + before do + stub_application_setting(require_admin_approval_after_user_signup: true) + end + + it 'creates the user but does not sign them in' do + visit new_user_registration_path + + expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1) + expect(page).to have_current_path new_user_session_path, ignore_query: true + expect(page).to have_content(<<~TEXT.squish) You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator - TEXT - end + TEXT end end + end - context 'with errors' do - it "displays the errors" do - create(:user, email: new_user.email) - visit new_user_registration_path + context 'with errors' do + it "displays the errors" do + create(:user, email: new_user.email) + visit new_user_registration_path - fill_in_sign_up_form(new_user) + fill_in_sign_up_form(new_user) - expect(page).to have_current_path user_registration_path, ignore_query: true - expect(page).to have_content("error prohibited this user from being saved") - expect(page).to have_content("Email has already been taken") - end + expect(page).to have_current_path user_registration_path, ignore_query: true + expect(page).to have_content("error prohibited this user from being saved") + expect(page).to have_content("Email has already been taken") + end - it 'redisplays all fields except password' do - create(:user, email: new_user.email) - visit new_user_registration_path + it 'redisplays all fields except password' do + create(:user, email: new_user.email) + visit new_user_registration_path - fill_in_sign_up_form(new_user) + fill_in_sign_up_form(new_user) - expect(page).to have_current_path user_registration_path, ignore_query: true - expect(page.body).not_to match(/#{new_user.password}/) + expect(page).to have_current_path user_registration_path, ignore_query: true + expect(page.body).not_to match(/#{new_user.password}/) - expect(find_field('First name').value).to eq(new_user.first_name) - expect(find_field('Last name').value).to eq(new_user.last_name) - expect(find_field('Username').value).to eq(new_user.username) - expect(find_field('Email').value).to eq(new_user.email) - end + expect(find_field('First name').value).to eq(new_user.first_name) + expect(find_field('Last name').value).to eq(new_user.last_name) + expect(find_field('Username').value).to eq(new_user.username) + expect(find_field('Email').value).to eq(new_user.email) end + end - context 'when terms are enforced' do - before do - enforce_terms - end + context 'when terms are enforced' do + before do + enforce_terms + end - it 'renders text that the user confirms terms by signing in' do - visit new_user_registration_path - expect(page).to have_content(terms_text) + it 'renders text that the user confirms terms by signing in' do + visit new_user_registration_path + expect(page).to have_content(terms_text) - fill_in_sign_up_form(new_user) + fill_in_sign_up_form(new_user) - expect(page).to have_current_path(dashboard_projects_path) - end + expect(page).to have_current_path(dashboard_projects_path) + end - it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name' - it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name' + it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name' + it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name' + end + + context 'when reCAPTCHA and invisible captcha are enabled' do + before do + stub_application_setting(invisible_captcha_enabled: true) + stub_application_setting(recaptcha_enabled: true) + allow_next_instance_of(RegistrationsController) do |instance| + allow(instance).to receive(:verify_recaptcha).and_return(true) + end end - context 'when reCAPTCHA and invisible captcha are enabled' do + context 'when reCAPTCHA detects malicious behaviour' do before do - stub_application_setting(invisible_captcha_enabled: true) - stub_application_setting(recaptcha_enabled: true) allow_next_instance_of(RegistrationsController) do |instance| - allow(instance).to receive(:verify_recaptcha).and_return(true) + allow(instance).to receive(:verify_recaptcha).and_return(false) end end - context 'when reCAPTCHA detects malicious behaviour' do - before do - allow_next_instance_of(RegistrationsController) do |instance| - allow(instance).to receive(:verify_recaptcha).and_return(false) - end - end + it 'prevents from signing up' do + visit new_user_registration_path + expect { fill_in_sign_up_form(new_user) }.not_to change { User.count } + expect(page).to have_content(_('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')) + expect(page).to have_content( + "Minimum length is #{Gitlab::CurrentSettings.minimum_password_length} characters") + end + end + + context 'when invisible captcha detects malicious behaviour' do + context 'with form submitted quicker than timestamp_threshold', :freeze_time do it 'prevents from signing up' do visit new_user_registration_path expect { fill_in_sign_up_form(new_user) }.not_to change { User.count } - expect(page).to have_content(_('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')) - expect(page).to have_content( - "Minimum length is #{Gitlab::CurrentSettings.minimum_password_length} characters") + expect(page).to have_content('That was a bit too quick! Please resubmit.') end end - context 'when invisible captcha detects malicious behaviour' do - context 'with form submitted quicker than timestamp_threshold', :freeze_time do - it 'prevents from signing up' do - visit new_user_registration_path - - expect { fill_in_sign_up_form(new_user) }.not_to change { User.count } - expect(page).to have_content('That was a bit too quick! Please resubmit.') - end - end - - context 'with honeypot field is filled' do - it 'prevents from signing up' do - visit new_user_registration_path + context 'with honeypot field is filled' do + it 'prevents from signing up' do + visit new_user_registration_path - find_field('If you are human, please ignore this field.', - visible: false).execute_script("this.value = 'bot'") + find_field('If you are human, please ignore this field.', + visible: false).execute_script("this.value = 'bot'") - expect { fill_in_sign_up_form(new_user) }.not_to change { User.count } - end + expect { fill_in_sign_up_form(new_user) }.not_to change { User.count } end end end + end - it 'allows visiting of a page after initial registration' do - visit new_user_registration_path - - fill_in_sign_up_form(new_user) + it 'allows visiting of a page after initial registration' do + visit new_user_registration_path - visit new_project_path + fill_in_sign_up_form(new_user) - expect(page).to have_current_path(new_project_path) - end + visit new_project_path - it 'does not redisplay the password' do - create(:user, email: new_user.email) - visit new_user_registration_path + expect(page).to have_current_path(new_project_path) + end - fill_in_sign_up_form(new_user) + it 'does not redisplay the password' do + create(:user, email: new_user.email) + visit new_user_registration_path - expect(page).to have_current_path user_registration_path, ignore_query: true - expect(page.body).not_to match(/#{new_user.password}/) - end + fill_in_sign_up_form(new_user) - context 'with invalid email' do - it_behaves_like 'user email validation' do - let(:path) { new_user_registration_path } - end - end + expect(page).to have_current_path user_registration_path, ignore_query: true + expect(page.body).not_to match(/#{new_user.password}/) end - include_examples 'signup process' - - # Inline `shared_example 'signup process'` again after feature flag - # `restyle_login_page` was removed. - context 'with feature flag restyle_login_page disabled' do - let(:terms_text) do - <<~TEXT.squish - By clicking Register, I agree that I have read and accepted the Terms of - Use and Privacy Statement - TEXT + context 'with invalid email' do + it_behaves_like 'user email validation' do + let(:path) { new_user_registration_path } end - - before do - stub_feature_flags(restyle_login_page: false) - end - - include_examples 'signup process' end end |