summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/admin/admin_appearance_spec.rb18
-rw-r--r--spec/features/admin/admin_browses_logs_spec.rb20
-rw-r--r--spec/features/admin/admin_hooks_spec.rb18
-rw-r--r--spec/features/admin/admin_mode/login_spec.rb77
-rw-r--r--spec/features/admin/admin_settings_spec.rb40
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb4
-rw-r--r--spec/features/boards/boards_spec.rb54
-rw-r--r--spec/features/boards/focus_mode_spec.rb17
-rw-r--r--spec/features/boards/sidebar_spec.rb2
-rw-r--r--spec/features/commits/user_view_commits_spec.rb22
-rw-r--r--spec/features/dashboard/help_spec.rb21
-rw-r--r--spec/features/dashboard/issues_spec.rb2
-rw-r--r--spec/features/dashboard/snippets_spec.rb43
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb42
-rw-r--r--spec/features/error_tracking/user_filters_errors_by_status_spec.rb2
-rw-r--r--spec/features/error_tracking/user_sees_error_index_spec.rb2
-rw-r--r--spec/features/explore/groups_spec.rb2
-rw-r--r--spec/features/global_search_spec.rb2
-rw-r--r--spec/features/groups/import_export/export_file_spec.rb59
-rw-r--r--spec/features/groups/issues_spec.rb23
-rw-r--r--spec/features/groups/members/leave_group_spec.rb2
-rw-r--r--spec/features/groups/members/manage_groups_spec.rb85
-rw-r--r--spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb68
-rw-r--r--spec/features/groups/navbar_spec.rb52
-rw-r--r--spec/features/groups_spec.rb36
-rw-r--r--spec/features/help_pages_spec.rb32
-rw-r--r--spec/features/issues/bulk_assignment_labels_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb47
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb18
-rw-r--r--spec/features/issues/spam_issues_spec.rb121
-rw-r--r--spec/features/issues/update_issues_spec.rb2
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb12
-rw-r--r--spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb32
-rw-r--r--spec/features/markdown/copy_as_gfm_spec.rb6
-rw-r--r--spec/features/markdown/metrics_spec.rb2
-rw-r--r--spec/features/merge_request/maintainer_edits_fork_spec.rb2
-rw-r--r--spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb4
-rw-r--r--spec/features/merge_request/user_posts_notes_spec.rb5
-rw-r--r--spec/features/merge_request/user_resolves_conflicts_spec.rb4
-rw-r--r--spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb54
-rw-r--r--spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb1
-rw-r--r--spec/features/merge_requests/user_mass_updates_spec.rb2
-rw-r--r--spec/features/milestones/user_creates_milestone_spec.rb6
-rw-r--r--spec/features/milestones/user_views_milestone_spec.rb6
-rw-r--r--spec/features/profiles/emails_spec.rb11
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb4
-rw-r--r--spec/features/projects/activity/user_sees_design_comment_spec.rb51
-rw-r--r--spec/features/projects/branches/user_creates_branch_spec.rb10
-rw-r--r--spec/features/projects/commit/comments/user_edits_comments_spec.rb6
-rw-r--r--spec/features/projects/environments_pod_logs_spec.rb2
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb39
-rw-r--r--spec/features/projects/graph_spec.rb2
-rw-r--r--spec/features/projects/import_export/export_file_spec.rb4
-rw-r--r--spec/features/projects/issues/design_management/user_paginates_designs_spec.rb40
-rw-r--r--spec/features/projects/issues/design_management/user_permissions_upload_spec.rb24
-rw-r--r--spec/features/projects/issues/design_management/user_uploads_designs_spec.rb63
-rw-r--r--spec/features/projects/issues/design_management/user_views_design_images_spec.rb41
-rw-r--r--spec/features/projects/issues/design_management/user_views_design_spec.rb29
-rw-r--r--spec/features/projects/issues/design_management/user_views_designs_spec.rb47
-rw-r--r--spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb55
-rw-r--r--spec/features/projects/members/list_spec.rb19
-rw-r--r--spec/features/projects/navbar_spec.rb21
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb72
-rw-r--r--spec/features/projects/serverless/functions_spec.rb2
-rw-r--r--spec/features/projects/services/disable_triggers_spec.rb10
-rw-r--r--spec/features/projects/services/prometheus_external_alerts_spec.rb20
-rw-r--r--spec/features/projects/services/user_activates_issue_tracker_spec.rb59
-rw-r--r--spec/features/projects/services/user_activates_jira_spec.rb42
-rw-r--r--spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb204
-rw-r--r--spec/features/projects/services/user_activates_slack_slash_command_spec.rb9
-rw-r--r--spec/features/projects/services/user_activates_youtrack_spec.rb91
-rw-r--r--spec/features/projects/settings/access_tokens_spec.rb93
-rw-r--r--spec/features/projects/settings/operations_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/project_settings_spec.rb30
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb16
-rw-r--r--spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb10
-rw-r--r--spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb2
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb17
-rw-r--r--spec/features/projects/snippets/user_updates_snippet_spec.rb20
-rw-r--r--spec/features/projects/user_sees_user_popover_spec.rb18
-rw-r--r--spec/features/projects/wiki/markdown_preview_spec.rb2
-rw-r--r--spec/features/projects/wiki/shortcuts_spec.rb2
-rw-r--r--spec/features/projects/wiki/user_creates_wiki_page_spec.rb35
-rw-r--r--spec/features/projects/wiki/user_git_access_wiki_page_spec.rb2
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb4
-rw-r--r--spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb2
-rw-r--r--spec/features/projects/wiki/user_views_wiki_page_spec.rb2
-rw-r--r--spec/features/projects/wiki/user_views_wiki_pages_spec.rb6
-rw-r--r--spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb4
-rw-r--r--spec/features/search/user_searches_for_wiki_pages_spec.rb2
-rw-r--r--spec/features/security/project/internal_access_spec.rb6
-rw-r--r--spec/features/security/project/private_access_spec.rb2
-rw-r--r--spec/features/security/project/public_access_spec.rb10
-rw-r--r--spec/features/snippets/search_snippets_spec.rb2
-rw-r--r--spec/features/snippets/spam_snippets_spec.rb76
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb19
-rw-r--r--spec/features/snippets/user_edits_snippet_spec.rb20
-rw-r--r--spec/features/static_site_editor_spec.rb4
-rw-r--r--spec/features/users/signup_spec.rb4
102 files changed, 1709 insertions, 757 deletions
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
@@ -173,6 +173,12 @@ describe 'Copy as GFM', :js do
)
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)',
project_media_uri(@project, '/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 <strong>#{ERB::Util.html_escape(branch_name)}</strong>")
- 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("<script>alert('FAIL')</script>")
+ 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'