From 9f46488805e86b1bc341ea1620b866016c2ce5ed Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 20 May 2020 14:34:42 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-0-stable-ee --- spec/features/admin/admin_appearance_spec.rb | 18 ++ spec/features/admin/admin_browses_logs_spec.rb | 20 -- spec/features/admin/admin_hooks_spec.rb | 18 ++ spec/features/admin/admin_mode/login_spec.rb | 77 ++++++++ spec/features/admin/admin_settings_spec.rb | 40 ++-- .../admin/admin_users_impersonation_tokens_spec.rb | 4 +- spec/features/boards/boards_spec.rb | 54 ++++++ spec/features/boards/focus_mode_spec.rb | 17 ++ spec/features/boards/sidebar_spec.rb | 2 +- spec/features/commits/user_view_commits_spec.rb | 22 +++ spec/features/dashboard/help_spec.rb | 21 --- spec/features/dashboard/issues_spec.rb | 2 +- spec/features/dashboard/snippets_spec.rb | 43 +---- spec/features/dashboard/todos/todos_spec.rb | 42 ++++- .../user_filters_errors_by_status_spec.rb | 2 +- .../error_tracking/user_sees_error_index_spec.rb | 2 +- spec/features/explore/groups_spec.rb | 2 +- spec/features/global_search_spec.rb | 2 +- .../groups/import_export/export_file_spec.rb | 59 ++++++ spec/features/groups/issues_spec.rb | 23 ++- spec/features/groups/members/leave_group_spec.rb | 2 - spec/features/groups/members/manage_groups_spec.rb | 85 ++++----- ...master_adds_member_with_expiration_date_spec.rb | 68 +++++++ spec/features/groups/navbar_spec.rb | 52 ++++++ spec/features/groups_spec.rb | 36 ++++ spec/features/help_pages_spec.rb | 32 +--- .../features/issues/bulk_assignment_labels_spec.rb | 2 +- .../issues/filtered_search/filter_issues_spec.rb | 47 +++-- .../issues/filtered_search/visual_tokens_spec.rb | 18 +- spec/features/issues/spam_issues_spec.rb | 121 ++++++++++-- spec/features/issues/update_issues_spec.rb | 2 +- .../user_creates_branch_and_merge_request_spec.rb | 12 +- .../user_sees_sidebar_updates_in_realtime_spec.rb | 32 ++++ spec/features/markdown/copy_as_gfm_spec.rb | 6 + spec/features/markdown/metrics_spec.rb | 2 +- .../merge_request/maintainer_edits_fork_spec.rb | 2 +- .../user_interacts_with_batched_mr_diffs_spec.rb | 2 +- .../merge_request/user_posts_diff_notes_spec.rb | 4 +- .../merge_request/user_posts_notes_spec.rb | 5 +- .../merge_request/user_resolves_conflicts_spec.rb | 4 +- ...lves_diff_notes_and_discussions_resolve_spec.rb | 54 +++--- .../user_sees_notes_from_forked_project_spec.rb | 1 + .../merge_requests/user_mass_updates_spec.rb | 2 +- .../milestones/user_creates_milestone_spec.rb | 6 +- .../milestones/user_views_milestone_spec.rb | 6 +- spec/features/profiles/emails_spec.rb | 11 +- .../profiles/personal_access_tokens_spec.rb | 4 +- .../activity/user_sees_design_comment_spec.rb | 51 ++++++ .../projects/branches/user_creates_branch_spec.rb | 10 +- .../commit/comments/user_edits_comments_spec.rb | 6 +- .../projects/environments_pod_logs_spec.rb | 2 +- .../projects/files/user_browses_files_spec.rb | 39 ++++ spec/features/projects/graph_spec.rb | 2 +- .../projects/import_export/export_file_spec.rb | 4 +- .../user_paginates_designs_spec.rb | 40 ++++ .../user_permissions_upload_spec.rb | 24 +++ .../design_management/user_uploads_designs_spec.rb | 63 +++++++ .../user_views_design_images_spec.rb | 41 +++++ .../design_management/user_views_design_spec.rb | 29 +++ .../design_management/user_views_designs_spec.rb | 47 +++++ .../user_views_designs_with_svg_xss_spec.rb | 55 ++++++ spec/features/projects/members/list_spec.rb | 19 +- spec/features/projects/navbar_spec.rb | 21 ++- spec/features/projects/pipelines/pipeline_spec.rb | 72 ++++++-- .../features/projects/serverless/functions_spec.rb | 2 +- .../projects/services/disable_triggers_spec.rb | 10 +- .../services/prometheus_external_alerts_spec.rb | 20 +- .../services/user_activates_issue_tracker_spec.rb | 59 ++---- .../projects/services/user_activates_jira_spec.rb | 42 ++--- ...user_activates_mattermost_slash_command_spec.rb | 204 ++++++++++----------- .../user_activates_slack_slash_command_spec.rb | 9 +- .../services/user_activates_youtrack_spec.rb | 91 --------- .../projects/settings/access_tokens_spec.rb | 93 ++++++++++ .../projects/settings/operations_settings_spec.rb | 2 +- .../projects/settings/project_settings_spec.rb | 30 +++ .../projects/settings/registry_settings_spec.rb | 2 +- .../projects/settings/repository_settings_spec.rb | 16 +- .../user_interacts_with_deploy_keys_spec.rb | 10 +- .../user_sees_revoke_deploy_token_modal_spec.rb | 2 +- .../projects/snippets/create_snippet_spec.rb | 17 +- .../projects/snippets/user_updates_snippet_spec.rb | 20 +- .../projects/user_sees_user_popover_spec.rb | 18 +- .../projects/wiki/markdown_preview_spec.rb | 2 +- spec/features/projects/wiki/shortcuts_spec.rb | 2 +- .../projects/wiki/user_creates_wiki_page_spec.rb | 35 +++- .../wiki/user_git_access_wiki_page_spec.rb | 2 +- .../projects/wiki/user_updates_wiki_page_spec.rb | 4 +- .../wiki/user_views_wiki_in_project_page_spec.rb | 2 +- .../projects/wiki/user_views_wiki_page_spec.rb | 2 +- .../projects/wiki/user_views_wiki_pages_spec.rb | 6 +- ...users_views_asciidoc_page_with_includes_spec.rb | 2 +- .../features/search/user_searches_for_code_spec.rb | 4 + .../search/user_searches_for_wiki_pages_spec.rb | 2 +- .../security/project/internal_access_spec.rb | 6 +- .../security/project/private_access_spec.rb | 2 +- .../security/project/public_access_spec.rb | 10 +- spec/features/snippets/search_snippets_spec.rb | 2 +- spec/features/snippets/spam_snippets_spec.rb | 76 +++++--- .../features/snippets/user_creates_snippet_spec.rb | 19 +- spec/features/snippets/user_edits_snippet_spec.rb | 20 +- spec/features/static_site_editor_spec.rb | 4 +- spec/features/users/signup_spec.rb | 4 +- 102 files changed, 1709 insertions(+), 757 deletions(-) delete mode 100644 spec/features/admin/admin_browses_logs_spec.rb create mode 100644 spec/features/boards/focus_mode_spec.rb create mode 100644 spec/features/commits/user_view_commits_spec.rb delete mode 100644 spec/features/dashboard/help_spec.rb create mode 100644 spec/features/groups/import_export/export_file_spec.rb create mode 100644 spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb create mode 100644 spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb create mode 100644 spec/features/projects/activity/user_sees_design_comment_spec.rb create mode 100644 spec/features/projects/issues/design_management/user_paginates_designs_spec.rb create mode 100644 spec/features/projects/issues/design_management/user_permissions_upload_spec.rb create mode 100644 spec/features/projects/issues/design_management/user_uploads_designs_spec.rb create mode 100644 spec/features/projects/issues/design_management/user_views_design_images_spec.rb create mode 100644 spec/features/projects/issues/design_management/user_views_design_spec.rb create mode 100644 spec/features/projects/issues/design_management/user_views_designs_spec.rb create mode 100644 spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb delete mode 100644 spec/features/projects/services/user_activates_youtrack_spec.rb create mode 100644 spec/features/projects/settings/access_tokens_spec.rb (limited to 'spec/features') diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index f6c498f7a4c..e711ee7d40e 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -12,6 +12,7 @@ describe 'Admin Appearance' do fill_in 'appearance_title', with: 'MyCompany' fill_in 'appearance_description', with: 'dev server' 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(current_path).to eq admin_appearances_path @@ -20,6 +21,7 @@ describe 'Admin Appearance' do 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_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 @@ -86,6 +88,22 @@ describe 'Admin Appearance' do expect_custom_new_project_appearance(appearance) end + context 'Profile page with custom profile image guidelines' do + before do + sign_in(create(:admin)) + visit admin_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 'Appearance logo' do sign_in(create(:admin)) visit admin_appearances_path diff --git a/spec/features/admin/admin_browses_logs_spec.rb b/spec/features/admin/admin_browses_logs_spec.rb deleted file mode 100644 index 45e860e1536..00000000000 --- a/spec/features/admin/admin_browses_logs_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe 'Admin browses logs' do - before do - sign_in(create(:admin)) - end - - it 'shows available log files' do - visit admin_logs_path - - expect(page).to have_link 'application_json.log' - expect(page).to have_link 'git_json.log' - expect(page).to have_link 'test.log' - expect(page).to have_link 'sidekiq.log' - expect(page).to have_link 'repocheck.log' - expect(page).to have_link 'kubernetes.log' - end -end diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 64326f3be32..40bcf4a31e4 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -36,6 +36,24 @@ describe 'Admin::Hooks' do expect(page).to have_content('foo.rb') expect(page).to have_content('bar.clj') end + + context 'deprecation warning' do + it 'shows warning for plugins directory' do + allow(Gitlab::FileHook).to receive(:files).and_return(['plugins/foo.rb']) + + visit admin_hooks_path + + expect(page).to have_content('Plugins directory is deprecated and will be removed in 14.0') + end + + it 'does not show warning for file_hooks directory' do + allow(Gitlab::FileHook).to receive(:files).and_return(['file_hooks/foo.rb']) + + visit admin_hooks_path + + expect(page).not_to have_content('Plugins directory is deprecated and will be removed in 14.0') + end + end end describe 'New Hook' do diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb index b8a910d3a40..afc6f2ddb56 100644 --- a/spec/features/admin/admin_mode/login_spec.rb +++ b/spec/features/admin/admin_mode/login_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do include TermsHelper include UserLoginHelper + include LdapHelpers describe 'with two-factor authentication', :js do def enter_code(code) @@ -179,6 +180,82 @@ describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_mock_admi 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 + let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) } + + 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('Two-Factor Authentication') + + enter_code(user.current_otp) + enable_admin_mode_using_ldap!(user) + + expect(page).to have_content('Two-Factor Authentication') + + # Cannot reuse the TOTP + Timecop.travel(30.seconds.from_now) do + enter_code(user.current_otp) + + expect(current_path).to eq admin_root_path + 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) + + 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! + + 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 + + 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 end end end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 1a3da8cb373..7ec3c2abb51 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -212,12 +212,12 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc expect(current_settings.hide_third_party_offers).to be true end - it 'Change Slack Notifications Service template settings' 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' fill_in 'Username', with: 'test_user' - fill_in 'service_push_channel', with: '#test_channel' + fill_in 'service[push_channel]', with: '#test_channel' page.check('Notify only broken pipelines') page.select 'All branches', from: 'Branches to be notified' @@ -231,10 +231,10 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc expect(page.all('input[type=checkbox]')).to all(be_checked) expect(find_field('Webhook').value).to eq 'http://localhost' expect(find_field('Username').value).to eq 'test_user' - expect(find('#service_push_channel').value).to eq '#test_channel' + expect(find('[name="service[push_channel]"]').value).to eq '#test_channel' end - it 'defaults Deployment events to false for chat notification template settings' do + it 'defaults Deployment events to false for chat notification template settings', :js do first(:link, 'Service Templates').click click_link 'Slack notifications' @@ -302,16 +302,6 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc visit metrics_and_profiling_admin_application_settings_path end - it 'Change Influx settings' do - page.within('.as-influx') do - check 'Enable InfluxDB Metrics' - click_button 'Save changes' - end - - expect(current_settings.metrics_enabled?).to be true - expect(page).to have_content "Application settings saved successfully" - end - it 'Change Prometheus settings' do page.within('.as-prometheus') do check 'Enable Prometheus Metrics' @@ -382,6 +372,18 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc expect(current_settings.allow_local_requests_from_system_hooks).to be false expect(current_settings.dns_rebinding_protection_enabled).to be false end + + it 'Changes Issues rate limits settings' do + visit network_admin_application_settings_path + + page.within('.as-issue-limits') do + fill_in 'Max requests per second per user', with: 0 + click_button 'Save changes' + end + + expect(page).to have_content "Application settings saved successfully" + expect(current_settings.issues_create_limit).to eq(0) + end end context 'Preferences page' do @@ -498,13 +500,13 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc def check_all_events page.check('Push') page.check('Issue') - page.check('Confidential issue') - page.check('Merge request') + page.check('Confidential Issue') + page.check('Merge Request') page.check('Note') - page.check('Confidential note') - page.check('Tag push') + page.check('Confidential Note') + page.check('Tag Push') page.check('Pipeline') - page.check('Wiki page') + page.check('Wiki Page') page.check('Deployment') end diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 27f2436108c..b9de858e3b9 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -70,7 +70,7 @@ describe 'Admin > Users > Impersonation Tokens', :js do accept_confirm { click_on "Revoke" } expect(page).to have_selector(".settings-message") - expect(no_personal_access_tokens_message).to have_text("This user has no active Impersonation Tokens.") + expect(no_personal_access_tokens_message).to have_text("This user has no active impersonation tokens.") end it "removes expired tokens from 'active' section" do @@ -79,7 +79,7 @@ describe 'Admin > Users > Impersonation Tokens', :js do visit admin_user_impersonation_tokens_path(user_id: user.username) expect(page).to have_selector(".settings-message") - expect(no_personal_access_tokens_message).to have_text("This user has no active Impersonation Tokens.") + expect(no_personal_access_tokens_message).to have_text("This user has no active impersonation tokens.") end end end diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 0ac8e7c5fc8..e82b1be4310 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -137,6 +137,49 @@ describe 'Issue Boards', :js do expect(find('.board:nth-child(4)')).to have_selector('.board-card', count: 0) end + context 'search list negation queries' do + context 'with the NOT queries feature flag disabled' do + before do + stub_feature_flags(not_issuable_queries: false) + visit project_board_path(project, board) + end + + it 'does not have the != option' do + find('.filtered-search').set('label:') + + wait_for_requests + within('#js-dropdown-operator') do + tokens = all(:css, 'li.filter-dropdown-item') + expect(tokens.count).to eq(1) + button = tokens[0].find('button') + expect(button).to have_content('=') + expect(button).not_to have_content('!=') + end + end + end + + context 'with the NOT queries feature flag enabled' do + before do + stub_feature_flags(not_issuable_queries: true) + visit project_board_path(project, board) + end + + it 'does not have the != option' do + find('.filtered-search').set('label:') + + wait_for_requests + within('#js-dropdown-operator') do + tokens = all(:css, 'li.filter-dropdown-item') + expect(tokens.count).to eq(2) + button = tokens[0].find('button') + expect(button).to have_content('=') + button = tokens[1].find('button') + expect(button).to have_content('!=') + end + end + end + end + it 'allows user to delete board' do page.within(find('.board:nth-child(2)')) do accept_confirm { find('.board-delete').click } @@ -549,6 +592,17 @@ describe 'Issue Boards', :js do end end + context 'issue board focus mode' do + before do + visit project_board_path(project, board) + wait_for_requests + end + + it 'shows the button' do + expect(page).to have_link('Toggle focus mode') + end + end + context 'keyboard shortcuts' do before do visit project_board_path(project, board) diff --git a/spec/features/boards/focus_mode_spec.rb b/spec/features/boards/focus_mode_spec.rb new file mode 100644 index 00000000000..fff3cce3c1a --- /dev/null +++ b/spec/features/boards/focus_mode_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Issue Boards focus mode', :js do + let(:project) { create(:project, :public) } + + before do + visit project_boards_path(project) + + wait_for_requests + end + + it 'shows focus mode button to guest users' do + expect(page).to have_selector('.board-extra-actions .js-focus-mode-btn') + end +end diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index f30689240c5..d05709b7e2f 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -217,7 +217,7 @@ describe 'Issue Boards', :js do wait_for_requests - click_link "No Milestone" + click_link "No milestone" wait_for_requests diff --git a/spec/features/commits/user_view_commits_spec.rb b/spec/features/commits/user_view_commits_spec.rb new file mode 100644 index 00000000000..133baca8b1c --- /dev/null +++ b/spec/features/commits/user_view_commits_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Commit > User view commits' do + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:user) { project.creator } + + before do + visit project_commits_path(project) + end + + describe 'Commits List' do + it 'displays the correct number of commits per day in the header' do + expect(first('.js-commit-header').find('.commits-count').text).to eq('1 commit') + end + + it 'lists the correct number of commits' do + expect(page).to have_selector('#commits-list > li:nth-child(2) > ul', count: 1) + end + end +end diff --git a/spec/features/dashboard/help_spec.rb b/spec/features/dashboard/help_spec.rb deleted file mode 100644 index 3f425001447..00000000000 --- a/spec/features/dashboard/help_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Dashboard Help' do - before do - sign_in(create(:user)) - end - - context 'documentation' do - it 'renders correctly markdown' do - visit help_page_path("administration/raketasks/maintenance") - - expect(page).to have_content('Gather information about GitLab and the system it runs on') - - node = find('.documentation h2 a#user-content-check-gitlab-configuration') - expect(node[:href]).to eq '#check-gitlab-configuration' - expect(find(:xpath, "#{node.path}/..").text).to eq 'Check GitLab configuration' - end - end -end diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index ff661014fb9..0b2811618b5 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -73,7 +73,7 @@ RSpec.describe 'Dashboard Issues' do find('.new-project-item-link').click - expect(page).to have_current_path("#{project_path}/issues/new") + expect(page).to have_current_path("#{project_path}/-/issues/new") page.within('#content-body') do expect(page).to have_selector('.issue-form') diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index 287af7e7b11..94aef03e093 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -35,7 +35,7 @@ describe 'Dashboard snippets' do element = page.find('.row.empty-state') expect(element).to have_content("Code snippets") - expect(element.find('.svg-content img')['src']).to have_content('illustrations/snippets_empty') + expect(element.find('.svg-content img.js-lazy-loaded')['src']).to have_content('illustrations/snippets_empty') end it 'shows new snippet button in main content area' do @@ -49,47 +49,6 @@ describe 'Dashboard snippets' do end end - context 'rendering file names' do - let_it_be(:snippet) { create(:personal_snippet, :public, author: user, file_name: 'foo.txt') } - let_it_be(:versioned_snippet) { create(:personal_snippet, :repository, :public, author: user, file_name: 'bar.txt') } - - before do - sign_in(user) - end - - context 'when feature flag :version_snippets is disabled' do - before do - stub_feature_flags(version_snippets: false) - - visit dashboard_snippets_path - end - - it 'contains the snippet file names from the DB' do - aggregate_failures do - expect(page).to have_content 'foo.txt' - expect(page).to have_content('bar.txt') - expect(page).not_to have_content('.gitattributes') - end - end - end - - context 'when feature flag :version_snippets is enabled' do - before do - stub_feature_flags(version_snippets: true) - - visit dashboard_snippets_path - end - - it 'contains both the versioned and non-versioned filenames' do - aggregate_failures do - expect(page).to have_content 'foo.txt' - expect(page).to have_content('.gitattributes') - expect(page).not_to have_content('bar.txt') - end - end - end - end - context 'filtering by visibility' do let_it_be(:snippets) do [ diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb index 867281da1e6..63867d5796a 100644 --- a/spec/features/dashboard/todos/todos_spec.rb +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -3,10 +3,10 @@ require 'spec_helper' describe 'Dashboard Todos' do - let(:user) { create(:user, username: 'john') } - let(:author) { create(:user) } - let(:project) { create(:project, :public) } - let(:issue) { create(:issue, due_date: Date.today, title: "Fix bug") } + let_it_be(:user) { create(:user, username: 'john') } + let_it_be(:author) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, due_date: Date.today, title: "Fix bug") } context 'User does not have todos' do before do @@ -357,4 +357,38 @@ describe 'Dashboard Todos' do expect(page).to have_link "merge request #{todo.target.to_reference}", href: href end end + + context 'User has a todo regarding a design' do + let_it_be(:target) { create(:design, issue: issue, project: project) } + let_it_be(:note) { create(:note, project: project, note: 'I am note, hear me roar') } + let_it_be(:todo) do + create(:todo, :mentioned, + user: user, + project: project, + target: target, + author: author, + note: note) + end + + before do + project.add_developer(user) + sign_in(user) + + visit dashboard_todos_path + end + + it 'has todo present' do + expect(page).to have_selector('.todos-list .todo', count: 1) + end + + it 'has a link that will take me to the design page' do + click_link "design #{target.to_reference}" + + expectation = Gitlab::Routing.url_helpers.designs_project_issue_path( + target.project, target.issue, target.filename + ) + + expect(current_path).to eq(expectation) + end + end end diff --git a/spec/features/error_tracking/user_filters_errors_by_status_spec.rb b/spec/features/error_tracking/user_filters_errors_by_status_spec.rb index 51e29e2a5ec..4b5bc16c4db 100644 --- a/spec/features/error_tracking/user_filters_errors_by_status_spec.rb +++ b/spec/features/error_tracking/user_filters_errors_by_status_spec.rb @@ -6,7 +6,7 @@ describe 'When a user filters Sentry errors by status', :js, :use_clean_rails_me include_context 'sentry error tracking context feature' let_it_be(:issues_response_body) { fixture_file('sentry/issues_sample_response.json') } - let_it_be(:filtered_errors_by_status_response) { JSON.parse(issues_response_body).filter { |error| error['status'] == 'ignored' }.to_json } + let_it_be(:filtered_errors_by_status_response) { Gitlab::Json.parse(issues_response_body).filter { |error| error['status'] == 'ignored' }.to_json } let(:issues_api_url) { "#{sentry_api_urls.issues_url}?limit=20&query=is:unresolved" } let(:issues_api_url_filter) { "#{sentry_api_urls.issues_url}?limit=20&query=is:ignored" } let(:auth_token) {{ 'Authorization' => 'Bearer access_token_123' }} diff --git a/spec/features/error_tracking/user_sees_error_index_spec.rb b/spec/features/error_tracking/user_sees_error_index_spec.rb index 842e4a2e8b5..34a3a4b5a49 100644 --- a/spec/features/error_tracking/user_sees_error_index_spec.rb +++ b/spec/features/error_tracking/user_sees_error_index_spec.rb @@ -6,7 +6,7 @@ describe 'View error index page', :js, :use_clean_rails_memory_store_caching, :s include_context 'sentry error tracking context feature' let_it_be(:issues_response_body) { fixture_file('sentry/issues_sample_response.json') } - let_it_be(:issues_response) { JSON.parse(issues_response_body) } + let_it_be(:issues_response) { Gitlab::Json.parse(issues_response_body) } let(:issues_api_url) { "#{sentry_api_urls.issues_url}?limit=20&query=is:unresolved" } before do diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb index 50ec44580d2..aee0a7c5573 100644 --- a/spec/features/explore/groups_spec.rb +++ b/spec/features/explore/groups_spec.rb @@ -27,7 +27,7 @@ describe 'Explore Groups', :js do end before do - stub_feature_flags({ vue_issuables_list: { enabled: false, thing: group } }) + stub_feature_flags(vue_issuables_list: false) end shared_examples 'renders public and internal projects' do diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index c499fac6bc0..a7c8c29517e 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -21,7 +21,7 @@ describe 'Global search' do describe 'I search through the issues and I see pagination' do before do - allow_next_instance_of(Gitlab::SearchResults) do |instance| + allow_next_instance_of(SearchService) do |instance| allow(instance).to receive(:per_page).and_return(1) end create_list(:issue, 2, project: project, title: 'initial') diff --git a/spec/features/groups/import_export/export_file_spec.rb b/spec/features/groups/import_export/export_file_spec.rb new file mode 100644 index 00000000000..5829e659722 --- /dev/null +++ b/spec/features/groups/import_export/export_file_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Group Export', :js do + include ExportFileHelper + + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + + context 'when the signed in user has the required permission level' do + before do + group.add_owner(user) + sign_in(user) + end + + it 'allows the user to export the group', :sidekiq_inline do + visit edit_group_path(group) + + expect(page).to have_content('Export group') + + click_link('Export group') + expect(page).to have_content('Group export started') + + expect(page).to have_content('Download export') + end + end + + context 'when the group import/export FF is disabled' do + before do + stub_feature_flags(group_import_export: false) + + group.add_owner(user) + sign_in(user) + end + + it 'does not show the group export options' do + visit edit_group_path(group) + + expect(page).to have_content('Advanced') + expect(page).not_to have_content('Export group') + end + end + + context 'when the signed in user does not have the required permission level' do + before do + group.add_guest(user) + + sign_in(user) + end + + it 'does not let the user export the group' do + visit edit_group_path(group) + + expect(page).to have_content('Page Not Found') + expect(page).not_to have_content('Export group') + end + end +end diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index e03d7b6d1f7..1cefcd18989 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -12,7 +12,7 @@ describe 'Group issues page' do let(:path) { issues_group_path(group) } before do - stub_feature_flags({ vue_issuables_list: { enabled: false, thing: group } }) + stub_feature_flags(vue_issuables_list: false) end context 'with shared examples' do @@ -186,4 +186,25 @@ describe 'Group issues page' do end end end + + context 'issues pagination' do + let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } + + let!(:issues) do + (1..25).to_a.map { |index| create(:issue, project: project, title: "Issue #{index}") } + end + + before do + sign_in(user_in_group) + visit issues_group_path(group) + end + + it 'shows the pagination' do + expect(page).to have_selector('.gl-pagination') + end + + it 'first pagination item is active' do + expect(page).to have_css(".js-first-button a.page-link.active") + end + end end diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb index df15f995be4..5c7c83aea6d 100644 --- a/spec/features/groups/members/leave_group_spec.rb +++ b/spec/features/groups/members/leave_group_spec.rb @@ -31,8 +31,6 @@ describe 'Groups > Members > Leave group' do page.accept_confirm - expect(find('.flash-notice')).to have_content "You left the \"#{group.full_name}\" group" - expect(page).to have_content left_group_message(group) expect(current_path).to eq(dashboard_groups_path) expect(group.users).not_to include(user) end diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb index 55f9418521f..593c450c6d6 100644 --- a/spec/features/groups/members/manage_groups_spec.rb +++ b/spec/features/groups/members/manage_groups_spec.rb @@ -15,75 +15,56 @@ describe 'Groups > Members > Manage groups', :js do sign_in(user) end - context 'with share groups with groups feature flag' do - before do - stub_feature_flags(shared_with_group: true) - end - - it 'add group to group' do - visit group_group_members_path(shared_group) + it 'add group to group' do + visit group_group_members_path(shared_group) - add_group(shared_with_group.id, 'Reporter') + add_group(shared_with_group.id, 'Reporter') - page.within(first_row) do - expect(page).to have_content(shared_with_group.name) - expect(page).to have_content('Reporter') - end + page.within(first_row) do + expect(page).to have_content(shared_with_group.name) + expect(page).to have_content('Reporter') end + end - it 'remove user from group' do - create(:group_group_link, shared_group: shared_group, - shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER) - - visit group_group_members_path(shared_group) - - expect(page).to have_content(shared_with_group.name) + it 'remove user from group' do + create(:group_group_link, shared_group: shared_group, + shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER) - accept_confirm do - find(:css, '#existing_shares li', text: shared_with_group.name).find(:css, 'a.btn-remove').click - end + visit group_group_members_path(shared_group) - wait_for_requests + expect(page).to have_content(shared_with_group.name) - expect(page).not_to have_content(shared_with_group.name) + accept_confirm do + find(:css, '#existing_shares li', text: shared_with_group.name).find(:css, 'a.btn-remove').click end - it 'update group to owner level' do - create(:group_group_link, shared_group: shared_group, - shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER) + wait_for_requests - visit group_group_members_path(shared_group) + expect(page).not_to have_content(shared_with_group.name) + end - page.within(first_row) do - click_button('Developer') - click_link('Maintainer') + it 'update group to owner level' do + create(:group_group_link, shared_group: shared_group, + shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER) - wait_for_requests + visit group_group_members_path(shared_group) - expect(page).to have_button('Maintainer') - end - end + page.within(first_row) do + click_button('Developer') + click_link('Maintainer') - def add_group(id, role) - page.click_link 'Invite group' - page.within ".invite-group-form" do - select2(id, from: "#shared_with_group_id") - select(role, from: "shared_group_access") - click_button "Invite" - end - end - end + wait_for_requests - context 'without share groups with groups feature flag' do - before do - stub_feature_flags(share_group_with_group: false) + expect(page).to have_button('Maintainer') end + end - it 'does not render invitation form and tabs' do - visit group_group_members_path(shared_group) - - expect(page).not_to have_link('Invite member') - expect(page).not_to have_link('Invite group') + def add_group(id, role) + page.click_link 'Invite group' + page.within ".invite-group-form" do + select2(id, from: "#shared_with_group_id") + select(role, from: "shared_group_access") + click_button "Invite" end end end diff --git a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb new file mode 100644 index 00000000000..491937ce4ab --- /dev/null +++ b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Groups > Members > Owner adds member with expiration date', :js do + include Select2Helper + include ActiveSupport::Testing::TimeHelpers + + let(:user1) { create(:user, name: 'John Doe') } + let!(:new_member) { create(:user, name: 'Mary Jane') } + let(:group) { create(:group) } + + before do + group.add_owner(user1) + sign_in(user1) + end + + it 'expiration date is displayed in the members list' do + travel_to Time.zone.parse('2016-08-06 08:00') do + date = 4.days.from_now + visit group_group_members_path(group) + + page.within '.invite-users-form' do + select2(new_member.id, from: '#user_ids', multiple: true) + fill_in 'expires_at', with: date.to_s(:medium) + "\n" + click_on 'Invite' + end + + page.within "#group_member_#{group_member_id(new_member)}" do + expect(page).to have_content('Expires in 4 days') + end + end + end + + it 'change expiration date' do + travel_to Time.zone.parse('2016-08-06 08:00') do + date = 3.days.from_now + group.add_developer(new_member) + + visit group_group_members_path(group) + + page.within "#group_member_#{group_member_id(new_member)}" do + find('.js-access-expiration-date').set date.to_s(:medium) + "\n" + wait_for_requests + expect(page).to have_content('Expires in 3 days') + end + end + end + + it 'remove expiration date' do + travel_to Time.zone.parse('2016-08-06 08:00') do + date = 3.days.from_now + group_member = create(:group_member, :developer, user: new_member, group: group, expires_at: date.to_s(:medium)) + + visit group_group_members_path(group) + + page.within "#group_member_#{group_member.id}" do + find('.js-clear-input').click + wait_for_requests + expect(page).not_to have_content('Expires in 3 days') + end + end + end + + def group_member_id(user) + group.members.find_by(user_id: new_member).id + end +end diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb index 0cdc2aa88f4..fd5b4ec9345 100644 --- a/spec/features/groups/navbar_spec.rb +++ b/spec/features/groups/navbar_spec.rb @@ -10,7 +10,42 @@ describe 'Group navbar' do let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } + let(:structure) do + [ + { + nav_item: _('Group overview'), + nav_sub_items: [ + _('Details'), + _('Activity') + ] + }, + { + nav_item: _('Issues'), + nav_sub_items: [ + _('List'), + _('Board'), + _('Labels'), + _('Milestones') + ] + }, + { + nav_item: _('Merge Requests'), + nav_sub_items: [] + }, + { + nav_item: _('Kubernetes'), + nav_sub_items: [] + }, + (analytics_nav_item if Gitlab.ee?), + { + nav_item: _('Members'), + nav_sub_items: [] + } + ] + end + before do + stub_feature_flags(group_push_rules: false) group.add_maintainer(user) sign_in(user) end @@ -20,4 +55,21 @@ describe 'Group navbar' do visit group_path(group) end end + + context 'when container registry is available' do + before do + stub_config(registry: { enabled: true }) + + insert_after_nav_item( + _('Kubernetes'), + new_nav_item: { + nav_item: _('Packages & Registries'), + nav_sub_items: [_('Container Registry')] + } + ) + visit group_path(group) + end + + it_behaves_like 'verified navigation bar' + end end diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index d2e65c02e37..c1cb0b4951e 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -262,6 +262,42 @@ describe 'Group' do end 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) } + + it 'new subgroup button is displayed without project creation permission' do + visit group_path(group) + + page.within '.group-buttons' do + expect(page).to have_link('New subgroup') + end + end + + it 'new subgroup button is displayed together with new project button when having project creation permission' do + group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) + visit group_path(group) + + page.within '.group-buttons' do + expect(page).to have_css("li[data-text='New subgroup']", visible: false) + expect(page).to have_css("li[data-text='New project']", visible: false) + end + end + + it 'new project button is displayed without subgroup creation permission' do + group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) + user = create(:user) + + group.add_maintainer(user) + sign_out(:user) + sign_in(user) + + visit group_path(group) + page.within '.group-buttons' do + expect(page).to have_link('New project') + end + end + end + def remove_with_confirm(button_text, confirm_with) click_button button_text fill_in 'confirm_name_input', with: confirm_with diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb index 88a7aa51326..1ba3849fe2c 100644 --- a/spec/features/help_pages_spec.rb +++ b/spec/features/help_pages_spec.rb @@ -4,35 +4,9 @@ require 'spec_helper' describe 'Help Pages' do describe 'Get the main help page' do - shared_examples_for 'help page' do |prefix: ''| - it 'prefixes links correctly' do - expect(page).to have_selector(%(div.documentation-index > table tbody tr td a[href="#{prefix}/help/api/README.md"])) - end - end - - context 'without a trailing slash' do - before do - visit help_path - end - - it_behaves_like 'help page' - end - - context 'with a trailing slash' do - before do - visit help_path + '/' - end - - it_behaves_like 'help page' - end - - context 'with a relative installation' do - before do - stub_config_setting(relative_url_root: '/gitlab') - visit help_path - end - - it_behaves_like 'help page', prefix: '/gitlab' + before do + allow(File).to receive(:read).and_call_original + allow(File).to receive(:read).with(Rails.root.join('doc', 'README.md')).and_return(fixture_file('sample_doc.md')) end context 'quick link shortcuts', :js do diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index d036fde5657..fc9176715c3 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -274,7 +274,7 @@ describe 'Issues > Labels bulk assignment' do expect(find("#issue_#{issue2.id}")).to have_content 'First Release' check 'check-all-issues' - open_milestone_dropdown(['No Milestone']) + open_milestone_dropdown(['No milestone']) update_issues expect(find("#issue_#{issue1.id}")).to have_content 'bug' diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 5e2b5921e06..3ee5840e1b9 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -81,6 +81,26 @@ describe 'Filter issues', :js do expect_filtered_search_input(search_term) end + context 'with the NOT queries feature flag disabled' do + before do + stub_feature_flags(not_issuable_queries: false) + visit project_issues_path(project) + end + + it 'does not have the != option' do + input_filtered_search("label:", submit: false) + + wait_for_requests + within('#js-dropdown-operator') do + tokens = all(:css, 'li.filter-dropdown-item') + expect(tokens.count).to eq(1) + button = tokens[0].find('button') + expect(button).to have_content('=') + expect(button).not_to have_content('!=') + end + end + end + describe 'filter issues by author' do context 'only author' do it 'filters issues by searched author' do @@ -153,16 +173,16 @@ describe 'Filter issues', :js do expect_filtered_search_input_empty end - it 'filters issues by no label' do - input_filtered_search('label:=none') + it 'filters issues by any label' do + input_filtered_search('label:=any') - expect_tokens([label_token('None', false)]) + expect_tokens([label_token('Any', false)]) expect_issues_list_count(4) expect_filtered_search_input_empty end it 'filters issues by no label' do - input_filtered_search('label:!=none') + input_filtered_search('label:=none') expect_tokens([label_token('None', false)]) expect_issues_list_count(4) @@ -351,14 +371,6 @@ describe 'Filter issues', :js do expect_filtered_search_input_empty end - it 'filters issues by negation of no milestone' do - input_filtered_search("milestone:!=none ") - - expect_tokens([milestone_token('None', false, '!=')]) - expect_issues_list_count(5) - expect_filtered_search_input_empty - end - it 'filters issues by upcoming milestones' do create(:milestone, project: project, due_date: 1.month.from_now) do |future_milestone| create(:issue, project: project, milestone: future_milestone, author: user) @@ -376,10 +388,14 @@ describe 'Filter issues', :js do create(:issue, project: project, milestone: future_milestone, author: user) end + create(:milestone, project: project, due_date: 3.days.ago) do |past_milestone| + create(:issue, project: project, milestone: past_milestone, author: user) + end + input_filtered_search("milestone:!=upcoming") expect_tokens([milestone_token('Upcoming', false, '!=')]) - expect_issues_list_count(8) + expect_issues_list_count(1) expect_filtered_search_input_empty end @@ -392,10 +408,13 @@ describe 'Filter issues', :js do end it 'filters issues by negation of started milestones' do + milestone2 = create(:milestone, title: "9", project: project, start_date: 2.weeks.from_now) + create(:issue, project: project, author: user, title: "something else", milestone: milestone2) + input_filtered_search("milestone:!=started") expect_tokens([milestone_token('Started', false, '!=')]) - expect_issues_list_count(3) + expect_issues_list_count(1) expect_filtered_search_input_empty end diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index 3c50cb4c997..d34253b3c5e 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -113,7 +113,7 @@ describe 'Visual tokens', :js do describe 'add new token after editing existing token' do before do input_filtered_search('author:=@root assignee:=none', submit: false) - first('.tokens-container .filtered-search-token').double_click + first('.tokens-container .filtered-search-token').click filtered_search.send_keys(' ') end @@ -175,4 +175,20 @@ describe 'Visual tokens', :js do expect(token.find('.name').text).to eq('Label') expect(token.find('.operator').text).to eq('=') end + + describe 'Any/None option' do + it 'hidden when NOT operator is selected' do + input_filtered_search('milestone:!=', extra_space: false, submit: false) + + expect(page).not_to have_selector("#js-dropdown-milestone", text: 'Any') + expect(page).not_to have_selector("#js-dropdown-milestone", text: 'None') + end + + it 'shown when EQUAL operator is selected' do + input_filtered_search('milestone:=', extra_space: false, submit: false) + + expect(page).to have_selector("#js-dropdown-milestone", text: 'Any') + expect(page).to have_selector("#js-dropdown-milestone", text: 'None') + end + end end diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb index b59cd2d632a..47e7022011d 100644 --- a/spec/features/issues/spam_issues_spec.rb +++ b/spec/features/issues/spam_issues_spec.rb @@ -23,9 +23,13 @@ describe 'New issue', :js do sign_in(user) end - context 'when identified as spam' do + context 'when SpamVerdictService disallows' do + include_context 'includes Spam constants' + before do - WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "true", status: 200) + allow_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + allow(verdict_service).to receive(:execute).and_return(DISALLOW) + end visit new_project_issue_path(project) end @@ -33,23 +37,22 @@ describe 'New issue', :js do context 'when allow_possible_spam feature flag is false' do before do stub_feature_flags(allow_possible_spam: false) - end - it 'creates an issue after solving reCaptcha' do fill_in 'issue_title', with: 'issue title' fill_in 'issue_description', with: 'issue description' + end + it 'rejects issue creation' do click_button 'Submit issue' - # it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha - # recaptcha verification is skipped in test environment and it always returns true + expect(page).to have_content('discarded') + expect(page).not_to have_content('potential spam') expect(page).not_to have_content('issue title') - expect(page).to have_css('.recaptcha') - - click_button 'Submit issue' + end - expect(page.find('.issue-details h2.title')).to have_content('issue title') - expect(page.find('.issue-details .description')).to have_content('issue description') + it 'creates a spam log record' do + expect { click_button 'Submit issue' } + .to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue') end end @@ -59,10 +62,9 @@ describe 'New issue', :js do fill_in 'issue_description', with: 'issue description' end - it 'creates an issue without a need to solve reCaptcha' do + it 'allows issue creation' do click_button 'Submit issue' - expect(page).not_to have_css('.recaptcha') expect(page.find('.issue-details h2.title')).to have_content('issue title') expect(page.find('.issue-details .description')).to have_content('issue description') end @@ -74,9 +76,98 @@ describe 'New issue', :js do end end - context 'when not identified as spam' do + context 'when SpamVerdictService requires recaptcha' do + include_context 'includes Spam constants' + before do - WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: 'false', status: 200) + allow_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + allow(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) + end + + visit new_project_issue_path(project) + end + + context 'when recaptcha is enabled' do + before do + stub_application_setting(recaptcha_enabled: true) + end + + context 'when allow_possible_spam feature flag is false' do + before do + stub_feature_flags(allow_possible_spam: false) + end + + it 'creates an issue after solving reCaptcha' do + fill_in 'issue_title', with: 'issue title' + fill_in 'issue_description', with: 'issue description' + + click_button 'Submit issue' + + # it is impossible to test reCAPTCHA automatically and there is no possibility to fill in recaptcha + # reCAPTCHA verification is skipped in test environment and it always returns true + expect(page).not_to have_content('issue title') + expect(page).to have_css('.recaptcha') + + click_button 'Submit issue' + + expect(page.find('.issue-details h2.title')).to have_content('issue title') + expect(page.find('.issue-details .description')).to have_content('issue description') + end + end + + context 'when allow_possible_spam feature flag is true' do + before do + fill_in 'issue_title', with: 'issue title' + fill_in 'issue_description', with: 'issue description' + end + + it 'creates an issue without a need to solve reCAPTCHA' do + click_button 'Submit issue' + + expect(page).not_to have_css('.recaptcha') + expect(page.find('.issue-details h2.title')).to have_content('issue title') + expect(page.find('.issue-details .description')).to have_content('issue description') + end + + it 'creates a spam log record' do + expect { click_button 'Submit issue' } + .to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue') + end + end + end + + context 'when reCAPTCHA is not enabled' do + before do + stub_application_setting(recaptcha_enabled: false) + end + + context 'when allow_possible_spam feature flag is true' do + before do + fill_in 'issue_title', with: 'issue title' + fill_in 'issue_description', with: 'issue description' + end + + it 'creates an issue without a need to solve reCaptcha' do + click_button 'Submit issue' + + expect(page).not_to have_css('.recaptcha') + expect(page.find('.issue-details h2.title')).to have_content('issue title') + expect(page.find('.issue-details .description')).to have_content('issue description') + end + + it 'creates a spam log record' do + expect { click_button 'Submit issue' } + .to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue') + end + end + end + end + + context 'when the SpamVerdictService allows' do + before do + allow_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + allow(verdict_service).to receive(:execute).and_return(ALLOW) + end visit new_project_issue_path(project) end diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index 45a0b1932a2..98f70df1c8b 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -95,7 +95,7 @@ describe 'Multiple issue updating from issues#index', :js do find('#check-all-issues').click find('.issues-bulk-update .js-milestone-select').click - find('.dropdown-menu-milestone a', text: "No Milestone").click + find('.dropdown-menu-milestone a', text: "No milestone").click click_update_issues_button expect(find('.issue:first-child')).not_to have_content milestone.title diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb index 7eecfd1ccf4..848dbbb85a6 100644 --- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb +++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb @@ -164,17 +164,7 @@ describe 'User creates branch and merge request on issue page', :js do context 'when issue is confidential' do let(:issue) { create(:issue, :confidential, project: project) } - it 'disables the create branch button' do - stub_feature_flags(create_confidential_merge_request: false) - - visit project_issue_path(project, issue) - - expect(page).not_to have_css('.create-mr-dropdown-wrap') - end - - it 'enables the create branch button when feature flag is enabled' do - stub_feature_flags(create_confidential_merge_request: true) - + it 'enables the create branch button' do visit project_issue_path(project, issue) expect(page).to have_css('.create-mr-dropdown-wrap') diff --git a/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb b/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb new file mode 100644 index 00000000000..c3f17227701 --- /dev/null +++ b/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Issues > Real-time sidebar', :js do + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:user) { create(:user) } + + before_all do + project.add_developer(user) + end + + it 'updates the assignee in real-time' do + Capybara::Session.new(:other_session) + + using_session :other_session do + visit project_issue_path(project, issue) + expect(page.find('.assignee')).to have_content 'None' + end + + gitlab_sign_in(user) + visit project_issue_path(project, issue) + expect(page.find('.assignee')).to have_content 'None' + + click_button 'assign yourself' + + using_session :other_session do + expect(page.find('.assignee')).to have_content user.name + end + end +end diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb index f85acc28645..d40c2b8bafd 100644 --- a/spec/features/markdown/copy_as_gfm_spec.rb +++ b/spec/features/markdown/copy_as_gfm_spec.rb @@ -172,6 +172,12 @@ describe 'Copy as GFM', :js do '![Image](https://example.com/image.png)' ) + verify_media_with_partial_path( + '[test.txt](/uploads/a123/image.txt)', + + project_media_uri(@project, '/uploads/a123/image.txt') + ) + verify_media_with_partial_path( '![Image](/uploads/a123/image.png)', diff --git a/spec/features/markdown/metrics_spec.rb b/spec/features/markdown/metrics_spec.rb index dadb9571c54..7b0eb8959a5 100644 --- a/spec/features/markdown/metrics_spec.rb +++ b/spec/features/markdown/metrics_spec.rb @@ -137,7 +137,7 @@ describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidek end context 'transient metrics embeds' do - let(:metrics_url) { urls.metrics_project_environment_url(project, environment, embed_json: embed_json) } + let(:metrics_url) { urls.metrics_dashboard_project_environment_url(project, environment, embed_json: embed_json) } let(:title) { 'Important Metrics' } let(:embed_json) do { diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb index f1ee6aaa897..17ff494a6fa 100644 --- a/spec/features/merge_request/maintainer_edits_fork_spec.rb +++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb @@ -20,7 +20,7 @@ describe 'a maintainer edits files on a source-branch of an MR from a fork', :js end before do - stub_feature_flags(web_ide_default: false, single_mr_diff_view: { enabled: false, thing: target_project }, code_navigation: false) + stub_feature_flags(web_ide_default: false, single_mr_diff_view: false, code_navigation: false) target_project.add_maintainer(user) sign_in(user) diff --git a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb index 8633d67f875..2a4192374bd 100644 --- a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb +++ b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb @@ -10,7 +10,7 @@ describe 'Batch diffs', :js do let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'empty-branch') } before do - stub_feature_flags(single_mr_diff_view: { enabled: true, thing: project }) + stub_feature_flags(single_mr_diff_view: project) stub_feature_flags(diffs_batch_load: true) sign_in(project.owner) 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 19f82058be2..ebfb5ce796f 100644 --- a/spec/features/merge_request/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb @@ -235,7 +235,9 @@ describe 'Merge request > User posts diff notes', :js do def should_allow_dismissing_a_comment(line_holder, diff_side = nil) write_comment_on_line(line_holder, diff_side) - find('.js-close-discussion-note-form').click + accept_confirm do + find('.js-close-discussion-note-form').click + end assert_comment_dismissal(line_holder) end diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index b22f5a6c211..0548d958322 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -147,7 +147,10 @@ describe 'Merge request > User posts notes', :js do it 'resets the edit note form textarea with the original content of the note if cancelled' do within('.current-note-edit-form') do fill_in 'note[note]', with: 'Some new content' - find('.btn-cancel').click + + accept_confirm do + find('.btn-cancel').click + end end expect(find('.js-note-text').text).to eq '' end diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb index 5fc65f020d3..41a7456aed5 100644 --- a/spec/features/merge_request/user_resolves_conflicts_spec.rb +++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb @@ -183,14 +183,14 @@ describe 'Merge request > User resolves conflicts', :js do end end - UNRESOLVABLE_CONFLICTS = { + unresolvable_conflicts = { 'conflict-too-large' => 'when the conflicts contain a large file', 'conflict-binary-file' => 'when the conflicts contain a binary file', 'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another', 'conflict-non-utf8' => 'when the conflicts contain a non-UTF-8 file' }.freeze - UNRESOLVABLE_CONFLICTS.each do |source_branch, description| + unresolvable_conflicts.each do |source_branch, description| context description do let(:merge_request) { create_merge_request(source_branch) } 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 b8a5a4036a5..0e30df518d7 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 @@ -43,7 +43,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do context 'single thread' do it 'shows text with how many threads' do page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end @@ -60,7 +60,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -77,7 +77,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -89,7 +89,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end @@ -162,7 +162,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') end end @@ -174,7 +174,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') expect(page).not_to have_selector('.line-resolve-btn.is-active') end end @@ -189,7 +189,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end end @@ -203,7 +203,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -218,7 +218,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -275,7 +275,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do expect(page).to have_content('Last updated') page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end @@ -292,7 +292,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') end end end @@ -305,7 +305,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do it 'shows text with how many threads' do page.within '.line-resolve-all-container' do - expect(page).to have_content('0/2 threads resolved') + expect(page).to have_content('2 unresolved threads') end end @@ -313,7 +313,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do click_button('Resolve thread', match: :first) page.within '.line-resolve-all-container' do - expect(page).to have_content('1/2 threads resolved') + expect(page).to have_content('1 unresolved thread') end end @@ -323,7 +323,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('2/2 threads resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -336,7 +336,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('2/2 threads resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -392,7 +392,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do context 'changes tab' do it 'shows text with how many threads' do page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end @@ -408,7 +408,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -423,7 +423,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -435,7 +435,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end @@ -449,7 +449,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -466,7 +466,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end end @@ -489,7 +489,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end @@ -519,7 +519,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('1/1 thread resolved') + expect(page).to have_content('All threads resolved') expect(page).to have_selector('.line-resolve-btn.is-active') end end @@ -538,7 +538,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do end page.within '.line-resolve-all-container' do - expect(page).to have_content('0/1 thread resolved') + expect(page).to have_content('1 unresolved thread') end end end @@ -550,17 +550,17 @@ describe 'Merge request > User resolves diff notes and threads', :js do end it 'shows resolved icon' do - expect(page).to have_content '1/1 thread resolved' + expect(page).to have_content 'All threads resolved' click_button 'Toggle thread' expect(page).to have_selector('.line-resolve-btn.is-active') end it 'does not allow user to click resolve button' do - expect(page).to have_selector('.line-resolve-btn.is-disabled') + expect(page).to have_selector('.line-resolve-btn.is-active') click_button 'Toggle thread' - expect(page).to have_selector('.line-resolve-btn.is-disabled') + expect(page).to have_selector('.line-resolve-btn.is-active') end end end diff --git a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb index 9c9e0dacb87..029f55c2cd6 100644 --- a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb +++ b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb @@ -28,6 +28,7 @@ describe 'Merge request > User sees notes from forked project', :js do page.within('.discussion-notes') do find('.btn-text-field').click + scroll_to(page.find('#note_note', visible: false)) find('#note_note').send_keys('A reply comment') find('.js-comment-button').click end diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb index 4d3461bf1ae..fa951dd50d3 100644 --- a/spec/features/merge_requests/user_mass_updates_spec.rb +++ b/spec/features/merge_requests/user_mass_updates_spec.rb @@ -91,7 +91,7 @@ describe 'Merge requests > User mass updates', :js do end it 'removes milestone from the merge request' do - change_milestone("No Milestone") + change_milestone("No milestone") expect(find('.merge-request')).not_to have_content milestone.title end diff --git a/spec/features/milestones/user_creates_milestone_spec.rb b/spec/features/milestones/user_creates_milestone_spec.rb index 368a2ddecdf..12cb27b0062 100644 --- a/spec/features/milestones/user_creates_milestone_spec.rb +++ b/spec/features/milestones/user_creates_milestone_spec.rb @@ -14,13 +14,13 @@ describe "User creates milestone", :js do end it "creates milestone" do - TITLE = "v2.3".freeze + title = "v2.3".freeze - fill_in("Title", with: TITLE) + fill_in("Title", with: title) fill_in("Description", with: "# Description header") click_button("Create milestone") - expect(page).to have_content(TITLE) + expect(page).to have_content(title) .and have_content("Issues") .and have_header_with_correct_id_and_link(1, "Description header", "description-header") diff --git a/spec/features/milestones/user_views_milestone_spec.rb b/spec/features/milestones/user_views_milestone_spec.rb index d8bb4902087..ca13e226432 100644 --- a/spec/features/milestones/user_views_milestone_spec.rb +++ b/spec/features/milestones/user_views_milestone_spec.rb @@ -14,13 +14,13 @@ describe "User views milestone" do end it "avoids N+1 database queries" do - ISSUE_PARAMS = { project: project, assignees: [user], author: user, milestone: milestone, labels: labels }.freeze + issue_params = { project: project, assignees: [user], author: user, milestone: milestone, labels: labels }.freeze - create(:labeled_issue, ISSUE_PARAMS) + create(:labeled_issue, issue_params) control = ActiveRecord::QueryRecorder.new { visit_milestone } - create(:labeled_issue, ISSUE_PARAMS) + create(:labeled_issue, issue_params) expect { visit_milestone }.not_to exceed_query_limit(control) end diff --git a/spec/features/profiles/emails_spec.rb b/spec/features/profiles/emails_spec.rb index 4d2cd0f8b56..a41ef9e86ae 100644 --- a/spec/features/profiles/emails_spec.rb +++ b/spec/features/profiles/emails_spec.rb @@ -31,6 +31,15 @@ describe 'Profile > Emails' do expect(email).to be_nil expect(page).to have_content('Email has already been taken') end + + it 'does not add an invalid email' do + fill_in('Email', with: 'test.@example.com') + click_button('Add email address') + + email = user.emails.find_by(email: email) + expect(email).to be_nil + expect(page).to have_content('Email is invalid') + end end it 'User removes email' do @@ -58,7 +67,7 @@ describe 'Profile > Emails' do email = user.emails.create(email: 'my@email.com') visit profile_emails_path - expect { click_link("Resend confirmation email") }.to change { ActionMailer::Base.deliveries.size } + expect { click_link("Resend confirmation email") }.to have_enqueued_job.on_queue('mailers') expect(page).to have_content("Confirmation email sent to #{email.email}") end diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 22f9c8d8afc..1fb61eeeb5a 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -86,7 +86,7 @@ describe 'Profile > Personal Access Tokens', :js do accept_confirm { click_on "Revoke" } expect(page).to have_selector(".settings-message") - expect(no_personal_access_tokens_message).to have_text("This user has no active Personal Access Tokens.") + expect(no_personal_access_tokens_message).to have_text("This user has no active personal access tokens.") end it "removes expired tokens from 'active' section" do @@ -94,7 +94,7 @@ describe 'Profile > Personal Access Tokens', :js do visit profile_personal_access_tokens_path expect(page).to have_selector(".settings-message") - expect(no_personal_access_tokens_message).to have_text("This user has no active Personal Access Tokens.") + expect(no_personal_access_tokens_message).to have_text("This user has no active personal access tokens.") end context "when revocation fails" do diff --git a/spec/features/projects/activity/user_sees_design_comment_spec.rb b/spec/features/projects/activity/user_sees_design_comment_spec.rb new file mode 100644 index 00000000000..9864e9ce29f --- /dev/null +++ b/spec/features/projects/activity/user_sees_design_comment_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Projects > Activity > User sees design comment', :js do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :repository, :public) } + let_it_be(:user) { project.creator } + let_it_be(:commenter) { create(:user) } + let_it_be(:issue) { create(:closed_issue, project: project) } + let_it_be(:design) { create(:design, issue: issue) } + + let(:design_activity) do + "#{commenter.name} #{commenter.to_reference} commented on design" + end + + let(:issue_activity) do + "#{user.name} #{user.to_reference} closed issue #{issue.to_reference}" + end + + before_all do + project.add_developer(commenter) + create(:event, :for_design, project: project, author: commenter, design: design) + create(:closed_issue_event, project: project, author: user, target: issue) + end + + before do + enable_design_management + end + + it 'shows the design comment action in the activity page' do + visit activity_project_path(project) + + expect(page).to have_content(design_activity) + end + + it 'allows to filter out the design event with the "event_filter=issue" URL param', :aggregate_failures do + visit activity_project_path(project, event_filter: EventFilter::ISSUE) + + expect(page).not_to have_content(design_activity) + expect(page).to have_content(issue_activity) + end + + it 'allows to filter in the event with the "event_filter=comments" URL param', :aggregate_failures do + visit activity_project_path(project, event_filter: EventFilter::COMMENTS) + + expect(page).to have_content(design_activity) + expect(page).not_to have_content(issue_activity) + end +end diff --git a/spec/features/projects/branches/user_creates_branch_spec.rb b/spec/features/projects/branches/user_creates_branch_spec.rb index 156edb973cd..8aac188160b 100644 --- a/spec/features/projects/branches/user_creates_branch_spec.rb +++ b/spec/features/projects/branches/user_creates_branch_spec.rb @@ -16,18 +16,18 @@ describe "User creates branch", :js do end it "creates new branch" do - BRANCH_NAME = "deploy_keys".freeze + branch_name = "deploy_keys".freeze - create_branch(BRANCH_NAME) + create_branch(branch_name) - expect(page).to have_content(BRANCH_NAME) + expect(page).to have_content(branch_name) end context "when branch name is invalid" do it "does not create new branch" do - INVALID_BRANCH_NAME = "1.0 stable".freeze + invalid_branch_name = "1.0 stable".freeze - fill_in("branch_name", with: INVALID_BRANCH_NAME) + fill_in("branch_name", with: invalid_branch_name) page.find("body").click # defocus the branch_name input select_branch("master") diff --git a/spec/features/projects/commit/comments/user_edits_comments_spec.rb b/spec/features/projects/commit/comments/user_edits_comments_spec.rb index 0fa2b2ff232..29132173674 100644 --- a/spec/features/projects/commit/comments/user_edits_comments_spec.rb +++ b/spec/features/projects/commit/comments/user_edits_comments_spec.rb @@ -19,7 +19,7 @@ describe "User edits a comment on a commit", :js do end it "edits comment" do - NEW_COMMENT_TEXT = "+1 Awesome!".freeze + new_comment_text = "+1 Awesome!".freeze page.within(".main-notes-list") do note = find(".note") @@ -31,14 +31,14 @@ describe "User edits a comment on a commit", :js do page.find(".current-note-edit-form textarea") page.within(".current-note-edit-form") do - fill_in("note[note]", with: NEW_COMMENT_TEXT) + fill_in("note[note]", with: new_comment_text) click_button("Save comment") end wait_for_requests page.within(".note") do - expect(page).to have_content(NEW_COMMENT_TEXT) + expect(page).to have_content(new_comment_text) end end end diff --git a/spec/features/projects/environments_pod_logs_spec.rb b/spec/features/projects/environments_pod_logs_spec.rb index a51f121bf59..32eaf690950 100644 --- a/spec/features/projects/environments_pod_logs_spec.rb +++ b/spec/features/projects/environments_pod_logs_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe 'Environment > Pod Logs', :js do +describe 'Environment > Pod Logs', :js, :kubeclient do include KubernetesHelpers let(:pod_names) { %w(kube-pod) } diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index 5c52abaeb62..7e3d8e5c1c5 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -171,6 +171,18 @@ describe "User browses files" do end end + context 'when commit message has markdown', :js do + before do + project.repository.create_file(user, 'index', 'test', message: ':star: testing', branch_name: 'master') + + visit(project_tree_path(project, "master")) + end + + it 'renders emojis' do + expect(page).to have_selector('gl-emoji', count: 2) + end + end + context "when browsing a `improve/awesome` branch", :js do before do visit(project_tree_path(project, "improve/awesome")) @@ -197,6 +209,33 @@ describe "User browses files" do end end + context "when browsing a `Ääh-test-utf-8` branch", :js do + before do + project.repository.create_branch('Ääh-test-utf-8', project.repository.root_ref) + visit(project_tree_path(project, "Ääh-test-utf-8")) + end + + it "shows files from a repository" do + expect(page).to have_content("VERSION") + .and have_content(".gitignore") + .and have_content("LICENSE") + + click_link("files") + + page.within('.repo-breadcrumb') do + expect(page).to have_link('files') + end + + click_link("html") + + page.within('.repo-breadcrumb') do + expect(page).to have_link('html') + end + + expect(page).to have_link('500.html') + end + end + context "when browsing a `test-#` branch", :js do before do project.repository.create_branch('test-#', project.repository.root_ref) diff --git a/spec/features/projects/graph_spec.rb b/spec/features/projects/graph_spec.rb index 6b2a9a6b852..25efb7b28a7 100644 --- a/spec/features/projects/graph_spec.rb +++ b/spec/features/projects/graph_spec.rb @@ -59,7 +59,7 @@ describe 'Project Graph', :js do it 'HTML escapes branch name' do expect(page.body).to include("Commit statistics for #{ERB::Util.html_escape(branch_name)}") - expect(page.body).not_to include(branch_name) + expect(page.find('.dropdown-toggle-text')['innerHTML']).to eq(ERB::Util.html_escape(branch_name)) end end diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index 7ee8f42e6ef..1d6d5ae1b4d 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -52,7 +52,7 @@ describe 'Import/Export - project export integration test', :js do project_json_path = File.join(tmpdir, 'project.json') expect(File).to exist(project_json_path) - project_hash = JSON.parse(IO.read(project_json_path)) + project_hash = Gitlab::Json.parse(IO.read(project_json_path)) sensitive_words.each do |sensitive_word| found = find_sensitive_attributes(sensitive_word, project_hash) @@ -78,7 +78,7 @@ describe 'Import/Export - project export integration test', :js do expect(File).to exist(project_json_path) relations = [] - relations << JSON.parse(IO.read(project_json_path)) + relations << Gitlab::Json.parse(IO.read(project_json_path)) Dir.glob(File.join(tmpdir, 'tree/project', '*.ndjson')) do |rb_filename| File.foreach(rb_filename) do |line| json = ActiveSupport::JSON.decode(line) diff --git a/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb b/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb new file mode 100644 index 00000000000..d9a72f2d5c5 --- /dev/null +++ b/spec/features/projects/issues/design_management/user_paginates_designs_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'User paginates issue designs', :js do + include DesignManagementTestHelpers + + let(:project) { create(:project_empty_repo, :public) } + let(:issue) { create(:issue, project: project) } + + before do + enable_design_management + + create_list(:design, 2, :with_file, issue: issue) + + visit project_issue_path(project, issue) + + click_link 'Designs' + + wait_for_requests + + find('.js-design-list-item', match: :first).click + end + + it 'paginates to next design' do + expect(find('.js-previous-design')[:disabled]).to eq('true') + + page.within(find('.js-design-header')) do + expect(page).to have_content('1 of 2') + end + + find('.js-next-design').click + + expect(find('.js-previous-design')[:disabled]).not_to eq('true') + + page.within(find('.js-design-header')) do + expect(page).to have_content('2 of 2') + end + end +end diff --git a/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb b/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb new file mode 100644 index 00000000000..2238e86a47f --- /dev/null +++ b/spec/features/projects/issues/design_management/user_permissions_upload_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'User design permissions', :js do + include DesignManagementTestHelpers + + let(:project) { create(:project_empty_repo, :public) } + let(:issue) { create(:issue, project: project) } + + before do + enable_design_management + + visit project_issue_path(project, issue) + + click_link 'Designs' + + wait_for_requests + end + + it 'user does not have permissions to upload design' do + expect(page).not_to have_field('design_file') + end +end diff --git a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb new file mode 100644 index 00000000000..d160ab95a65 --- /dev/null +++ b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'User uploads new design', :js do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project_empty_repo, :public) } + let_it_be(:user) { project.owner } + let_it_be(:issue) { create(:issue, project: project) } + + before do + sign_in(user) + end + + context "when the feature is available" do + before do + enable_design_management + + visit project_issue_path(project, issue) + + click_link 'Designs' + + wait_for_requests + end + + it 'uploads designs' do + attach_file(:design_file, logo_fixture, make_visible: true) + + expect(page).to have_selector('.js-design-list-item', count: 1) + + within first('#designs-tab .js-design-list-item') do + expect(page).to have_content('dk.png') + end + + attach_file(:design_file, gif_fixture, make_visible: true) + + expect(page).to have_selector('.js-design-list-item', count: 2) + end + end + + context 'when the feature is not available' do + before do + visit project_issue_path(project, issue) + + click_link 'Designs' + + wait_for_requests + end + + it 'shows the message about requirements' do + expect(page).to have_content("To enable design management, you'll need to meet the requirements.") + end + end + + def logo_fixture + Rails.root.join('spec', 'fixtures', 'dk.png') + end + + def gif_fixture + Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + end +end diff --git a/spec/features/projects/issues/design_management/user_views_design_images_spec.rb b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb new file mode 100644 index 00000000000..3d0f4df55c4 --- /dev/null +++ b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Users views raw design image files' do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:design) { create(:design, :with_file, issue: issue, versions_count: 2) } + let(:newest_version) { design.versions.ordered.first } + let(:oldest_version) { design.versions.ordered.last } + + before do + enable_design_management + end + + it 'serves the latest design version when no ref is given' do + visit project_design_management_designs_raw_image_path(design.project, design) + + expect(response_headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to eq( + workhorse_data_header_for_version(oldest_version.sha) + ) + end + + it 'serves the correct design version when a ref is given' do + visit project_design_management_designs_raw_image_path(design.project, design, oldest_version.sha) + + expect(response_headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to eq( + workhorse_data_header_for_version(oldest_version.sha) + ) + end + + private + + def workhorse_data_header_for_version(ref) + blob = project.design_repository.blob_at(ref, design.full_path) + + Gitlab::Workhorse.send_git_blob(project.design_repository, blob).last + end +end diff --git a/spec/features/projects/issues/design_management/user_views_design_spec.rb b/spec/features/projects/issues/design_management/user_views_design_spec.rb new file mode 100644 index 00000000000..707049b0068 --- /dev/null +++ b/spec/features/projects/issues/design_management/user_views_design_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'User views issue designs', :js do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project_empty_repo, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:design) { create(:design, :with_file, issue: issue) } + + before do + enable_design_management + + visit project_issue_path(project, issue) + + click_link 'Designs' + end + + it 'opens design detail' do + click_link design.filename + + page.within(find('.js-design-header')) do + expect(page).to have_content(design.filename) + end + + expect(page).to have_selector('.js-design-image') + end +end diff --git a/spec/features/projects/issues/design_management/user_views_designs_spec.rb b/spec/features/projects/issues/design_management/user_views_designs_spec.rb new file mode 100644 index 00000000000..a4fb7456922 --- /dev/null +++ b/spec/features/projects/issues/design_management/user_views_designs_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'User views issue designs', :js do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project_empty_repo, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:design) { create(:design, :with_file, issue: issue) } + + before do + enable_design_management + end + + context 'navigates from the issue view' do + before do + visit project_issue_path(project, issue) + click_link 'Designs' + wait_for_requests + end + + it 'fetches list of designs' do + expect(page).to have_selector('.js-design-list-item', count: 1) + end + end + + context 'navigates directly to the design collection view' do + before do + visit designs_project_issue_path(project, issue) + end + + it 'expands the sidebar' do + expect(page).to have_selector('.layout-page.right-sidebar-expanded') + end + end + + context 'navigates directly to the individual design view' do + before do + visit designs_project_issue_path(project, issue, vueroute: design.filename) + end + + it 'sees the design' do + expect(page).to have_selector('.js-design-detail') + end + end +end diff --git a/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb b/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb new file mode 100644 index 00000000000..a9e4aa899a7 --- /dev/null +++ b/spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'User views an SVG design that contains XSS', :js do + include DesignManagementTestHelpers + + let(:project) { create(:project_empty_repo, :public) } + let(:issue) { create(:issue, project: project) } + let(:file) { Rails.root.join('spec', 'fixtures', 'logo_sample.svg') } + let(:design) { create(:design, :with_file, filename: 'xss.svg', file: file, issue: issue) } + + before do + enable_design_management + + visit designs_project_issue_path( + project, + issue, + { vueroute: design.filename } + ) + + wait_for_requests + end + + it 'has XSS within the SVG file' do + file_content = File.read(file) + + expect(file_content).to include("") + end + + it 'displays the SVG' do + expect(page).to have_selector("img.design-img[alt='xss.svg']", count: 1, visible: false) + end + + it 'does not execute the JavaScript within the SVG' do + # The expectation is that we can call the capybara `page.dismiss_prompt` + # method to close a JavaScript alert prompt without a `Capybara::ModalNotFound` + # being raised. + run_expectation = -> { + page.dismiss_prompt(wait: 1) + } + + # With the page loaded, there should be no alert modal + expect(run_expectation).to raise_error( + Capybara::ModalNotFound, + 'Unable to find modal dialog' + ) + + # Perform a negative control test of the above expectation. + # With an alert modal displaying, the modal should be dismissable. + execute_script('alert(true)') + + expect(run_expectation).not_to raise_error + end +end diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index 84000ef73ce..f404699b2f6 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -34,7 +34,7 @@ describe 'Project members list' do expect(second_row).to be_blank end - it 'update user acess level', :js do + it 'update user access level', :js do project.add_developer(user2) visit_members_page @@ -86,6 +86,23 @@ describe 'Project members list' do end end + context 'project bots' do + let(:project_bot) { create(:user, :project_bot, name: 'project_bot') } + + before do + project.add_maintainer(project_bot) + end + + it 'does not show form used to change roles and "Expiration date" or the remove user button' do + project_member = project.project_members.find_by(user_id: project_bot.id) + + visit_members_page + + expect(page).not_to have_selector("#edit_project_member_#{project_member.id}") + expect(page).not_to have_selector("#project_member_#{project_member.id} .btn-remove") + end + end + def add_user(id, role) page.within ".invite-users-form" do select2(id, from: "#user_ids", multiple: true) diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 9dfdaf54a2f..1797ca8aa7d 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -12,6 +12,8 @@ describe 'Project navbar' do let_it_be(:project) { create(:project, :repository) } before do + stub_licensed_features(service_desk: false) + project.add_maintainer(user) sign_in(user) end @@ -40,7 +42,7 @@ describe 'Project navbar' do context 'when pages are available' do before do - allow(Gitlab.config.pages).to receive(:enabled).and_return(true) + stub_config(pages: { enabled: true }) insert_after_sub_nav_item( _('Operations'), @@ -53,4 +55,21 @@ describe 'Project navbar' do it_behaves_like 'verified navigation bar' end + + context 'when container registry is available' do + before do + stub_config(registry: { enabled: true }) + + insert_after_nav_item( + _('Operations'), + new_nav_item: { + nav_item: _('Packages & Registries'), + nav_sub_items: [_('Container Registry')] + } + ) + visit project_path(project) + end + + it_behaves_like 'verified navigation bar' + end end diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index e8846b5b617..de81547887b 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -19,32 +19,32 @@ describe 'Pipeline', :js do shared_context 'pipeline builds' do let!(:build_passed) do create(:ci_build, :success, - pipeline: pipeline, stage: 'build', name: 'build') + pipeline: pipeline, stage: 'build', stage_idx: 0, name: 'build') end let!(:build_failed) do create(:ci_build, :failed, - pipeline: pipeline, stage: 'test', name: 'test') + pipeline: pipeline, stage: 'test', stage_idx: 1, name: 'test') end let!(:build_preparing) do create(:ci_build, :preparing, - pipeline: pipeline, stage: 'deploy', name: 'prepare') + pipeline: pipeline, stage: 'deploy', stage_idx: 2, name: 'prepare') end let!(:build_running) do create(:ci_build, :running, - pipeline: pipeline, stage: 'deploy', name: 'deploy') + pipeline: pipeline, stage: 'deploy', stage_idx: 3, name: 'deploy') end let!(:build_manual) do create(:ci_build, :manual, - pipeline: pipeline, stage: 'deploy', name: 'manual-build') + pipeline: pipeline, stage: 'deploy', stage_idx: 3, name: 'manual-build') end let!(:build_scheduled) do create(:ci_build, :scheduled, - pipeline: pipeline, stage: 'deploy', name: 'delayed-job') + pipeline: pipeline, stage: 'deploy', stage_idx: 3, name: 'delayed-job') end let!(:build_external) do @@ -307,9 +307,12 @@ describe 'Pipeline', :js do context 'when the pipeline has manual stage' do before do - create(:ci_build, :manual, pipeline: pipeline, stage: 'publish', name: 'CentOS') - create(:ci_build, :manual, pipeline: pipeline, stage: 'publish', name: 'Debian') - create(:ci_build, :manual, pipeline: pipeline, stage: 'publish', name: 'OpenSUDE') + create(:ci_build, :manual, pipeline: pipeline, stage_idx: 10, stage: 'publish', name: 'CentOS') + create(:ci_build, :manual, pipeline: pipeline, stage_idx: 10, stage: 'publish', name: 'Debian') + create(:ci_build, :manual, pipeline: pipeline, stage_idx: 10, stage: 'publish', name: 'OpenSUDE') + + # force to update stages statuses + Ci::ProcessPipelineService.new(pipeline).execute visit_pipeline end @@ -324,9 +327,10 @@ describe 'Pipeline', :js do visit_pipeline end - it 'shows Pipeline, Jobs and Failed Jobs tabs with link' do + it 'shows Pipeline, Jobs, DAG and Failed Jobs tabs with link' do expect(page).to have_link('Pipeline') expect(page).to have_link('Jobs') + expect(page).to have_link('DAG') expect(page).to have_link('Failed Jobs') end @@ -611,6 +615,20 @@ describe 'Pipeline', :js do end end end + + context 'when FF dag_pipeline_tab is disabled' do + before do + stub_feature_flags(dag_pipeline_tab: false) + visit_pipeline + end + + it 'does not show DAG link' do + expect(page).to have_link('Pipeline') + expect(page).to have_link('Jobs') + expect(page).not_to have_link('DAG') + expect(page).to have_link('Failed Jobs') + end + end end context 'when user does not have access to read jobs' do @@ -862,9 +880,10 @@ describe 'Pipeline', :js do end context 'page tabs' do - it 'shows Pipeline and Jobs tabs with link' do + it 'shows Pipeline, Jobs and DAG tabs with link' do expect(page).to have_link('Pipeline') expect(page).to have_link('Jobs') + expect(page).to have_link('DAG') end it 'shows counter in Jobs tab' do @@ -1054,6 +1073,37 @@ describe 'Pipeline', :js do end end + describe 'GET /:project/pipelines/:id/dag' do + include_context 'pipeline builds' + + let(:project) { create(:project, :repository) } + let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) } + + before do + visit dag_project_pipeline_path(project, pipeline) + end + + it 'shows DAG tab pane as active' do + expect(page).to have_css('#js-tab-dag.active', visible: false) + end + + context 'page tabs' do + it 'shows Pipeline, Jobs and DAG tabs with link' do + expect(page).to have_link('Pipeline') + expect(page).to have_link('Jobs') + expect(page).to have_link('DAG') + end + + it 'shows counter in Jobs tab' do + expect(page.find('.js-builds-counter').text).to eq(pipeline.total_size.to_s) + end + + it 'shows DAG tab as active' do + expect(page).to have_css('li.js-dag-tab-link .active') + end + end + end + context 'when user sees pipeline flags in a pipeline detail page' do let(:project) { create(:project, :repository) } diff --git a/spec/features/projects/serverless/functions_spec.rb b/spec/features/projects/serverless/functions_spec.rb index e494a0e9626..4c89af29339 100644 --- a/spec/features/projects/serverless/functions_spec.rb +++ b/spec/features/projects/serverless/functions_spec.rb @@ -40,7 +40,7 @@ describe 'Functions', :js do it_behaves_like "it's missing knative installation" end - context 'when the user has a cluster and knative installed and visits the serverless page' do + context 'when the user has a cluster and knative installed and visits the serverless page', :kubeclient do let(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) } let(:service) { cluster.platform_kubernetes } let(:environment) { create(:environment, project: project) } diff --git a/spec/features/projects/services/disable_triggers_spec.rb b/spec/features/projects/services/disable_triggers_spec.rb index 2785f74bee2..d07abb94208 100644 --- a/spec/features/projects/services/disable_triggers_spec.rb +++ b/spec/features/projects/services/disable_triggers_spec.rb @@ -3,16 +3,12 @@ require 'spec_helper' describe 'Disable individual triggers' do - let(:project) { create(:project) } - let(:user) { project.owner } + include_context 'project service activation' + let(:checkbox_selector) { 'input[type=checkbox][id$=_events]' } before do - sign_in(user) - - visit(project_settings_integrations_path(project)) - - click_link(service_name) + visit_project_integration(service_name) end context 'service has multiple supported events' do diff --git a/spec/features/projects/services/prometheus_external_alerts_spec.rb b/spec/features/projects/services/prometheus_external_alerts_spec.rb index e33b2d9a75e..1a706f20352 100644 --- a/spec/features/projects/services/prometheus_external_alerts_spec.rb +++ b/spec/features/projects/services/prometheus_external_alerts_spec.rb @@ -3,26 +3,18 @@ require 'spec_helper' describe 'Prometheus external alerts', :js do - let(:project) { create(:project) } - let(:user) { create(:user) } + include_context 'project service activation' let(:alerts_section_selector) { '.js-prometheus-alerts' } let(:alerts_section) { page.find(alerts_section_selector) } - before do - sign_in(user) - project.add_maintainer(user) - - visit_edit_service - end - context 'with manual configuration' do before do create(:prometheus_service, project: project, api_url: 'http://prometheus.example.com', manual_configuration: '1', active: true) end it 'shows the Alerts section' do - visit_edit_service + visit_project_integration('Prometheus') expect(alerts_section).to have_content('Alerts') expect(alerts_section).to have_content('Receive alerts from manually configured Prometheus servers.') @@ -33,16 +25,10 @@ describe 'Prometheus external alerts', :js do context 'with no configuration' do it 'does not show the Alerts section' do + visit_project_integration('Prometheus') wait_for_requests expect(page).not_to have_css(alerts_section_selector) end end - - private - - def visit_edit_service - visit(project_settings_integrations_path(project)) - click_link('Prometheus') - end end diff --git a/spec/features/projects/services/user_activates_issue_tracker_spec.rb b/spec/features/projects/services/user_activates_issue_tracker_spec.rb index 4f3fb6ac3bf..3c5005d0c0c 100644 --- a/spec/features/projects/services/user_activates_issue_tracker_spec.rb +++ b/spec/features/projects/services/user_activates_issue_tracker_spec.rb @@ -3,29 +3,17 @@ require 'spec_helper' describe 'User activates issue tracker', :js do - let(:user) { create(:user) } - let(:project) { create(:project) } + include_context 'project service activation' let(:url) { 'http://tracker.example.com' } - def fill_short_form(disabled: false) - find('input[name="service[active]"] + button').click if disabled + def fill_form(disable: false, skip_new_issue_url: false) + click_active_toggle if disable fill_in 'service_project_url', with: url fill_in 'service_issues_url', with: "#{url}/:id" - end - - def fill_full_form(disabled: false) - fill_short_form(disabled: disabled) - fill_in 'service_new_issue_url', with: url - end - - before do - project.add_maintainer(user) - sign_in(user) - - visit project_settings_integrations_path(project) + fill_in 'service_new_issue_url', with: url unless skip_new_issue_url end shared_examples 'external issue tracker activation' do |tracker:, skip_new_issue_url: false| @@ -34,16 +22,10 @@ describe 'User activates issue tracker', :js do before do stub_request(:head, url).to_return(headers: { 'Content-Type' => 'application/json' }) - click_link(tracker) - - if skip_new_issue_url - fill_short_form - else - fill_full_form - end + visit_project_integration(tracker) + fill_form(skip_new_issue_url: skip_new_issue_url) - click_button('Test settings and save changes') - wait_for_requests + click_test_integration end it 'activates the service' do @@ -62,22 +44,10 @@ describe 'User activates issue tracker', :js do it 'activates the service' do stub_request(:head, url).to_raise(Gitlab::HTTP::Error) - click_link(tracker) + visit_project_integration(tracker) + fill_form(skip_new_issue_url: skip_new_issue_url) - if skip_new_issue_url - fill_short_form - else - fill_full_form - end - - click_button('Test settings and save changes') - wait_for_requests - - expect(find('.flash-container-page')).to have_content 'Test failed.' - expect(find('.flash-container-page')).to have_content 'Save anyway' - - find('.flash-alert .flash-action').click - wait_for_requests + click_test_then_save_integration expect(page).to have_content("#{tracker} activated.") expect(current_path).to eq(project_settings_integrations_path(project)) @@ -87,13 +57,8 @@ describe 'User activates issue tracker', :js do describe 'user disables the service' do before do - click_link(tracker) - - if skip_new_issue_url - fill_short_form(disabled: true) - else - fill_full_form(disabled: true) - end + visit_project_integration(tracker) + fill_form(disable: true, skip_new_issue_url: skip_new_issue_url) click_button('Save changes') end diff --git a/spec/features/projects/services/user_activates_jira_spec.rb b/spec/features/projects/services/user_activates_jira_spec.rb index fb9628032b2..a14dbf9c14d 100644 --- a/spec/features/projects/services/user_activates_jira_spec.rb +++ b/spec/features/projects/services/user_activates_jira_spec.rb @@ -3,14 +3,13 @@ require 'spec_helper' describe 'User activates Jira', :js do - let(:user) { create(:user) } - let(:project) { create(:project) } + include_context 'project service activation' let(:url) { 'http://jira.example.com' } let(:test_url) { 'http://jira.example.com/rest/api/2/serverInfo' } - def fill_form(disabled: false) - find('input[name="service[active]"] + button').click if disabled + def fill_form(disable: false) + click_active_toggle if disable fill_in 'service_url', with: url fill_in 'service_username', with: 'username' @@ -18,23 +17,15 @@ describe 'User activates Jira', :js do fill_in 'service_jira_issue_transition_id', with: '25' end - before do - project.add_maintainer(user) - sign_in(user) - - visit project_settings_integrations_path(project) - end - describe 'user sets and activates Jira Service' do context 'when Jira connection test succeeds' do before do server_info = { key: 'value' }.to_json - WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info) + stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info) - click_link('Jira') + visit_project_integration('Jira') fill_form - click_button('Test settings and save changes') - wait_for_requests + click_test_integration end it 'activates the Jira service' do @@ -51,10 +42,10 @@ describe 'User activates Jira', :js do context 'when Jira connection test fails' do it 'shows errors when some required fields are not filled in' do - click_link('Jira') + visit_project_integration('Jira') fill_in 'service_password', with: 'password' - click_button('Test settings and save changes') + click_test_integration page.within('.service-settings') do expect(page).to have_content('This field is required.') @@ -62,19 +53,12 @@ describe 'User activates Jira', :js do end it 'activates the Jira service' do - WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password)) + stub_request(:get, test_url).with(basic_auth: %w(username password)) .to_raise(JIRA::HTTPError.new(double(message: 'message'))) - click_link('Jira') + visit_project_integration('Jira') fill_form - click_button('Test settings and save changes') - wait_for_requests - - expect(find('.flash-container-page')).to have_content 'Test failed. message' - expect(find('.flash-container-page')).to have_content 'Save anyway' - - find('.flash-alert .flash-action').click - wait_for_requests + click_test_then_save_integration expect(page).to have_content('Jira activated.') expect(current_path).to eq(project_settings_integrations_path(project)) @@ -84,8 +68,8 @@ describe 'User activates Jira', :js do describe 'user disables the Jira Service' do before do - click_link('Jira') - fill_form(disabled: true) + visit_project_integration('Jira') + fill_form(disable: true) click_button('Save changes') end diff --git a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb index ac9cb00be84..c6825ee663a 100644 --- a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb @@ -3,158 +3,158 @@ require 'spec_helper' describe 'Set up Mattermost slash commands', :js do - let(:user) { create(:user) } - let(:project) { create(:project) } - let(:mattermost_enabled) { true } - - before do - stub_mattermost_setting(enabled: mattermost_enabled) - project.add_maintainer(user) - sign_in(user) - visit edit_project_service_path(project, :mattermost_slash_commands) - end - describe 'user visits the mattermost slash command config page' do - it 'shows a help message' do - expect(page).to have_content("This service allows users to perform common") + include_context 'project service activation' + + before do + stub_mattermost_setting(enabled: mattermost_enabled) + visit_project_integration('Mattermost slash commands') end - it 'shows a token placeholder' do - token_placeholder = find_field('service_token')['placeholder'] + context 'mattermost service is enabled' do + let(:mattermost_enabled) { true } - expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx') - end + it 'shows a help message' do + expect(page).to have_content("This service allows users to perform common") + end - it 'redirects to the integrations page after saving but not activating' do - token = ('a'..'z').to_a.join + it 'shows a token placeholder' do + token_placeholder = find_field('service_token')['placeholder'] - fill_in 'service_token', with: token - find('input[name="service[active]"] + button').click - click_on 'Save changes' + expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx') + end - expect(current_path).to eq(project_settings_integrations_path(project)) - expect(page).to have_content('Mattermost slash commands settings saved, but not activated.') - end + it 'redirects to the integrations page after saving but not activating' do + token = ('a'..'z').to_a.join - it 'redirects to the integrations page after activating' do - token = ('a'..'z').to_a.join + fill_in 'service_token', with: token + click_active_toggle + click_on 'Save changes' - fill_in 'service_token', with: token - click_on 'Save changes' + expect(current_path).to eq(project_settings_integrations_path(project)) + expect(page).to have_content('Mattermost slash commands settings saved, but not activated.') + end - expect(current_path).to eq(project_settings_integrations_path(project)) - expect(page).to have_content('Mattermost slash commands activated.') - end + it 'redirects to the integrations page after activating' do + token = ('a'..'z').to_a.join - it 'shows the add to mattermost button' do - expect(page).to have_link('Add to Mattermost') - end + fill_in 'service_token', with: token + click_on 'Save changes' - it 'shows an explanation if user is a member of no teams' do - stub_teams(count: 0) + expect(current_path).to eq(project_settings_integrations_path(project)) + expect(page).to have_content('Mattermost slash commands activated.') + end - click_link 'Add to Mattermost' + it 'shows the add to mattermost button' do + expect(page).to have_link('Add to Mattermost') + end - expect(page).to have_content('You aren’t a member of any team on the Mattermost instance') - expect(page).to have_link('join a team', href: "#{Gitlab.config.mattermost.host}/select_team") - end + it 'shows an explanation if user is a member of no teams' do + stub_teams(count: 0) - it 'shows an explanation if user is a member of 1 team' do - stub_teams(count: 1) + click_link 'Add to Mattermost' - click_link 'Add to Mattermost' + expect(page).to have_content('You aren’t a member of any team on the Mattermost instance') + expect(page).to have_link('join a team', href: "#{Gitlab.config.mattermost.host}/select_team") + end - expect(page).to have_content('The team where the slash commands will be used in') - expect(page).to have_content('This is the only available team that you are a member of.') - end + it 'shows an explanation if user is a member of 1 team' do + stub_teams(count: 1) - it 'shows a disabled prefilled select if user is a member of 1 team' do - teams = stub_teams(count: 1) + click_link 'Add to Mattermost' - click_link 'Add to Mattermost' + expect(page).to have_content('The team where the slash commands will be used in') + expect(page).to have_content('This is the only available team that you are a member of.') + end - team_name = teams.first['display_name'] - select_element = find('#mattermost_team_id') - selected_option = select_element.find('option[selected]') + it 'shows a disabled prefilled select if user is a member of 1 team' do + teams = stub_teams(count: 1) - expect(select_element['disabled']).to eq("true") - expect(selected_option).to have_content(team_name.to_s) - end + click_link 'Add to Mattermost' - it 'has a hidden input for the prefilled value if user is a member of 1 team' do - teams = stub_teams(count: 1) + team_name = teams.first['display_name'] + select_element = find('#mattermost_team_id') + selected_option = select_element.find('option[selected]') - click_link 'Add to Mattermost' + expect(select_element['disabled']).to eq("true") + expect(selected_option).to have_content(team_name.to_s) + end - expect(find('input#mattermost_team_id', visible: false).value).to eq(teams.first['id']) - end + it 'has a hidden input for the prefilled value if user is a member of 1 team' do + teams = stub_teams(count: 1) - it 'shows an explanation user is a member of multiple teams' do - stub_teams(count: 2) + click_link 'Add to Mattermost' - click_link 'Add to Mattermost' + expect(find('input#mattermost_team_id', visible: false).value).to eq(teams.first['id']) + end - expect(page).to have_content('Select the team where the slash commands will be used in') - expect(page).to have_content('The list shows all available teams that you are a member of.') - end + it 'shows an explanation user is a member of multiple teams' do + stub_teams(count: 2) - it 'shows a select with team options user is a member of multiple teams' do - stub_teams(count: 2) + click_link 'Add to Mattermost' - click_link 'Add to Mattermost' + expect(page).to have_content('Select the team where the slash commands will be used in') + expect(page).to have_content('The list shows all available teams that you are a member of.') + end - select_element = find('#mattermost_team_id') + it 'shows a select with team options user is a member of multiple teams' do + stub_teams(count: 2) - expect(select_element['disabled']).to be_falsey - expect(select_element.all('option').count).to eq(3) - end + click_link 'Add to Mattermost' - it 'shows an error alert with the error message if there is an error requesting teams' do - allow_any_instance_of(MattermostSlashCommandsService).to receive(:list_teams) { [[], 'test mattermost error message'] } + select_element = find('#mattermost_team_id') - click_link 'Add to Mattermost' + expect(select_element['disabled']).to be_falsey + expect(select_element.all('option').count).to eq(3) + end - expect(page).to have_selector('.alert') - expect(page).to have_content('test mattermost error message') - end + it 'shows an error alert with the error message if there is an error requesting teams' do + allow_any_instance_of(MattermostSlashCommandsService).to receive(:list_teams) { [[], 'test mattermost error message'] } - it 'enables the submit button if the required fields are provided', :js do - stub_teams(count: 1) + click_link 'Add to Mattermost' - click_link 'Add to Mattermost' + expect(page).to have_selector('.alert') + expect(page).to have_content('test mattermost error message') + end - expect(find('input[type="submit"]')['disabled']).not_to eq("true") - end + it 'enables the submit button if the required fields are provided', :js do + stub_teams(count: 1) - it 'disables the submit button if the required fields are not provided', :js do - stub_teams(count: 1) + click_link 'Add to Mattermost' - click_link 'Add to Mattermost' + expect(find('input[type="submit"]')['disabled']).not_to eq("true") + end - fill_in('mattermost_trigger', with: '') + it 'disables the submit button if the required fields are not provided', :js do + stub_teams(count: 1) - expect(find('input[type="submit"]')['disabled']).to eq("true") - end + click_link 'Add to Mattermost' - def stub_teams(count: 0) - teams = create_teams(count) + fill_in('mattermost_trigger', with: '') - allow_any_instance_of(MattermostSlashCommandsService).to receive(:list_teams) { [teams, nil] } + expect(find('input[type="submit"]')['disabled']).to eq("true") + end - teams - end + def stub_teams(count: 0) + teams = create_teams(count) - def create_teams(count = 0) - teams = [] + allow_any_instance_of(MattermostSlashCommandsService).to receive(:list_teams) { [teams, nil] } - count.times do |i| - teams.push({ "id" => "x#{i}", "display_name" => "x#{i}-name" }) + teams end - teams + def create_teams(count = 0) + teams = [] + + count.times do |i| + teams.push({ "id" => "x#{i}", "display_name" => "x#{i}-name" }) + end + + teams + end end - describe 'mattermost service is not enabled' do + context 'mattermost service is not enabled' do let(:mattermost_enabled) { false } it 'shows the correct trigger url' do diff --git a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb index 4ce1acd9377..05f1a0c6b17 100644 --- a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb @@ -3,13 +3,10 @@ require 'spec_helper' describe 'Slack slash commands' do - let(:user) { create(:user) } - let(:project) { create(:project) } + include_context 'project service activation' before do - project.add_maintainer(user) - sign_in(user) - visit edit_project_service_path(project, :slack_slash_commands) + visit_project_integration('Slack slash commands') end it 'shows a token placeholder' do @@ -24,7 +21,7 @@ describe 'Slack slash commands' do it 'redirects to the integrations page after saving but not activating', :js do fill_in 'service_token', with: 'token' - find('input[name="service[active]"] + button').click + click_active_toggle click_on 'Save' expect(current_path).to eq(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_youtrack_spec.rb b/spec/features/projects/services/user_activates_youtrack_spec.rb deleted file mode 100644 index 26734766ff0..00000000000 --- a/spec/features/projects/services/user_activates_youtrack_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe 'User activates issue tracker', :js do - let(:user) { create(:user) } - let(:project) { create(:project) } - - let(:url) { 'http://tracker.example.com' } - - def fill_form(disabled: false) - find('input[name="service[active]"] + button').click if disabled - - fill_in 'service_project_url', with: url - fill_in 'service_issues_url', with: "#{url}/:id" - end - - before do - project.add_maintainer(user) - sign_in(user) - - visit project_settings_integrations_path(project) - end - - shared_examples 'external issue tracker activation' do |tracker:| - describe 'user sets and activates the Service' do - context 'when the connection test succeeds' do - before do - stub_request(:head, url).to_return(headers: { 'Content-Type' => 'application/json' }) - - click_link(tracker) - fill_form - click_button('Test settings and save changes') - wait_for_requests - end - - it 'activates the service' do - expect(page).to have_content("#{tracker} activated.") - expect(current_path).to eq(project_settings_integrations_path(project)) - end - - it 'shows the link in the menu' do - page.within('.nav-sidebar') do - expect(page).to have_link(tracker, href: url) - end - end - end - - context 'when the connection test fails' do - it 'activates the service' do - stub_request(:head, url).to_raise(Gitlab::HTTP::Error) - - click_link(tracker) - fill_form - click_button('Test settings and save changes') - wait_for_requests - - expect(find('.flash-container-page')).to have_content 'Test failed.' - expect(find('.flash-container-page')).to have_content 'Save anyway' - - find('.flash-alert .flash-action').click - wait_for_requests - - expect(page).to have_content("#{tracker} activated.") - expect(current_path).to eq(project_settings_integrations_path(project)) - end - end - end - - describe 'user disables the service' do - before do - click_link(tracker) - fill_form(disabled: true) - click_button('Save changes') - end - - it 'saves but does not activate the service' do - expect(page).to have_content("#{tracker} settings saved, but not activated.") - expect(current_path).to eq(project_settings_integrations_path(project)) - end - - it 'does not show the external tracker link in the menu' do - page.within('.nav-sidebar') do - expect(page).not_to have_link(tracker, href: url) - end - end - end - end - - it_behaves_like 'external issue tracker activation', tracker: 'YouTrack' -end diff --git a/spec/features/projects/settings/access_tokens_spec.rb b/spec/features/projects/settings/access_tokens_spec.rb new file mode 100644 index 00000000000..9a8a8e38164 --- /dev/null +++ b/spec/features/projects/settings/access_tokens_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Project > Settings > Access Tokens', :js do + let_it_be(:user) { create(:user) } + let_it_be(:bot_user) { create(:user, :project_bot) } + let_it_be(:project) { create(:project) } + + before_all do + project.add_maintainer(user) + end + + before do + sign_in(user) + end + + def create_project_access_token + project.add_maintainer(bot_user) + + create(:personal_access_token, user: bot_user) + end + + def active_project_access_tokens + find('.table.active-tokens') + end + + def no_project_access_tokens_message + find('.settings-message') + end + + def created_project_access_token + find('#created-personal-access-token').value + end + + describe 'token creation' do + it 'allows creation of a project access token' do + name = 'My project access token' + + visit project_settings_access_tokens_path(project) + fill_in 'Name', with: name + + # Set date to 1st of next month + find_field('Expires at').click + find('.pika-next').click + click_on '1' + + # Scopes + check 'api' + check 'read_api' + + click_on 'Create project access token' + + expect(active_project_access_tokens).to have_text(name) + expect(active_project_access_tokens).to have_text('In') + expect(active_project_access_tokens).to have_text('api') + expect(active_project_access_tokens).to have_text('read_api') + expect(created_project_access_token).not_to be_empty + end + end + + describe 'active tokens' do + let!(:project_access_token) { create_project_access_token } + + it 'shows active project access tokens' do + visit project_settings_access_tokens_path(project) + + expect(active_project_access_tokens).to have_text(project_access_token.name) + end + end + + describe 'inactive tokens' do + let!(:project_access_token) { create_project_access_token } + + no_active_tokens_text = 'This project has no active access tokens.' + + it 'allows revocation of an active token' do + visit project_settings_access_tokens_path(project) + accept_confirm { click_on 'Revoke' } + + expect(page).to have_selector('.settings-message') + expect(no_project_access_tokens_message).to have_text(no_active_tokens_text) + end + + it 'removes expired tokens from active section' do + project_access_token.update(expires_at: 5.days.ago) + visit project_settings_access_tokens_path(project) + + expect(page).to have_selector('.settings-message') + expect(no_project_access_tokens_message).to have_text(no_active_tokens_text) + end + end +end diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb index 3c9102431e8..752353cf2f5 100644 --- a/spec/features/projects/settings/operations_settings_spec.rb +++ b/spec/features/projects/settings/operations_settings_spec.rb @@ -76,7 +76,7 @@ describe 'Projects > Settings > For a forked project', :js do context 'success path' do let(:projects_sample_response) do Gitlab::Utils.deep_indifferent_access( - JSON.parse(fixture_file('sentry/list_projects_sample_response.json')) + Gitlab::Json.parse(fixture_file('sentry/list_projects_sample_response.json')) ) end diff --git a/spec/features/projects/settings/project_settings_spec.rb b/spec/features/projects/settings/project_settings_spec.rb index 9fc91550667..171c7920878 100644 --- a/spec/features/projects/settings/project_settings_spec.rb +++ b/spec/features/projects/settings/project_settings_spec.rb @@ -54,6 +54,36 @@ describe 'Projects settings' do end end + context 'default award emojis', :js do + it 'shows award emojis by default' do + visit edit_project_path(project) + + default_award_emojis_input = find('input[name="project[project_setting_attributes][show_default_award_emojis]"]', visible: :hidden) + + expect(default_award_emojis_input.value).to eq('true') + end + + it 'disables award emojis when the checkbox is toggled off' do + visit edit_project_path(project) + + default_award_emojis_input = find('input[name="project[project_setting_attributes][show_default_award_emojis]"]', visible: :hidden) + default_award_emojis_checkbox = find('input[name="project[project_setting_attributes][show_default_award_emojis]"][type=checkbox]') + + expect(default_award_emojis_input.value).to eq('true') + + default_award_emojis_checkbox.click + + expect(default_award_emojis_input.value).to eq('false') + + page.within('.sharing-permissions') do + find('input[value="Save changes"]').click + end + wait_for_requests + + expect(default_award_emojis_input.value).to eq('false') + end + end + def expect_toggle_state(state) is_collapsed = state == :collapsed diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb index 74d3544ce92..ba92e8bc516 100644 --- a/spec/features/projects/settings/registry_settings_spec.rb +++ b/spec/features/projects/settings/registry_settings_spec.rb @@ -29,7 +29,7 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy' 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('Docker tags with names matching this regex pattern will expire:', with: '*-production') + fill_in('Tags with names matching this regex pattern will expire:', with: '*-production') end submit_button = find('.card-footer .btn.btn-success') expect(submit_button).not_to be_disabled diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 2fb6c71384f..b8baaa3e963 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -30,7 +30,7 @@ describe 'Projects > Settings > Repository settings' do before do stub_container_registry_config(enabled: true) - stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project }) + stub_feature_flags(ajax_new_deploy_token: project) visit project_settings_repository_path(project) end @@ -222,20 +222,6 @@ describe 'Projects > Settings > Repository settings' do end end - # Removal: https://gitlab.com/gitlab-org/gitlab/-/issues/208828 - context 'with the `keep_divergent_refs` feature flag disabled' do - before do - stub_feature_flags(keep_divergent_refs: { enabled: false, thing: project }) - end - - it 'hides the "Keep divergent refs" option' do - visit project_settings_repository_path(project) - - expect(page).not_to have_selector('#keep_divergent_refs') - expect(page).not_to have_text('Keep divergent refs') - end - end - context 'repository cleanup settings' do let(:object_map_file) { Rails.root.join('spec', 'fixtures', 'bfg_object_map.txt') } 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 cd9299150b2..45a16fda2cb 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 @@ -88,18 +88,18 @@ describe "User interacts with deploy keys", :js do end it "adds new key" do - DEPLOY_KEY_TITLE = attributes_for(:key)[:title] - DEPLOY_KEY_BODY = attributes_for(:key)[:key] + deploy_key_title = attributes_for(:key)[:title] + deploy_key_body = attributes_for(:key)[:key] - fill_in("deploy_key_title", with: DEPLOY_KEY_TITLE) - fill_in("deploy_key_key", with: DEPLOY_KEY_BODY) + fill_in("deploy_key_title", with: deploy_key_title) + fill_in("deploy_key_key", with: deploy_key_body) click_button("Add key") expect(current_path).to eq(project_settings_repository_path(project)) page.within(".deploy-keys") do - expect(page).to have_content(DEPLOY_KEY_TITLE) + expect(page).to have_content(deploy_key_title) end end end diff --git a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb index a77240c5c33..0abc4b41a2b 100644 --- a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb +++ b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb @@ -11,7 +11,7 @@ describe 'Repository Settings > User sees revoke deploy token modal', :js do before do project.add_role(user, role) sign_in(user) - stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project }) + stub_feature_flags(ajax_new_deploy_token: project) visit(project_settings_repository_path(project)) click_link('Revoke') end diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index d883a1fc39c..1e8f9fa0875 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -5,7 +5,6 @@ require 'spec_helper' shared_examples_for 'snippet editor' do before do stub_feature_flags(snippets_edit_vue: false) - stub_feature_flags(monaco_snippets: flag) end def description_field @@ -20,7 +19,7 @@ shared_examples_for 'snippet editor' do fill_in 'project_snippet_description', with: 'My Snippet **Description**' page.within('.file-editor') do - el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false) + el = find('.inputarea') el.send_keys 'Hello World!' end end @@ -100,7 +99,7 @@ shared_examples_for 'snippet editor' do end context 'when the git operation fails' do - let(:error) { 'This is a git error' } + let(:error) { 'Error creating the snippet' } before do allow_next_instance_of(Snippets::CreateService) do |instance| @@ -145,15 +144,5 @@ describe 'Projects > Snippets > Create Snippet', :js do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public) } - context 'when using Monaco' do - it_behaves_like "snippet editor" do - let(:flag) { true } - end - end - - context 'when using ACE' do - it_behaves_like "snippet editor" do - let(:flag) { false } - end - end + it_behaves_like "snippet editor" end diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb index cf501e55e23..d19fe9e8d38 100644 --- a/spec/features/projects/snippets/user_updates_snippet_spec.rb +++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb @@ -7,12 +7,9 @@ describe 'Projects > Snippets > User updates a snippet', :js do let_it_be(:project) { create(:project, namespace: user.namespace) } let_it_be(:snippet, reload: true) { create(:project_snippet, :repository, project: project, author: user) } - let(:version_snippet_enabled) { true } - before do stub_feature_flags(snippets_vue: false) stub_feature_flags(snippets_edit_vue: false) - stub_feature_flags(version_snippets: version_snippet_enabled) project.add_maintainer(user) sign_in(user) @@ -35,18 +32,6 @@ describe 'Projects > Snippets > User updates a snippet', :js do end end - context 'when feature flag :version_snippets is disabled' do - let(:version_snippet_enabled) { false } - - it 'displays the snippet file_name and content' do - aggregate_failures do - expect(page.find_field('project_snippet_file_name').value).to eq snippet.file_name - expect(page.find('.file-content')).to have_content(snippet.content) - expect(page.find('.snippet-file-content', visible: false).value).to eq snippet.content - end - end - end - it 'updates a snippet' do fill_in('project_snippet_title', with: 'Snippet new title') click_button('Save') @@ -57,16 +42,17 @@ describe 'Projects > Snippets > User updates a snippet', :js do context 'when the git operation fails' do before do allow_next_instance_of(Snippets::UpdateService) do |instance| - allow(instance).to receive(:create_commit).and_raise(StandardError) + allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message') end fill_in('project_snippet_title', with: 'Snippet new title') + fill_in('project_snippet_file_name', with: 'new_file_name') click_button('Save') end it 'renders edit page and displays the error' do - expect(page.find('.flash-container span').text).to eq('Error updating the snippet') + expect(page.find('.flash-container span').text).to eq('Error updating the snippet - Error Message') expect(page).to have_content('Edit Snippet') end end diff --git a/spec/features/projects/user_sees_user_popover_spec.rb b/spec/features/projects/user_sees_user_popover_spec.rb index fafb3773866..6197460776d 100644 --- a/spec/features/projects/user_sees_user_popover_spec.rb +++ b/spec/features/projects/user_sees_user_popover_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe 'User sees user popover', :js do + include Spec::Support::Helpers::Features::NotesHelpers + let_it_be(:project) { create(:project, :repository) } let(:user) { project.creator } let(:merge_request) do @@ -17,13 +19,13 @@ describe 'User sees user popover', :js do subject { page } describe 'hovering over a user link in a merge request' do + let(:popover_selector) { '.user-popover' } + before do visit project_merge_request_path(project, merge_request) end it 'displays user popover' do - popover_selector = '.user-popover' - find('.js-user-link').hover expect(page).to have_css(popover_selector, visible: true) @@ -32,5 +34,17 @@ describe 'User sees user popover', :js do expect(page).to have_content(user.name) end end + + it "displays user popover in system note" do + add_note("/assign @#{user.username}") + + wait_for_requests + + find('.system-note-message .js-user-link').hover + + page.within(popover_selector) do + expect(page).to have_content(user.name) + end + end end end diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 7d18c0f7a14..bc567d4db42 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe 'Projects > Wiki > User previews markdown changes', :js do let_it_be(:user) { create(:user) } let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' }) } + let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') } let(:wiki_content) do <<-HEREDOC [regular link](regular) diff --git a/spec/features/projects/wiki/shortcuts_spec.rb b/spec/features/projects/wiki/shortcuts_spec.rb index 806d2f28bb9..c51af2526c9 100644 --- a/spec/features/projects/wiki/shortcuts_spec.rb +++ b/spec/features/projects/wiki/shortcuts_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe 'Wiki shortcuts', :js do let(:user) { create(:user) } let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: 'Home page' }) } + let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: 'Home page') } before do sign_in(user) diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index 67996cc3e5d..5678ebcb72a 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -195,7 +195,7 @@ describe "User creates wiki page" do context "when wiki is not empty", :js do before do - create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'Home page' }) + create(:wiki_page, wiki: wiki, title: 'home', content: 'Home page') visit(project_wikis_path(project)) end @@ -304,19 +304,20 @@ describe "User creates wiki page" do describe 'sidebar feature' do context 'when there are some existing pages' do before do - create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'home' }) - create(:wiki_page, wiki: wiki, attrs: { title: 'another', content: 'another' }) + create(:wiki_page, wiki: wiki, title: 'home', content: 'home') + create(:wiki_page, wiki: wiki, title: 'another', content: 'another') end it 'renders a default sidebar when there is no customized sidebar' do visit(project_wikis_path(project)) expect(page).to have_content('another') + expect(page).not_to have_link('View All Pages') end context 'when there is a customized sidebar' do before do - create(:wiki_page, wiki: wiki, attrs: { title: '_sidebar', content: 'My customized sidebar' }) + create(:wiki_page, wiki: wiki, title: '_sidebar', content: 'My customized sidebar') end it 'renders my customized sidebar instead of the default one' do @@ -328,17 +329,31 @@ describe "User creates wiki page" do end end - context 'when there are more than 15 existing pages' do + context 'when there are 15 existing pages' do before do - create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'home' }) - (1..14).each { |i| create(:wiki_page, wiki: wiki, attrs: { title: "page-#{i}", content: "page #{i}" }) } + (1..5).each { |i| create(:wiki_page, wiki: wiki, title: "my page #{i}") } + (6..10).each { |i| create(:wiki_page, wiki: wiki, title: "parent/my page #{i}") } + (11..15).each { |i| create(:wiki_page, wiki: wiki, title: "grandparent/parent/my page #{i}") } end - it 'renders a default sidebar when there is no customized sidebar' do + it 'shows all pages in the sidebar' do visit(project_wikis_path(project)) - expect(page).to have_content('View All Pages') - expect(page).to have_content('page 1') + (1..15).each { |i| expect(page).to have_content("my page #{i}") } + expect(page).not_to have_link('View All Pages') + end + + context 'when there are more than 15 existing pages' do + before do + create(:wiki_page, wiki: wiki, title: 'my page 16') + end + + it 'shows the first 15 pages in the sidebar' do + visit(project_wikis_path(project)) + + expect(page).to have_text('my page', count: 15) + expect(page).to have_link('View All Pages') + end end 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 index ab3d912dd15..6c6af1c41d2 100644 --- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' 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, attrs: { title: 'home', content: '[some link](other-page)' }) } + let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') } before do sign_in(user) diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index 9d9c83331fb..55509ddfa10 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -64,7 +64,7 @@ describe 'User updates wiki page' do context 'when wiki is not empty' do let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) } - let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: 'home', content: 'Home page' }) } + let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: 'home', content: 'Home page') } before do visit(project_wikis_path(project)) @@ -168,7 +168,7 @@ describe 'User updates wiki page' do let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) } let(:page_name) { 'page_name' } let(:page_dir) { "foo/bar/#{page_name}" } - let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: page_dir, content: 'Home page' }) } + let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: page_dir, content: 'Home page') } before do visit(project_wiki_edit_path(project, wiki_page)) diff --git a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb index 471e80b27dc..cb425e8b704 100644 --- a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb @@ -21,7 +21,7 @@ describe 'Projects > Wiki > User views wiki in project page' do context 'when wiki homepage contains a link' do before do - create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' }) + create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') end it 'displays the correct URL for the link' do diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb index 8a338756323..e379e7466db 100644 --- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb @@ -11,7 +11,7 @@ describe 'User views a wiki page' do let(:wiki_page) do create(:wiki_page, wiki: project.wiki, - attrs: { title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" }) + title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})") end before do diff --git a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb index 6740df1d4ed..584b2a76143 100644 --- a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb @@ -9,13 +9,13 @@ describe 'User views wiki pages' do let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } let!(:wiki_page1) do - create(:wiki_page, wiki: project.wiki, attrs: { title: '3 home', content: '3' }) + create(:wiki_page, wiki: project.wiki, title: '3 home', content: '3') end let!(:wiki_page2) do - create(:wiki_page, wiki: project.wiki, attrs: { title: '1 home', content: '1' }) + create(:wiki_page, wiki: project.wiki, title: '1 home', content: '1') end let!(:wiki_page3) do - create(:wiki_page, wiki: project.wiki, attrs: { title: '2 home', content: '2' }) + create(:wiki_page, wiki: project.wiki, title: '2 home', content: '2') end let(:pages) do diff --git a/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb b/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb index 08eea14c438..014b63fa154 100644 --- a/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb +++ b/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb @@ -16,7 +16,7 @@ describe 'User views AsciiDoc page with includes', :js do format: :asciidoc } - create(:wiki_page, wiki: project.wiki, attrs: attrs) + create(:wiki_page, wiki: project.wiki, **attrs) end before do diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb index 9949595fddf..0fdc7346535 100644 --- a/spec/features/search/user_searches_for_code_spec.rb +++ b/spec/features/search/user_searches_for_code_spec.rb @@ -40,6 +40,9 @@ describe 'User searches for code' do find('.btn-search').click expect(page).to have_selector('.results', text: 'Update capybara, rspec-rails, poltergeist to recent versions') + + find("#L3").click + expect(current_url).to match(/master\/.gitignore#L3/) end it 'search mutiple words with refs switching' do @@ -57,6 +60,7 @@ describe 'User searches for code' do expect(page).to have_selector('.results', text: expected_result) expect(find_field('dashboard_search').value).to eq(search) + expect(find("#L1502")[:href]).to match(/v1.0.0\/files\/markdown\/ruby-style-guide.md#L1502/) end end 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 1ae37447bdc..10c3032da8b 100644 --- a/spec/features/search/user_searches_for_wiki_pages_spec.rb +++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe 'User searches for wiki pages', :js do let(:user) { create(:user) } let(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) } - let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'directory/title', content: 'Some Wiki content' }) } + let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'directory/title', content: 'Some Wiki content') } before do project.add_maintainer(user) diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 45b57b5cb1b..f29aa8de928 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -464,9 +464,9 @@ describe "Internal Project Access" do 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) } - it { is_expected.to be_denied_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } + it { is_expected.to be_allowed_for(:reporter).of(project) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } it { is_expected.to be_denied_for(:external) } it { is_expected.to be_denied_for(:visitor) } end diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index 9aeb3ffbd43..ac8596d89bc 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -499,7 +499,7 @@ describe "Private Project Access" do 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) } - it { is_expected.to be_denied_for(:reporter).of(project) } + it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } it { is_expected.to be_denied_for(:user) } it { is_expected.to be_denied_for(:external) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 4d8c2c7822c..11e9bff10a1 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -278,11 +278,11 @@ describe "Public Project Access" do 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) } - it { is_expected.to be_denied_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } - it { is_expected.to be_denied_for(:external) } - it { is_expected.to be_denied_for(:visitor) } + it { is_expected.to be_allowed_for(:reporter).of(project) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } + it { is_expected.to be_allowed_for(:external) } + it { is_expected.to be_allowed_for(:visitor) } end describe "GET /:project_path/-/environments" do diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb index 691716d3576..d3e02d43813 100644 --- a/spec/features/snippets/search_snippets_spec.rb +++ b/spec/features/snippets/search_snippets_spec.rb @@ -11,7 +11,7 @@ describe 'Search Snippets' do visit dashboard_snippets_path submit_search('Middle') - select_search_scope('Titles and Filenames') + select_search_scope('Titles and Descriptions') expect(page).to have_link(public_snippet.title) expect(page).to have_link(private_snippet.title) diff --git a/spec/features/snippets/spam_snippets_spec.rb b/spec/features/snippets/spam_snippets_spec.rb index 69e3f190725..d7b181dc678 100644 --- a/spec/features/snippets/spam_snippets_spec.rb +++ b/spec/features/snippets/spam_snippets_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' shared_examples_for 'snippet editor' do + include_context 'includes Spam constants' + def description_field find('.js-description-input').find('input,textarea') end @@ -11,7 +13,6 @@ shared_examples_for 'snippet editor' do stub_feature_flags(allow_possible_spam: false) stub_feature_flags(snippets_vue: false) stub_feature_flags(snippets_edit_vue: false) - stub_feature_flags(monaco_snippets: flag) stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') Gitlab::CurrentSettings.update!( @@ -33,18 +34,18 @@ shared_examples_for 'snippet editor' do find('#personal_snippet_visibility_level_20').set(true) page.within('.file-editor') do - el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false) + el = find('.inputarea') el.send_keys 'Hello World!' end end - shared_examples 'solve recaptcha' do - it 'creates a snippet after solving reCaptcha' do + shared_examples 'solve reCAPTCHA' do + it 'creates a snippet after solving reCAPTCHA' do click_button('Create snippet') wait_for_requests - # it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha - # recaptcha verification is skipped in test environment and it always returns true + # it is impossible to test reCAPTCHA automatically and there is no possibility to fill in recaptcha + # reCAPTCHA verification is skipped in test environment and it always returns true expect(page).not_to have_content('My Snippet Title') expect(page).to have_css('.recaptcha') click_button('Submit personal snippet') @@ -53,23 +54,62 @@ shared_examples_for 'snippet editor' do end end - context 'when identified as spam' do + shared_examples 'does not allow creation' do + it 'rejects creation of the snippet' do + click_button('Create snippet') + wait_for_requests + + expect(page).to have_content('discarded') + expect(page).not_to have_content('My Snippet Title') + expect(page).not_to have_css('.recaptcha') + end + end + + context 'when SpamVerdictService requires recaptcha' do + before do + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) + end + end + + context 'when allow_possible_spam feature flag is false' do + before do + stub_application_setting(recaptcha_enabled: false) + end + + it_behaves_like 'does not allow creation' + end + + context 'when allow_possible_spam feature flag is true' do + it_behaves_like 'solve reCAPTCHA' + end + end + + context 'when SpamVerdictService disallows' do before do - WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "true", status: 200) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(DISALLOW) + end end context 'when allow_possible_spam feature flag is false' do - it_behaves_like 'solve recaptcha' + before do + stub_application_setting(recaptcha_enabled: false) + end + + it_behaves_like 'does not allow creation' end context 'when allow_possible_spam feature flag is true' do - it_behaves_like 'solve recaptcha' + it_behaves_like 'does not allow creation' end end - context 'when not identified as spam' do + context 'when SpamVerdictService allows' do before do - WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "false", status: 200) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(ALLOW) + end end it 'creates a snippet' do @@ -85,15 +125,5 @@ end describe 'User creates snippet', :js do let_it_be(:user) { create(:user) } - context 'when using Monaco' do - it_behaves_like "snippet editor" do - let(:flag) { true } - end - end - - context 'when using ACE' do - it_behaves_like "snippet editor" do - let(:flag) { false } - end - end + it_behaves_like "snippet editor" end diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index 5d3a84dd7bc..62054c1f491 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -6,7 +6,6 @@ shared_examples_for 'snippet editor' do before do stub_feature_flags(snippets_vue: false) stub_feature_flags(snippets_edit_vue: false) - stub_feature_flags(monaco_snippets: flag) sign_in(user) visit new_snippet_path end @@ -23,7 +22,7 @@ shared_examples_for 'snippet editor' do fill_in 'personal_snippet_description', with: 'My Snippet **Description**' page.within('.file-editor') do - el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false) + el = find('.inputarea') el.send_keys 'Hello World!' end end @@ -80,7 +79,7 @@ shared_examples_for 'snippet editor' do end context 'when the git operation fails' do - let(:error) { 'This is a git error' } + let(:error) { 'Error creating the snippet' } before do allow_next_instance_of(Snippets::CreateService) do |instance| @@ -136,7 +135,7 @@ shared_examples_for 'snippet editor' do fill_in 'personal_snippet_title', with: 'My Snippet Title' page.within('.file-editor') do find(:xpath, "//input[@id='personal_snippet_file_name']").set 'snippet+file+name' - el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false) + el = find('.inputarea') el.send_keys 'Hello World!' end @@ -154,15 +153,5 @@ describe 'User creates snippet', :js do let_it_be(:user) { create(:user) } - context 'when using Monaco' do - it_behaves_like "snippet editor" do - let(:flag) { true } - end - end - - context 'when using ACE' do - it_behaves_like "snippet editor" do - let(:flag) { false } - end - end + it_behaves_like "snippet editor" end diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb index b4f8fbfa47e..40b0113cf39 100644 --- a/spec/features/snippets/user_edits_snippet_spec.rb +++ b/spec/features/snippets/user_edits_snippet_spec.rb @@ -10,12 +10,9 @@ describe 'User edits snippet', :js do let_it_be(:user) { create(:user) } let_it_be(:snippet, reload: true) { create(:personal_snippet, :repository, :public, file_name: file_name, content: content, author: user) } - let(:version_snippet_enabled) { true } - before do stub_feature_flags(snippets_vue: false) stub_feature_flags(snippets_edit_vue: false) - stub_feature_flags(version_snippets: version_snippet_enabled) sign_in(user) @@ -33,18 +30,6 @@ describe 'User edits snippet', :js do end end - context 'when feature flag :version_snippets is disabled' do - let(:version_snippet_enabled) { false } - - it 'displays the snippet file_name and content' do - aggregate_failures do - expect(page.find_field('personal_snippet_file_name').value).to eq file_name - expect(page.find('.file-content')).to have_content(content) - expect(page.find('.snippet-file-content', visible: false).value).to eq content - end - end - end - it 'updates the snippet' do fill_in 'personal_snippet_title', with: 'New Snippet Title' @@ -88,16 +73,17 @@ describe 'User edits snippet', :js do context 'when the git operation fails' do before do allow_next_instance_of(Snippets::UpdateService) do |instance| - allow(instance).to receive(:create_commit).and_raise(StandardError) + allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message') end fill_in 'personal_snippet_title', with: 'New Snippet Title' + fill_in 'personal_snippet_file_name', with: 'new_file_name' click_button('Save changes') end it 'renders edit page and displays the error' do - expect(page.find('.flash-container span').text).to eq('Error updating the snippet') + expect(page.find('.flash-container span').text).to eq('Error updating the snippet - Error Message') expect(page).to have_content('Edit Snippet') end end diff --git a/spec/features/static_site_editor_spec.rb b/spec/features/static_site_editor_spec.rb index c457002f888..de000ee2b9f 100644 --- a/spec/features/static_site_editor_spec.rb +++ b/spec/features/static_site_editor_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe 'Static Site Editor' do - let(:user) { create(:user) } - let(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :public, :repository) } before do project.add_maintainer(user) diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index daa987ea389..0ef86dde030 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -470,8 +470,8 @@ end describe 'With experimental flow' do before do - stub_experiment(signup_flow: true, paid_signup_flow: false) - stub_experiment_for_user(signup_flow: true, paid_signup_flow: false) + stub_experiment(signup_flow: true) + stub_experiment_for_user(signup_flow: true) end it_behaves_like 'Signup' -- cgit v1.2.3