summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-18 09:45:46 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-18 09:45:46 +0000
commita7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch)
tree7452bd5c3545c2fa67a28aa013835fb4fa071baf /spec/features
parentee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff)
downloadgitlab-ce-a7b3560714b4d9cc4ab32dffcd1f74a284b93580.tar.gz
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/admin/admin_groups_spec.rb17
-rw-r--r--spec/features/admin/admin_mode/logout_spec.rb2
-rw-r--r--spec/features/admin/admin_runners_spec.rb52
-rw-r--r--spec/features/admin/admin_sees_background_migrations_spec.rb6
-rw-r--r--spec/features/admin/admin_settings_spec.rb56
-rw-r--r--spec/features/admin/integrations/instance_integrations_spec.rb15
-rw-r--r--spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb15
-rw-r--r--spec/features/admin/users/users_spec.rb17
-rw-r--r--spec/features/boards/board_filters_spec.rb13
-rw-r--r--spec/features/boards/boards_spec.rb6
-rw-r--r--spec/features/boards/new_issue_spec.rb19
-rw-r--r--spec/features/breadcrumbs_schema_markup_spec.rb6
-rw-r--r--spec/features/clusters/create_agent_spec.rb1
-rw-r--r--spec/features/contextual_sidebar_spec.rb2
-rw-r--r--spec/features/cycle_analytics_spec.rb4
-rw-r--r--spec/features/dashboard/groups_list_spec.rb65
-rw-r--r--spec/features/dashboard/issuables_counter_spec.rb15
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb4
-rw-r--r--spec/features/dashboard/snippets_spec.rb6
-rw-r--r--spec/features/error_tracking/user_filters_errors_by_status_spec.rb2
-rw-r--r--spec/features/error_tracking/user_searches_sentry_errors_spec.rb2
-rw-r--r--spec/features/error_tracking/user_sees_error_details_spec.rb2
-rw-r--r--spec/features/error_tracking/user_sees_error_index_spec.rb4
-rw-r--r--spec/features/file_uploads/attachment_spec.rb2
-rw-r--r--spec/features/file_uploads/git_lfs_spec.rb2
-rw-r--r--spec/features/file_uploads/maven_package_spec.rb2
-rw-r--r--spec/features/file_uploads/nuget_package_spec.rb2
-rw-r--r--spec/features/file_uploads/rubygem_package_spec.rb2
-rw-r--r--spec/features/gitlab_experiments_spec.rb4
-rw-r--r--spec/features/groups/group_settings_spec.rb45
-rw-r--r--spec/features/groups/integrations/group_integrations_spec.rb15
-rw-r--r--spec/features/groups/members/leave_group_spec.rb2
-rw-r--r--spec/features/groups/members/manage_groups_spec.rb20
-rw-r--r--spec/features/groups_spec.rb6
-rw-r--r--spec/features/ide/user_commits_changes_spec.rb2
-rw-r--r--spec/features/ide/user_opens_merge_request_spec.rb2
-rw-r--r--spec/features/issuables/markdown_references/internal_references_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/dropdown_base_spec.rb17
-rw-r--r--spec/features/issues/filtered_search/recent_searches_spec.rb2
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb778
-rw-r--r--spec/features/issues/keyboard_shortcut_spec.rb4
-rw-r--r--spec/features/issues/todo_spec.rb8
-rw-r--r--spec/features/issues/user_comments_on_issue_spec.rb1
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb25
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb2
-rw-r--r--spec/features/issues/user_interacts_with_awards_spec.rb3
-rw-r--r--spec/features/issues/user_sorts_issues_spec.rb83
-rw-r--r--spec/features/jira_connect/branches_spec.rb4
-rw-r--r--spec/features/markdown/copy_as_gfm_spec.rb2
-rw-r--r--spec/features/merge_request/batch_comments_spec.rb18
-rw-r--r--spec/features/merge_request/user_awards_emoji_spec.rb1
-rw-r--r--spec/features/merge_request/user_comments_on_diff_spec.rb52
-rw-r--r--spec/features/merge_request/user_creates_image_diff_notes_spec.rb4
-rw-r--r--spec/features/merge_request/user_edits_assignees_sidebar_spec.rb2
-rw-r--r--spec/features/merge_request/user_expands_diff_spec.rb4
-rw-r--r--spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb45
-rw-r--r--spec/features/merge_request/user_merges_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb4
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb60
-rw-r--r--spec/features/merge_request/user_posts_notes_spec.rb12
-rw-r--r--spec/features/merge_request/user_rebases_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_resolves_wip_mr_spec.rb4
-rw-r--r--spec/features/merge_request/user_reviews_image_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb11
-rw-r--r--spec/features/merge_request/user_sees_deleted_target_branch_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_deployment_widget_spec.rb6
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb25
-rw-r--r--spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb22
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb26
-rw-r--r--spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb4
-rw-r--r--spec/features/merge_request/user_sees_pipelines_spec.rb7
-rw-r--r--spec/features/merge_request/user_sees_versions_spec.rb10
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb12
-rw-r--r--spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb2
-rw-r--r--spec/features/merge_request/user_views_open_merge_request_spec.rb26
-rw-r--r--spec/features/merge_requests/user_mass_updates_spec.rb14
-rw-r--r--spec/features/monitor_sidebar_link_spec.rb5
-rw-r--r--spec/features/participants_autocomplete_spec.rb23
-rw-r--r--spec/features/profiles/keys_spec.rb7
-rw-r--r--spec/features/profiles/password_spec.rb2
-rw-r--r--spec/features/projects/active_tabs_spec.rb2
-rw-r--r--spec/features/projects/activity/rss_spec.rb4
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb1583
-rw-r--r--spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb2
-rw-r--r--spec/features/projects/branches/user_views_branches_spec.rb2
-rw-r--r--spec/features/projects/ci/editor_spec.rb61
-rw-r--r--spec/features/projects/cluster_agents_spec.rb7
-rw-r--r--spec/features/projects/clusters_spec.rb3
-rw-r--r--spec/features/projects/environments/environment_spec.rb23
-rw-r--r--spec/features/projects/environments_pod_logs_spec.rb2
-rw-r--r--spec/features/projects/files/dockerfile_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/edit_file_soft_wrap_spec.rb2
-rw-r--r--spec/features/projects/files/editing_a_file_spec.rb2
-rw-r--r--spec/features/projects/files/files_sort_submodules_with_folders_spec.rb2
-rw-r--r--spec/features/projects/files/find_file_keyboard_spec.rb2
-rw-r--r--spec/features/projects/files/gitignore_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/project_owner_creates_license_file_spec.rb2
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb2
-rw-r--r--spec/features/projects/files/template_type_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/undo_template_spec.rb2
-rw-r--r--spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb2
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb29
-rw-r--r--spec/features/projects/files/user_browses_lfs_files_spec.rb2
-rw-r--r--spec/features/projects/files/user_searches_for_files_spec.rb2
-rw-r--r--spec/features/projects/gfm_autocomplete_load_spec.rb2
-rw-r--r--spec/features/projects/import_export/import_file_spec.rb2
-rw-r--r--spec/features/projects/integrations/disable_triggers_spec.rb (renamed from spec/features/projects/services/disable_triggers_spec.rb)12
-rw-r--r--spec/features/projects/integrations/project_integrations_spec.rb15
-rw-r--r--spec/features/projects/integrations/prometheus_external_alerts_spec.rb (renamed from spec/features/projects/services/prometheus_external_alerts_spec.rb)2
-rw-r--r--spec/features/projects/integrations/user_activates_asana_spec.rb4
-rw-r--r--spec/features/projects/integrations/user_activates_assembla_spec.rb4
-rw-r--r--spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb4
-rw-r--r--spec/features/projects/integrations/user_activates_emails_on_push_spec.rb (renamed from spec/features/projects/services/user_activates_emails_on_push_spec.rb)4
-rw-r--r--spec/features/projects/integrations/user_activates_flowdock_spec.rb4
-rw-r--r--spec/features/projects/integrations/user_activates_irker_spec.rb (renamed from spec/features/projects/services/user_activates_irker_spec.rb)4
-rw-r--r--spec/features/projects/integrations/user_activates_issue_tracker_spec.rb (renamed from spec/features/projects/services/user_activates_issue_tracker_spec.rb)12
-rw-r--r--spec/features/projects/integrations/user_activates_jetbrains_teamcity_ci_spec.rb (renamed from spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb)4
-rw-r--r--spec/features/projects/integrations/user_activates_jira_spec.rb14
-rw-r--r--spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb (renamed from spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb)14
-rw-r--r--spec/features/projects/integrations/user_activates_packagist_spec.rb (renamed from spec/features/projects/services/user_activates_packagist_spec.rb)4
-rw-r--r--spec/features/projects/integrations/user_activates_pivotaltracker_spec.rb4
-rw-r--r--spec/features/projects/integrations/user_activates_prometheus_spec.rb (renamed from spec/features/projects/services/user_activates_prometheus_spec.rb)4
-rw-r--r--spec/features/projects/integrations/user_activates_pushover_spec.rb (renamed from spec/features/projects/services/user_activates_pushover_spec.rb)4
-rw-r--r--spec/features/projects/integrations/user_activates_slack_notifications_spec.rb (renamed from spec/features/projects/services/user_activates_slack_notifications_spec.rb)8
-rw-r--r--spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb (renamed from spec/features/projects/services/user_activates_slack_slash_command_spec.rb)2
-rw-r--r--spec/features/projects/integrations/user_uses_inherited_settings_spec.rb2
-rw-r--r--spec/features/projects/integrations/user_views_services_spec.rb (renamed from spec/features/projects/services/user_views_services_spec.rb)6
-rw-r--r--spec/features/projects/issues/design_management/user_uploads_designs_spec.rb2
-rw-r--r--spec/features/projects/jobs_spec.rb2
-rw-r--r--spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb2
-rw-r--r--spec/features/projects/members/invite_group_spec.rb126
-rw-r--r--spec/features/projects/members/member_leaves_project_spec.rb13
-rw-r--r--spec/features/projects/members/owner_cannot_leave_project_spec.rb2
-rw-r--r--spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb2
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb2
-rw-r--r--spec/features/projects/navbar_spec.rb2
-rw-r--r--spec/features/projects/network_graph_spec.rb2
-rw-r--r--spec/features/projects/new_project_spec.rb91
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb120
-rw-r--r--spec/features/projects/settings/monitor_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/packages_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/project_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb2
-rw-r--r--spec/features/projects/show/redirects_spec.rb2
-rw-r--r--spec/features/projects/show/user_manages_notifications_spec.rb2
-rw-r--r--spec/features/projects/show/user_sees_deletion_failure_message_spec.rb2
-rw-r--r--spec/features/projects/show/user_sees_git_instructions_spec.rb4
-rw-r--r--spec/features/projects/tree/tree_show_spec.rb8
-rw-r--r--spec/features/projects/user_changes_project_visibility_spec.rb10
-rw-r--r--spec/features/projects/user_uses_shortcuts_spec.rb2
-rw-r--r--spec/features/projects/view_on_env_spec.rb1
-rw-r--r--spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb2
-rw-r--r--spec/features/projects_spec.rb12
-rw-r--r--spec/features/protected_tags_spec.rb2
-rw-r--r--spec/features/security/project/snippet/internal_access_spec.rb4
-rw-r--r--spec/features/security/project/snippet/private_access_spec.rb2
-rw-r--r--spec/features/security/project/snippet/public_access_spec.rb6
-rw-r--r--spec/features/snippets_spec.rb2
-rw-r--r--spec/features/triggers_spec.rb6
-rw-r--r--spec/features/user_sorts_things_spec.rb12
-rw-r--r--spec/features/users/bizible_csp_spec.rb15
-rw-r--r--spec/features/users/logout_spec.rb2
164 files changed, 2239 insertions, 1900 deletions
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index 8d4e7a7442c..a0a41061d64 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Admin Groups' do
include Select2Helper
include Spec::Support::Helpers::Features::MembersHelpers
include Spec::Support::Helpers::Features::InviteMembersModalHelper
+ include Spec::Support::Helpers::ModalHelpers
let(:internal) { Gitlab::VisibilityLevel::INTERNAL }
@@ -250,26 +251,26 @@ RSpec.describe 'Admin Groups' do
end
end
- describe 'admin remove themself from a group', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/222342' do
+ describe 'admin removes themself from a group', :js do
it 'removes admin from the group' do
- stub_feature_flags(bootstrap_confirmation_modals: false)
group.add_user(current_user, Gitlab::Access::DEVELOPER)
visit group_group_members_path(group)
- page.within '[data-qa-selector="members_list"]' do # rubocop:disable QA/SelectorUsage
+ page.within members_table do
expect(page).to have_content(current_user.name)
expect(page).to have_content('Developer')
end
- accept_confirm { find(:css, 'li', text: current_user.name).find(:css, 'a.btn-danger').click }
+ find_member_row(current_user).click_button(title: 'Leave')
+
+ accept_gl_confirm(button_text: 'Leave')
+
+ wait_for_all_requests
visit group_group_members_path(group)
- page.within '[data-qa-selector="members_list"]' do # rubocop:disable QA/SelectorUsage
- expect(page).not_to have_content(current_user.name)
- expect(page).not_to have_content('Developer')
- end
+ expect(members_table).not_to have_content(current_user.name)
end
end
diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb
index 58bea5c4b5f..f2f6e26fbee 100644
--- a/spec/features/admin/admin_mode/logout_spec.rb
+++ b/spec/features/admin/admin_mode/logout_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe 'Admin Mode Logout', :js do
it 'disable shows flash notice' do
gitlab_disable_admin_mode
- expect(page).to have_selector('.flash-notice')
+ expect(page).to have_selector('[data-testid="alert-info"]')
end
context 'on a read-only instance' do
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index ceb91b86876..25ff4022454 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -254,6 +254,18 @@ RSpec.describe "Admin Runners" do
expect(page).not_to have_content 'runner-group'
end
+ it 'show the same counts after selecting another tab' do
+ visit admin_runners_path
+
+ page.within('[data-testid="runner-type-tabs"]') do
+ click_on('Project')
+
+ expect(page).to have_link('All 2')
+ expect(page).to have_link('Group 1')
+ expect(page).to have_link('Project 1')
+ end
+ end
+
it 'shows no runner when type does not match' do
visit admin_runners_path
@@ -460,7 +472,7 @@ RSpec.describe "Admin Runners" do
click_on 'Reset registration token'
within_modal do
- click_button('OK', match: :first)
+ click_button('Reset token', match: :first)
end
wait_for_requests
@@ -476,6 +488,42 @@ RSpec.describe "Admin Runners" do
end
end
+ describe "Runner show page", :js do
+ let(:runner) do
+ create(
+ :ci_runner,
+ description: 'runner-foo',
+ version: '14.0',
+ ip_address: '127.0.0.1',
+ tag_list: ['tag1']
+ )
+ end
+
+ before do
+ visit admin_runner_path(runner)
+ end
+
+ describe 'runner show page breadcrumbs' do
+ it 'contains the current runner id and token' do
+ page.within '[data-testid="breadcrumb-links"]' do
+ expect(page.find('h2')).to have_link("##{runner.id} (#{runner.short_sha})")
+ end
+ end
+ end
+
+ it 'shows runner details' do
+ aggregate_failures do
+ expect(page).to have_content 'Description runner-foo'
+ expect(page).to have_content 'Last contact Never contacted'
+ expect(page).to have_content 'Version 14.0'
+ expect(page).to have_content 'IP Address 127.0.0.1'
+ expect(page).to have_content 'Configuration Runs untagged jobs'
+ expect(page).to have_content 'Maximum job timeout None'
+ expect(page).to have_content 'Tags tag1'
+ end
+ end
+ end
+
describe "Runner edit page" do
let(:runner) { create(:ci_runner) }
@@ -487,7 +535,7 @@ RSpec.describe "Admin Runners" do
wait_for_requests
end
- describe 'runner page breadcrumbs' do
+ describe 'runner edit page breadcrumbs' do
it 'contains the current runner id and token' do
page.within '[data-testid="breadcrumb-links"]' do
expect(page).to have_link("##{runner.id} (#{runner.short_sha})")
diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb
index 94fb3a0314f..a3d0c7bdd4d 100644
--- a/spec/features/admin/admin_sees_background_migrations_spec.rb
+++ b/spec/features/admin/admin_sees_background_migrations_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe "Admin > Admin sees background migrations" do
let_it_be(:finished_migration) { create(:batched_background_migration, table_name: 'finished', status: :finished) }
before_all do
- create(:batched_background_migration_job, batched_migration: failed_migration, batch_size: 10, min_value: 6, max_value: 15, status: :failed, attempts: 3)
+ create(:batched_background_migration_job, :failed, batched_migration: failed_migration, batch_size: 10, min_value: 6, max_value: 15, attempts: 3)
end
before do
@@ -68,7 +68,7 @@ RSpec.describe "Admin > Admin sees background migrations" do
tab.click
expect(page).to have_current_path(admin_background_migrations_path(tab: 'failed'))
- expect(tab[:class]).to include('gl-tab-nav-item-active', 'gl-tab-nav-item-active-indigo')
+ expect(tab[:class]).to include('gl-tab-nav-item-active')
expect(page).to have_selector('tbody tr', count: 1)
@@ -93,7 +93,7 @@ RSpec.describe "Admin > Admin sees background migrations" do
tab.click
expect(page).to have_current_path(admin_background_migrations_path(tab: 'finished'))
- expect(tab[:class]).to include('gl-tab-nav-item-active', 'gl-tab-nav-item-active-indigo')
+ expect(tab[:class]).to include('gl-tab-nav-item-active')
expect(page).to have_selector('tbody tr', count: 1)
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index e136ab41966..ca452264c02 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -85,6 +85,8 @@ RSpec.describe 'Admin updates settings' do
select 'Are allowed', from: 'DSA SSH keys'
select 'Must be at least 384 bits', from: 'ECDSA SSH keys'
select 'Are forbidden', from: 'ED25519 SSH keys'
+ select 'Are forbidden', from: 'ECDSA_SK SSH keys'
+ select 'Are forbidden', from: 'ED25519_SK SSH keys'
click_on 'Save changes'
end
@@ -95,6 +97,8 @@ RSpec.describe 'Admin updates settings' do
expect(find_field('DSA SSH keys').value).to eq('0')
expect(find_field('ECDSA SSH keys').value).to eq('384')
expect(find_field('ED25519 SSH keys').value).to eq(forbidden)
+ expect(find_field('ECDSA_SK SSH keys').value).to eq(forbidden)
+ expect(find_field('ED25519_SK SSH keys').value).to eq(forbidden)
end
it 'change Account and Limit Settings' do
@@ -528,7 +532,7 @@ RSpec.describe 'Admin updates settings' do
expect(find_field('Allow access to members of the following group').value).to be_nil
end
- it 'loads usage ping payload on click', :js do
+ it 'loads togglable usage ping payload on click', :js do
stub_usage_data_connections
stub_database_flavor_check
@@ -544,6 +548,10 @@ RSpec.describe 'Admin updates settings' do
expect(page).to have_selector '.js-service-ping-payload'
expect(page).to have_button 'Hide payload'
expect(page).to have_content expected_payload_content
+
+ click_button('Hide payload')
+
+ expect(page).not_to have_content expected_payload_content
end
end
end
@@ -623,6 +631,20 @@ RSpec.describe 'Admin updates settings' do
expect(current_settings.issues_create_limit).to eq(0)
end
+ it 'changes Users API rate limits settings' do
+ visit network_admin_application_settings_path
+
+ page.within('.as-users-api-limits') do
+ fill_in 'Maximum requests per 10 minutes per user', with: 0
+ fill_in 'Users to exclude from the rate limit', with: 'someone, someone_else'
+ click_button 'Save changes'
+ end
+
+ expect(page).to have_content "Application settings saved successfully"
+ expect(current_settings.users_get_by_id_limit).to eq(0)
+ expect(current_settings.users_get_by_id_limit_allowlist).to eq(%w[someone someone_else])
+ end
+
shared_examples 'regular throttle rate limit settings' do
it 'changes rate limit settings' do
visit network_admin_application_settings_path
@@ -771,6 +793,38 @@ RSpec.describe 'Admin updates settings' do
end
end
end
+
+ context 'Service usage data page' do
+ before do
+ stub_usage_data_connections
+ stub_database_flavor_check
+
+ visit service_usage_data_admin_application_settings_path
+ end
+
+ it 'loads usage ping payload on click', :js do
+ expected_payload_content = /(?=.*"uuid")(?=.*"hostname")/m
+
+ expect(page).not_to have_content expected_payload_content
+
+ click_button('Preview payload')
+
+ wait_for_requests
+
+ expect(page).to have_button 'Hide payload'
+ expect(page).to have_content expected_payload_content
+ end
+
+ it 'generates usage ping payload on button click', :js do
+ expect_next_instance_of(Admin::ApplicationSettingsController) do |instance|
+ expect(instance).to receive(:usage_data).and_call_original
+ end
+
+ click_button('Download payload')
+
+ wait_for_requests
+ end
+ end
end
context 'application setting :admin_mode is disabled' do
diff --git a/spec/features/admin/integrations/instance_integrations_spec.rb b/spec/features/admin/integrations/instance_integrations_spec.rb
new file mode 100644
index 00000000000..7b326ec161c
--- /dev/null
+++ b/spec/features/admin/integrations/instance_integrations_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Instance integrations', :js do
+ include_context 'instance integration activation'
+
+ it_behaves_like 'integration settings form' do
+ let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_instance) }
+
+ def navigate_to_integration(integration)
+ visit_instance_integration(integration.title)
+ end
+ end
+end
diff --git a/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb b/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb
index 793a5bced00..22a27b33671 100644
--- a/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb
+++ b/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb
@@ -19,19 +19,4 @@ RSpec.describe 'User activates the instance-level Mattermost Slash Command integ
expect(page).to have_link('Settings', href: edit_path)
expect(page).to have_link('Projects using custom settings', href: overrides_path)
end
-
- it 'does not render integration form element' do
- expect(page).not_to have_selector('[data-testid="integration-form"]')
- end
-
- context 'when `vue_integration_form` feature flag is disabled' do
- before do
- stub_feature_flags(vue_integration_form: false)
- visit_instance_integration('Mattermost slash commands')
- end
-
- it 'renders integration form element' do
- expect(page).to have_selector('[data-testid="integration-form"]')
- end
- end
end
diff --git a/spec/features/admin/users/users_spec.rb b/spec/features/admin/users/users_spec.rb
index 473f51370b3..5b0b6e085c9 100644
--- a/spec/features/admin/users/users_spec.rb
+++ b/spec/features/admin/users/users_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Admin::Users' do
include Spec::Support::Helpers::Features::AdminUsersHelpers
+ include Spec::Support::Helpers::ModalHelpers
let_it_be(:user, reload: true) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
let_it_be(:current_user) { create(:admin) }
@@ -294,6 +295,22 @@ RSpec.describe 'Admin::Users' do
end
end
+ context 'when a user is locked', time_travel_to: '2020-02-25 10:30:45 -0700' do
+ let_it_be(:locked_user) { create(:user, locked_at: DateTime.parse('2020-02-25 10:30:00 -0700')) }
+
+ it "displays `Locked` badge next to user" do
+ expect(page).to have_content("#{locked_user.name} Locked")
+ end
+
+ it 'allows a user to be unlocked from the `User administration dropdown', :js do
+ accept_gl_confirm("Unlock user #{locked_user.name}?", button_text: 'Unlock') do
+ click_action_in_user_dropdown(locked_user.id, 'Unlock')
+ end
+
+ expect(page).not_to have_content("#{locked_user.name} (Locked)")
+ end
+ end
+
describe 'internal users' do
context 'when showing a `Ghost User`' do
let_it_be(:ghost_user) { create(:user, :ghost) }
diff --git a/spec/features/boards/board_filters_spec.rb b/spec/features/boards/board_filters_spec.rb
index 49375e4b37b..e37bf515088 100644
--- a/spec/features/boards/board_filters_spec.rb
+++ b/spec/features/boards/board_filters_spec.rb
@@ -7,15 +7,15 @@ RSpec.describe 'Issue board filters', :js do
let_it_be(:user) { create(:user) }
let_it_be(:board) { create(:board, project: project) }
let_it_be(:project_label) { create(:label, project: project, title: 'Label') }
- let_it_be(:milestone_1) { create(:milestone, project: project) }
- let_it_be(:milestone_2) { create(:milestone, project: project) }
+ let_it_be(:milestone_1) { create(:milestone, project: project, due_date: 3.days.from_now ) }
+ let_it_be(:milestone_2) { create(:milestone, project: project, due_date: Date.tomorrow ) }
let_it_be(:release) { create(:release, tag: 'v1.0', project: project, milestones: [milestone_1]) }
let_it_be(:release_2) { create(:release, tag: 'v2.0', project: project, milestones: [milestone_2]) }
let_it_be(:issue_1) { create(:issue, project: project, milestone: milestone_1, author: user) }
let_it_be(:issue_2) { create(:labeled_issue, project: project, milestone: milestone_2, assignees: [user], labels: [project_label], confidential: true) }
let_it_be(:award_emoji1) { create(:award_emoji, name: 'thumbsup', user: user, awardable: issue_1) }
- let(:filtered_search) { find('[data-testid="issue_1-board-filtered-search"]') }
+ let(:filtered_search) { find('[data-testid="issue-board-filtered-search"]') }
let(:filter_input) { find('.gl-filtered-search-term-input')}
let(:filter_dropdown) { find('.gl-filtered-search-suggestion-list') }
let(:filter_first_suggestion) { find('.gl-filtered-search-suggestion-list').first('.gl-filtered-search-suggestion') }
@@ -134,8 +134,11 @@ RSpec.describe 'Issue board filters', :js do
expect(filter_dropdown).to have_content('Any')
expect(filter_dropdown).to have_content('Started')
expect(filter_dropdown).to have_content('Upcoming')
- expect(filter_dropdown).to have_content(milestone_1.title)
- expect(filter_dropdown).to have_content(milestone_2.title)
+
+ dropdown_nodes = page.find_all('.gl-filtered-search-suggestion-list > .gl-filtered-search-suggestion')
+
+ expect(dropdown_nodes[4]).to have_content(milestone_2.title)
+ expect(dropdown_nodes.last).to have_content(milestone_1.title)
click_on milestone_1.title
filter_submit.click
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index d25cddea902..2ca4ff94911 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -583,7 +583,11 @@ RSpec.describe 'Project issue boards', :js do
end
page.within(find('.js-board-settings-sidebar')) do
- accept_confirm { find('[data-testid="remove-list"]').click }
+ click_button 'Remove list'
+ end
+
+ page.within('.modal') do
+ click_button 'Remove list'
end
end
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index f88d31bda88..5f4517d47ee 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -3,12 +3,13 @@
require 'spec_helper'
RSpec.describe 'Issue Boards new issue', :js do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:board) { create(:board, project: project) }
- let_it_be(:backlog_list) { create(:backlog_list, board: board) }
- let_it_be(:label) { create(:label, project: project, name: 'Label 1') }
- let_it_be(:list) { create(:list, board: board, label: label, position: 0) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:board) { create(:board, project: project) }
+ let_it_be(:backlog_list) { create(:backlog_list, board: board) }
+ let_it_be(:label) { create(:label, project: project, name: 'Label 1') }
+ let_it_be(:list) { create(:list, board: board, label: label, position: 0) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:existing_issue) { create(:issue, project: project, title: 'other issue', relative_position: 50) }
let(:board_list_header) { first('[data-testid="board-list-header"]') }
let(:project_select_dropdown) { find('[data-testid="project-select-dropdown"]') }
@@ -56,7 +57,7 @@ RSpec.describe 'Issue Boards new issue', :js do
end
end
- it 'creates new issue and opens sidebar' do
+ it 'creates new issue, places it on top of the list, and opens sidebar' do
page.within(first('.board')) do
click_button 'New issue'
end
@@ -69,12 +70,14 @@ RSpec.describe 'Issue Boards new issue', :js do
wait_for_requests
page.within(first('.board [data-testid="issue-count-badge"]')) do
- expect(page).to have_content('1')
+ expect(page).to have_content('2')
end
page.within(first('.board-card')) do
issue = project.issues.find_by_title('bug')
+ expect(issue.relative_position).to be < existing_issue.relative_position
+
expect(page).to have_content(issue.to_reference)
expect(page).to have_link(issue.title, href: /#{issue_path(issue)}/)
end
diff --git a/spec/features/breadcrumbs_schema_markup_spec.rb b/spec/features/breadcrumbs_schema_markup_spec.rb
index a87a3d284de..f86ad5cd2ae 100644
--- a/spec/features/breadcrumbs_schema_markup_spec.rb
+++ b/spec/features/breadcrumbs_schema_markup_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do
expect(item_list.size).to eq 2
expect(item_list[0]['name']).to eq project.namespace.name
- expect(item_list[0]['item']).to eq user_url(project.owner)
+ expect(item_list[0]['item']).to eq user_url(project.first_owner)
expect(item_list[1]['name']).to eq project.name
expect(item_list[1]['item']).to eq project_url(project)
@@ -59,7 +59,7 @@ RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do
expect(item_list.size).to eq 3
expect(item_list[0]['name']).to eq project.namespace.name
- expect(item_list[0]['item']).to eq user_url(project.owner)
+ expect(item_list[0]['item']).to eq user_url(project.first_owner)
expect(item_list[1]['name']).to eq project.name
expect(item_list[1]['item']).to eq project_url(project)
@@ -75,7 +75,7 @@ RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures do
expect(item_list.size).to eq 4
expect(item_list[0]['name']).to eq project.namespace.name
- expect(item_list[0]['item']).to eq user_url(project.owner)
+ expect(item_list[0]['item']).to eq user_url(project.first_owner)
expect(item_list[1]['name']).to eq project.name
expect(item_list[1]['item']).to eq project_url(project)
diff --git a/spec/features/clusters/create_agent_spec.rb b/spec/features/clusters/create_agent_spec.rb
index 7ed31a8c549..e03126d344e 100644
--- a/spec/features/clusters/create_agent_spec.rb
+++ b/spec/features/clusters/create_agent_spec.rb
@@ -15,6 +15,7 @@ RSpec.describe 'Cluster agent registration', :js do
double(agent_name: 'example-agent-1', path: '.gitlab/agents/example-agent-1/config.yaml'),
double(agent_name: 'example-agent-2', path: '.gitlab/agents/example-agent-2/config.yaml')
])
+ allow(client).to receive(:get_connected_agents).and_return([])
end
allow(Devise).to receive(:friendly_token).and_return('example-agent-token')
diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb
index 29c7e0ddd21..cc4a0471d4e 100644
--- a/spec/features/contextual_sidebar_spec.rb
+++ b/spec/features/contextual_sidebar_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Contextual sidebar', :js do
context 'when context is a project' do
let_it_be(:project) { create(:project) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 69361f66a71..03d61020ff0 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Value Stream Analytics', :js do
let_it_be(:stage_table_event_title_selector) { '[data-testid="vsa-stage-event-title"]' }
let_it_be(:stage_table_pagination_selector) { '[data-testid="vsa-stage-pagination"]' }
let_it_be(:stage_table_duration_column_header_selector) { '[data-testid="vsa-stage-header-duration"]' }
- let_it_be(:metrics_selector) { "[data-testid='vsa-time-metrics']" }
+ let_it_be(:metrics_selector) { "[data-testid='vsa-metrics']" }
let_it_be(:metric_value_selector) { "[data-testid='displayValue']" }
let(:stage_table) { find(stage_table_selector) }
@@ -134,7 +134,7 @@ RSpec.describe 'Value Stream Analytics', :js do
end
it 'can filter the metrics by date' do
- expect(metrics_values).to match_array(["21.0", "2.0", "1.0", "0.0"])
+ expect(metrics_values).to match_array(%w[21 2 1 0])
set_daterange(from, to)
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index 8c941b27cd2..3a4296836bd 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -15,6 +15,10 @@ RSpec.describe 'Dashboard Groups page', :js do
wait_for_requests
end
+ def click_options_menu(group)
+ page.find("[data-testid='group-#{group.id}-dropdown-button'").click
+ end
+
it 'shows groups user is member of' do
group.add_owner(user)
nested_group.add_owner(user)
@@ -112,6 +116,67 @@ RSpec.describe 'Dashboard Groups page', :js do
end
end
+ context 'group actions dropdown' do
+ let!(:subgroup) { create(:group, :public, parent: group) }
+
+ context 'user with subgroup ownership' do
+ before do
+ subgroup.add_owner(user)
+ sign_in(user)
+
+ visit dashboard_groups_path
+ end
+
+ it 'cannot remove parent group' do
+ expect(page).not_to have_selector("[data-testid='group-#{group.id}-dropdown-button'")
+ end
+ end
+
+ context 'user with parent group ownership' do
+ before do
+ group.add_owner(user)
+ sign_in(user)
+
+ visit dashboard_groups_path
+ end
+
+ it 'can remove parent group' do
+ click_options_menu(group)
+
+ expect(page).to have_selector("[data-testid='remove-group-#{group.id}-btn']")
+ end
+
+ it 'can remove subgroups' do
+ click_group_caret(group)
+ click_options_menu(subgroup)
+
+ expect(page).to have_selector("[data-testid='remove-group-#{subgroup.id}-btn']")
+ end
+ end
+
+ context 'user is a maintainer' do
+ before do
+ group.add_maintainer(user)
+ sign_in(user)
+
+ visit dashboard_groups_path
+ click_options_menu(group)
+ end
+
+ it 'cannot remove the group' do
+ expect(page).not_to have_selector("[data-testid='remove-group-#{group.id}-btn']")
+ end
+
+ it 'cannot edit the group' do
+ expect(page).not_to have_selector("[data-testid='edit-group-#{group.id}-btn']")
+ end
+
+ it 'can leave the group' do
+ expect(page).to have_selector("[data-testid='leave-group-#{group.id}-btn']")
+ end
+ end
+ end
+
context 'when using pagination' do
let(:group) { create(:group, created_at: 5.days.ago) }
let(:group2) { create(:group, created_at: 2.days.ago) }
diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb
index 8e938fef155..6700ec07765 100644
--- a/spec/features/dashboard/issuables_counter_spec.rb
+++ b/spec/features/dashboard/issuables_counter_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching d
it 'reflects dashboard issues count' do
visit issues_path
- expect_counters('issues', '1')
+ expect_counters('issues', '1', n_("%d assigned issue", "%d assigned issues", 1) % 1)
issue.assignees = []
@@ -26,14 +26,14 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching d
travel_to(3.minutes.from_now) do
visit issues_path
- expect_counters('issues', '0')
+ expect_counters('issues', '0', n_("%d assigned issue", "%d assigned issues", 0) % 0)
end
end
it 'reflects dashboard merge requests count' do
visit merge_requests_path
- expect_counters('merge_requests', '1')
+ expect_counters('merge_requests', '1', n_("%d merge request", "%d merge requests", 1) % 1)
merge_request.update!(assignees: [])
@@ -42,7 +42,7 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching d
travel_to(3.minutes.from_now) do
visit merge_requests_path
- expect_counters('merge_requests', '0')
+ expect_counters('merge_requests', '0', n_("%d merge request", "%d merge requests", 0) % 0)
end
end
@@ -54,13 +54,14 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching d
merge_requests_dashboard_path(assignee_username: user.username)
end
- def expect_counters(issuable_type, count)
+ def expect_counters(issuable_type, count, badge_label)
dashboard_count = find('.gl-tabs-nav li a.active')
nav_count = find(".dashboard-shortcuts-#{issuable_type}")
- header_count = find(".header-content .#{issuable_type.tr('_', '-')}-count")
expect(dashboard_count).to have_content(count)
expect(nav_count).to have_content(count)
- expect(header_count).to have_content(count)
+ within("span[aria-label='#{badge_label}']") do
+ expect(page).to have_content(count)
+ end
end
end
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 6239702edde..7507ef4e453 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -112,7 +112,9 @@ RSpec.describe 'Dashboard Merge Requests' do
end
it 'includes assigned and reviewers in badge' do
- expect(find('.merge-requests-count')).to have_content('3')
+ within("span[aria-label='#{n_("%d merge request", "%d merge requests", 3) % 3}']") do
+ expect(page).to have_content('3')
+ end
expect(find('.js-assigned-mr-count')).to have_content('2')
expect(find('.js-reviewer-mr-count')).to have_content('1')
end
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index 224f2111014..f891950eeb8 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -7,11 +7,11 @@ RSpec.describe 'Dashboard snippets' do
context 'when the project has snippets' do
let(:project) { create(:project, :public, creator: user) }
- let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) }
+ let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.first_owner, project: project) }
before do
allow(Snippet).to receive(:default_per_page).and_return(1)
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit dashboard_snippets_path
end
@@ -27,7 +27,7 @@ RSpec.describe 'Dashboard snippets' do
let(:project) { create(:project, :public, creator: user) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit dashboard_snippets_path
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 6846d8f6ade..d5dbe259159 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
@@ -22,7 +22,7 @@ RSpec.describe 'When a user filters Sentry errors by status', :js, :use_clean_ra
end
it 'displays the results' do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_error_tracking_index_path(project)
page.within(find('.gl-table')) do
results = page.all('.table-row')
diff --git a/spec/features/error_tracking/user_searches_sentry_errors_spec.rb b/spec/features/error_tracking/user_searches_sentry_errors_spec.rb
index c16c9d3fb1f..89bf79ebb81 100644
--- a/spec/features/error_tracking/user_searches_sentry_errors_spec.rb
+++ b/spec/features/error_tracking/user_searches_sentry_errors_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'When a user searches for Sentry errors', :js, :use_clean_rails_m
end
it 'displays the results' do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_error_tracking_index_path(project)
page.within(find('.gl-table')) do
diff --git a/spec/features/error_tracking/user_sees_error_details_spec.rb b/spec/features/error_tracking/user_sees_error_details_spec.rb
index e4a09d04ca1..ecbb3fe0412 100644
--- a/spec/features/error_tracking/user_sees_error_details_spec.rb
+++ b/spec/features/error_tracking/user_sees_error_details_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'View error details page', :js, :use_clean_rails_memory_store_cac
context 'with current user as project owner' do
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit details_project_error_tracking_index_path(project, issue_id: issue_id)
end
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 bc6709c659d..21f9e688e3f 100644
--- a/spec/features/error_tracking/user_sees_error_index_spec.rb
+++ b/spec/features/error_tracking/user_sees_error_index_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe 'View error index page', :js, :use_clean_rails_memory_store_cachi
context 'with current user as project owner' do
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_error_tracking_index_path(project)
end
@@ -43,7 +43,7 @@ RSpec.describe 'View error index page', :js, :use_clean_rails_memory_store_cachi
context 'with error tracking settings disabled' do
before do
project_error_tracking_settings.update!(enabled: false)
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_error_tracking_index_path(project)
end
diff --git a/spec/features/file_uploads/attachment_spec.rb b/spec/features/file_uploads/attachment_spec.rb
index 9ad404ce869..41da0e9fbe0 100644
--- a/spec/features/file_uploads/attachment_spec.rb
+++ b/spec/features/file_uploads/attachment_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Upload an attachment', :api, :js do
include_context 'file upload requests helpers'
let_it_be(:project) { create(:project) }
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let(:api_path) { "/projects/#{project_id}/uploads" }
diff --git a/spec/features/file_uploads/git_lfs_spec.rb b/spec/features/file_uploads/git_lfs_spec.rb
index 239afb1a1bb..8d15c5c33f7 100644
--- a/spec/features/file_uploads/git_lfs_spec.rb
+++ b/spec/features/file_uploads/git_lfs_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Upload a git lfs object', :js do
include_context 'file upload requests helpers'
let_it_be(:project) { create(:project) }
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
diff --git a/spec/features/file_uploads/maven_package_spec.rb b/spec/features/file_uploads/maven_package_spec.rb
index ab9f023bd8f..70302142fa2 100644
--- a/spec/features/file_uploads/maven_package_spec.rb
+++ b/spec/features/file_uploads/maven_package_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Upload a maven package', :api, :js do
include_context 'file upload requests helpers'
let_it_be(:project) { create(:project) }
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let(:project_id) { project.id }
diff --git a/spec/features/file_uploads/nuget_package_spec.rb b/spec/features/file_uploads/nuget_package_spec.rb
index 871c0274445..cbffd34d4ab 100644
--- a/spec/features/file_uploads/nuget_package_spec.rb
+++ b/spec/features/file_uploads/nuget_package_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Upload a nuget package', :api, :js do
include_context 'file upload requests helpers'
let_it_be(:project) { create(:project) }
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let(:api_path) { "/projects/#{project.id}/packages/nuget/" }
diff --git a/spec/features/file_uploads/rubygem_package_spec.rb b/spec/features/file_uploads/rubygem_package_spec.rb
index 4a5891fdfed..f91fb407b28 100644
--- a/spec/features/file_uploads/rubygem_package_spec.rb
+++ b/spec/features/file_uploads/rubygem_package_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Upload a RubyGems package', :api, :js do
include_context 'file upload requests helpers'
let_it_be(:project) { create(:project) }
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let(:api_path) { "/projects/#{project_id}/packages/rubygems/api/v1/gems" }
diff --git a/spec/features/gitlab_experiments_spec.rb b/spec/features/gitlab_experiments_spec.rb
index ca772680ff6..af14b6e2e95 100644
--- a/spec/features/gitlab_experiments_spec.rb
+++ b/spec/features/gitlab_experiments_spec.rb
@@ -21,8 +21,8 @@ RSpec.describe "Gitlab::Experiment", :js do
allow_next_instance_of(Admin::AbuseReportsController) do |instance|
allow(instance).to receive(:index).and_wrap_original do |original|
instance.experiment(:null_hypothesis, user: instance.current_user) do |e|
- e.use { original.call }
- e.try { original.call }
+ e.control { original.call }
+ e.candidate { original.call }
end
end
end
diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb
index 161a8a7a203..30a81333547 100644
--- a/spec/features/groups/group_settings_spec.rb
+++ b/spec/features/groups/group_settings_spec.rb
@@ -138,6 +138,51 @@ RSpec.describe 'Edit group settings' do
end
end
+ describe 'transfer group', :js do
+ let(:namespace_select) { page.find('[data-testid="transfer-group-namespace-select"]') }
+ let(:confirm_modal) { page.find('[data-testid="confirm-danger-modal"]') }
+
+ shared_examples 'can transfer the group' do
+ before do
+ selected_group.add_owner(user)
+ end
+
+ it 'can successfully transfer the group' do
+ visit edit_group_path(selected_group)
+
+ page.within('.js-group-transfer-form') do
+ namespace_select.find('button').click
+ namespace_select.find('.dropdown-menu p', text: target_group_name, match: :first).click
+
+ click_button "Transfer group"
+ end
+
+ page.within(confirm_modal) do
+ expect(page).to have_text "You are going to transfer #{selected_group.name} to another namespace. Are you ABSOLUTELY sure? "
+
+ fill_in "confirm_name_input", with: selected_group.name
+ click_button "Confirm"
+ end
+
+ expect(page).to have_text "Group '#{selected_group.name}' was successfully transferred."
+ end
+ end
+
+ context 'with a sub group' do
+ let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) }
+ let(:target_group_name) { "No parent group" }
+
+ it_behaves_like 'can transfer the group'
+ end
+
+ context 'with a root group' do
+ let(:selected_group) { create(:group, path: 'foo-rootgroup') }
+ let(:target_group_name) { group.name }
+
+ it_behaves_like 'can transfer the group'
+ end
+ end
+
context 'disable email notifications' do
it 'is visible' do
visit edit_group_path(group)
diff --git a/spec/features/groups/integrations/group_integrations_spec.rb b/spec/features/groups/integrations/group_integrations_spec.rb
new file mode 100644
index 00000000000..0d65fa5964b
--- /dev/null
+++ b/spec/features/groups/integrations/group_integrations_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Group integrations', :js do
+ include_context 'group integration activation'
+
+ it_behaves_like 'integration settings form' do
+ let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_group(group)) }
+
+ def navigate_to_integration(integration)
+ visit_group_integration(integration.title)
+ end
+ end
+end
diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb
index e6bf1ffc2f7..9612c6625f6 100644
--- a/spec/features/groups/members/leave_group_spec.rb
+++ b/spec/features/groups/members/leave_group_spec.rb
@@ -79,7 +79,7 @@ RSpec.describe 'Groups > Members > Leave group' do
visit group_path(group, leave: 1)
- expect(find('.flash-alert')).to have_content 'You do not have permission to leave this group'
+ expect(find('[data-testid="alert-danger"]')).to have_content 'You do not have permission to leave this group'
end
def left_group_message(group)
diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb
index 2beecda23b5..61c6709f9cc 100644
--- a/spec/features/groups/members/manage_groups_spec.rb
+++ b/spec/features/groups/members/manage_groups_spec.rb
@@ -156,6 +156,26 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
group_outside_hierarchy.add_owner(user)
end
+ context 'when the invite members group modal is enabled' do
+ it 'does not show self or ancestors', :aggregate_failures do
+ group_sibbling = create(:group, parent: group)
+ group_sibbling.add_owner(user)
+
+ visit group_group_members_path(group_within_hierarchy)
+
+ click_on 'Invite a group'
+ click_on 'Select a group'
+ wait_for_requests
+
+ page.within('[data-testid="group-select-dropdown"]') do
+ expect(page).to have_selector("[entity-id='#{group_outside_hierarchy.id}']")
+ expect(page).to have_selector("[entity-id='#{group_sibbling.id}']")
+ expect(page).not_to have_selector("[entity-id='#{group.id}']")
+ expect(page).not_to have_selector("[entity-id='#{group_within_hierarchy.id}']")
+ end
+ end
+ end
+
context 'when sharing with groups outside the hierarchy is enabled' do
context 'when the invite members group modal is disabled' do
before do
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 19f60ce55d3..925bbc47cf6 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe 'Group' do
click_button 'Create group'
expect(current_path).to eq(new_group_path)
- expect(page).to have_text('Please choose a group URL with no special characters or spaces.')
+ expect(page).to have_text('Choose a group path that does not start with a dash or end with a period. It can also contain alphanumeric characters and underscores.')
end
end
@@ -90,7 +90,7 @@ RSpec.describe 'Group' do
fill_in 'group_path', with: user.username
wait_for_requests
- expect(page).to have_content("Group path is already taken. We've suggested one that is available.")
+ expect(page).to have_content("Group path is unavailable. Path has been replaced with a suggested available path.")
end
it 'does not break after an invalid form submit' do
@@ -279,7 +279,7 @@ RSpec.describe 'Group' do
fill_in 'Group URL', with: subgroup.path
wait_for_requests
- expect(page).to have_content("Group path is already taken. We've suggested one that is available.")
+ expect(page).to have_content("Group path is unavailable. Path has been replaced with a suggested available path.")
end
end
end
diff --git a/spec/features/ide/user_commits_changes_spec.rb b/spec/features/ide/user_commits_changes_spec.rb
index 1b1e71e2862..e1e586a4f18 100644
--- a/spec/features/ide/user_commits_changes_spec.rb
+++ b/spec/features/ide/user_commits_changes_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'IDE user commits changes', :js do
include WebIdeSpecHelpers
let(:project) { create(:project, :public, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/ide/user_opens_merge_request_spec.rb b/spec/features/ide/user_opens_merge_request_spec.rb
index 7ae43f35901..72fe6eb6ca8 100644
--- a/spec/features/ide/user_opens_merge_request_spec.rb
+++ b/spec/features/ide/user_opens_merge_request_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'IDE merge request', :js do
let(:merge_request) { create(:merge_request, :simple, source_project: project) }
let(:project) { create(:project, :public, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb
index 2dcabb38b8f..ab7c0ce2891 100644
--- a/spec/features/issuables/markdown_references/internal_references_spec.rb
+++ b/spec/features/issuables/markdown_references/internal_references_spec.rb
@@ -5,11 +5,11 @@ require 'spec_helper'
RSpec.describe "Internal references", :js do
include Spec::Support::Helpers::Features::NotesHelpers
- let(:private_project_user) { private_project.owner }
+ let(:private_project_user) { private_project.first_owner }
let(:private_project) { create(:project, :private, :repository) }
let(:private_project_issue) { create(:issue, project: private_project) }
let(:private_project_merge_request) { create(:merge_request, source_project: private_project) }
- let(:public_project_user) { public_project.owner }
+ let(:public_project_user) { public_project.first_owner }
let(:public_project) { create(:project, :public, :repository) }
let(:public_project_issue) { create(:issue, project: public_project) }
let(:public_project_merge_request) { create(:merge_request, source_project: public_project) }
diff --git a/spec/features/issues/filtered_search/dropdown_base_spec.rb b/spec/features/issues/filtered_search/dropdown_base_spec.rb
index 3a304515cab..b8fb807dd78 100644
--- a/spec/features/issues/filtered_search/dropdown_base_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_base_spec.rb
@@ -24,23 +24,6 @@ RSpec.describe 'Dropdown base', :js do
visit project_issues_path(project)
end
- describe 'behavior' do
- it 'shows loading indicator when opened' do
- slow_requests do
- # We aren't using `input_filtered_search` because we want to see the loading indicator
- filtered_search.set('assignee:=')
-
- expect(page).to have_css("#{js_dropdown_assignee} .filter-dropdown-loading", visible: true)
- end
- end
-
- it 'hides loading indicator when loaded' do
- input_filtered_search('assignee:=', submit: false, extra_space: false)
-
- expect(find(js_dropdown_assignee)).not_to have_css('.filter-dropdown-loading')
- end
- end
-
describe 'caching requests' do
it 'caches requests after the first load' do
input_filtered_search('assignee:=', submit: false, extra_space: false)
diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb
index 3ddcbf1bd01..3929d3694ff 100644
--- a/spec/features/issues/filtered_search/recent_searches_spec.rb
+++ b/spec/features/issues/filtered_search/recent_searches_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe 'Recent searches', :js do
set_recent_searches(project_1_local_storage_key, 'fail')
visit project_issues_path(project_1)
- expect(find('.flash-alert')).to have_text('An error occurred while parsing recent searches')
+ expect(find('[data-testid="alert-danger"]')).to have_text('An error occurred while parsing recent searches')
end
context 'on tablet/mobile screen' do
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index b0e4729db8b..b4d1b0aeab9 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -6,10 +6,8 @@ RSpec.describe 'GFM autocomplete', :js do
let_it_be(:user) { create(:user, name: '๐Ÿ’ƒspeciฤ…l someone๐Ÿ’ƒ', username: 'someone.special') }
let_it_be(:user2) { create(:user, name: 'Marge Simpson', username: 'msimpson') }
- let_it_be(:group) { create(:group, name: 'Ancestor') }
- let_it_be(:child_group) { create(:group, parent: group, name: 'My group') }
- let_it_be(:project) { create(:project, group: child_group) }
-
+ let_it_be(:group) { create(:group, :crm_enabled) }
+ let_it_be(:project) { create(:project, group: group) }
let_it_be(:issue) { create(:issue, project: project, assignees: [user]) }
let_it_be(:label) { create(:label, project: project, title: 'special+') }
let_it_be(:label_scoped) { create(:label, project: project, title: 'scoped::label') }
@@ -22,675 +20,390 @@ RSpec.describe 'GFM autocomplete', :js do
let_it_be(:label_xss) { create(:label, project: project, title: label_xss_title) }
before_all do
- project.add_maintainer(user)
- project.add_maintainer(user_xss)
- project.add_maintainer(user2)
+ group.add_maintainer(user)
+ group.add_maintainer(user_xss)
+ group.add_maintainer(user2)
end
- describe 'when tribute_autocomplete feature flag is off' do
- describe 'new issue page' do
- before do
- stub_feature_flags(tribute_autocomplete: false)
-
- sign_in(user)
- visit new_project_issue_path(project)
+ describe 'new issue page' do
+ before do
+ sign_in(user)
+ visit new_project_issue_path(project)
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'allows quick actions' do
- fill_in 'Description', with: '/'
+ it 'allows quick actions' do
+ fill_in 'Description', with: '/'
- expect(find_autocomplete_menu).to be_visible
- end
+ expect(find_autocomplete_menu).to be_visible
end
+ end
- describe 'issue description' do
- let(:issue_to_edit) { create(:issue, project: project) }
-
- before do
- stub_feature_flags(tribute_autocomplete: false)
+ describe 'issue description' do
+ let(:issue_to_edit) { create(:issue, project: project) }
- sign_in(user)
- visit project_issue_path(project, issue_to_edit)
+ before do
+ sign_in(user)
+ visit project_issue_path(project, issue_to_edit)
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'updates with GFM reference' do
- click_button 'Edit title and description'
+ it 'updates with GFM reference' do
+ click_button 'Edit title and description'
- wait_for_requests
+ wait_for_requests
- fill_in 'Description', with: "@#{user.name[0...3]}"
+ fill_in 'Description', with: "@#{user.name[0...3]}"
- wait_for_requests
+ wait_for_requests
- find_highlighted_autocomplete_item.click
+ find_highlighted_autocomplete_item.click
- click_button 'Save changes'
+ click_button 'Save changes'
- wait_for_requests
+ wait_for_requests
- expect(find('.description')).to have_text(user.to_reference)
- end
+ expect(find('.description')).to have_text(user.to_reference)
+ end
- it 'allows quick actions' do
- click_button 'Edit title and description'
+ it 'allows quick actions' do
+ click_button 'Edit title and description'
- fill_in 'Description', with: '/'
+ fill_in 'Description', with: '/'
- expect(find_autocomplete_menu).to be_visible
- end
+ expect(find_autocomplete_menu).to be_visible
end
+ end
- describe 'issue comment' do
- before do
- stub_feature_flags(tribute_autocomplete: false)
-
- sign_in(user)
- visit project_issue_path(project, issue)
+ describe 'issue comment' do
+ before do
+ sign_in(user)
+ visit project_issue_path(project, issue)
- wait_for_requests
- end
+ wait_for_requests
+ end
- describe 'triggering autocomplete' do
- it 'only opens autocomplete menu when trigger character is after whitespace', :aggregate_failures do
- fill_in 'Comment', with: 'testing@'
- expect(page).not_to have_css('.atwho-view')
+ describe 'triggering autocomplete' do
+ it 'only opens autocomplete menu when trigger character is after whitespace', :aggregate_failures do
+ fill_in 'Comment', with: 'testing@'
+ expect(page).not_to have_css('.atwho-view')
- fill_in 'Comment', with: '@@'
- expect(page).not_to have_css('.atwho-view')
+ fill_in 'Comment', with: '@@'
+ expect(page).not_to have_css('.atwho-view')
- fill_in 'Comment', with: "@#{user.username[0..2]}!"
- expect(page).not_to have_css('.atwho-view')
+ fill_in 'Comment', with: "@#{user.username[0..2]}!"
+ expect(page).not_to have_css('.atwho-view')
- fill_in 'Comment', with: "hello:#{user.username[0..2]}"
- expect(page).not_to have_css('.atwho-view')
+ fill_in 'Comment', with: "hello:#{user.username[0..2]}"
+ expect(page).not_to have_css('.atwho-view')
- fill_in 'Comment', with: '7:'
- expect(page).not_to have_css('.atwho-view')
+ fill_in 'Comment', with: '7:'
+ expect(page).not_to have_css('.atwho-view')
- fill_in 'Comment', with: 'w:'
- expect(page).not_to have_css('.atwho-view')
+ fill_in 'Comment', with: 'w:'
+ expect(page).not_to have_css('.atwho-view')
- fill_in 'Comment', with: 'ะ:'
- expect(page).not_to have_css('.atwho-view')
+ fill_in 'Comment', with: 'ะ:'
+ expect(page).not_to have_css('.atwho-view')
- fill_in 'Comment', with: "test\n\n@"
- expect(find_autocomplete_menu).to be_visible
- end
+ fill_in 'Comment', with: "test\n\n@"
+ expect(find_autocomplete_menu).to be_visible
end
+ end
- context 'xss checks' do
- it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
- issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
- create(:issue, project: project, title: issue_xss_title)
-
- fill_in 'Comment', with: '#'
-
- wait_for_requests
-
- expect(find_autocomplete_menu).to have_text(issue_xss_title)
- end
-
- it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
- fill_in 'Comment', with: '@ev'
-
- wait_for_requests
-
- expect(find_highlighted_autocomplete_item).to have_text(user_xss.username)
- end
-
- it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
- milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
- create(:milestone, project: project, title: milestone_xss_title)
-
- fill_in 'Comment', with: '%'
-
- wait_for_requests
-
- expect(find_autocomplete_menu).to have_text('alert milestone')
- end
+ context 'xss checks' do
+ it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
+ issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
+ create(:issue, project: project, title: issue_xss_title)
- it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
- fill_in 'Comment', with: '~'
+ fill_in 'Comment', with: '#'
- wait_for_requests
+ wait_for_requests
- expect(find_autocomplete_menu).to have_text('alert label')
- end
+ expect(find_autocomplete_menu).to have_text(issue_xss_title)
end
- describe 'autocomplete highlighting' do
- it 'auto-selects the first item when there is a query, and only for assignees with no query', :aggregate_failures do
- fill_in 'Comment', with: ':'
- wait_for_requests
- expect(find_autocomplete_menu).not_to have_css('.cur')
+ it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
+ fill_in 'Comment', with: '@ev'
- fill_in 'Comment', with: ':1'
- wait_for_requests
- expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
+ wait_for_requests
- fill_in 'Comment', with: '@'
- wait_for_requests
- expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
- end
+ expect(find_highlighted_autocomplete_item).to have_text(user_xss.username)
end
- describe 'assignees' do
- it 'does not wrap with quotes for assignee values' do
- fill_in 'Comment', with: "@#{user.username}"
-
- find_highlighted_autocomplete_item.click
-
- expect(find_field('Comment').value).to have_text("@#{user.username}")
- end
-
- it 'includes items for assignee dropdowns with non-ASCII characters in name' do
- fill_in 'Comment', with: "@#{user.name[0...8]}"
-
- wait_for_requests
-
- expect(find_autocomplete_menu).to have_text(user.name)
- end
-
- it 'searches across full name for assignees' do
- fill_in 'Comment', with: '@speciฤ…lsome'
-
- wait_for_requests
-
- expect(find_highlighted_autocomplete_item).to have_text(user.name)
- end
-
- it 'shows names that start with the query as the top result' do
- fill_in 'Comment', with: '@mar'
-
- wait_for_requests
-
- expect(find_highlighted_autocomplete_item).to have_text(user2.name)
- end
-
- it 'shows usernames that start with the query as the top result' do
- fill_in 'Comment', with: '@msi'
-
- wait_for_requests
-
- expect(find_highlighted_autocomplete_item).to have_text(user2.name)
- end
-
- # Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/321925
- it 'shows username when pasting then pressing Enter' do
- fill_in 'Comment', with: "@#{user.username}\n"
-
- expect(find_field('Comment').value).to have_text "@#{user.username}"
- end
-
- it 'does not show `@undefined` when pressing `@` then Enter' do
- fill_in 'Comment', with: "@\n"
-
- expect(find_field('Comment').value).to have_text '@'
- expect(find_field('Comment').value).not_to have_text '@undefined'
- end
+ it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
+ milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
+ create(:milestone, project: project, title: milestone_xss_title)
- context 'when /assign quick action is selected' do
- it 'triggers user autocomplete and lists users who are currently not assigned to the issue' do
- fill_in 'Comment', with: '/as'
+ fill_in 'Comment', with: '%'
- find_highlighted_autocomplete_item.click
+ wait_for_requests
- expect(find_autocomplete_menu).not_to have_text(user.username)
- expect(find_autocomplete_menu).to have_text(user2.username)
- end
- end
+ expect(find_autocomplete_menu).to have_text('alert milestone')
end
- context 'if a selected value has special characters' do
- it 'wraps the result in double quotes' do
- fill_in 'Comment', with: "~#{label.title[0..2]}"
-
- find_highlighted_autocomplete_item.click
-
- expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
- end
-
- it 'doesn\'t wrap for emoji values' do
- fill_in 'Comment', with: ':cartwheel_'
-
- find_highlighted_autocomplete_item.click
-
- expect(find_field('Comment').value).to have_text('cartwheel_tone1')
- end
- end
+ it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
+ fill_in 'Comment', with: '~'
- context 'quick actions' do
- it 'does not limit quick actions autocomplete list to 5' do
- fill_in 'Comment', with: '/'
+ wait_for_requests
- expect(find_autocomplete_menu).to have_css('li', minimum: 6)
- end
+ expect(find_autocomplete_menu).to have_text('alert label')
end
+ end
- context 'labels' do
- it 'allows colons when autocompleting scoped labels' do
- fill_in 'Comment', with: '~scoped:'
-
- wait_for_requests
-
- expect(find_autocomplete_menu).to have_text('scoped::label')
- end
-
- it 'allows spaces when autocompleting multi-word labels' do
- fill_in 'Comment', with: '~Accepting merge'
-
- wait_for_requests
-
- expect(find_autocomplete_menu).to have_text('Accepting merge requests')
- end
-
- it 'only autocompletes the last label' do
- fill_in 'Comment', with: '~scoped:: foo bar ~Accepting merge'
+ describe 'autocomplete highlighting' do
+ it 'auto-selects the first item when there is a query, and only for assignees with no query', :aggregate_failures do
+ fill_in 'Comment', with: ':'
+ wait_for_requests
+ expect(find_autocomplete_menu).not_to have_css('.cur')
- wait_for_requests
+ fill_in 'Comment', with: ':1'
+ wait_for_requests
+ expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
- expect(find_autocomplete_menu).to have_text('Accepting merge requests')
- end
+ fill_in 'Comment', with: '@'
+ wait_for_requests
+ expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
+ end
+ end
- it 'does not autocomplete labels if no tilde is typed' do
- fill_in 'Comment', with: 'Accepting merge'
+ describe 'assignees' do
+ it 'does not wrap with quotes for assignee values' do
+ fill_in 'Comment', with: "@#{user.username}"
- wait_for_requests
+ find_highlighted_autocomplete_item.click
- expect(page).not_to have_css('.atwho-view')
- end
+ expect(find_field('Comment').value).to have_text("@#{user.username}")
end
- context 'when other notes are destroyed' do
- let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
+ it 'includes items for assignee dropdowns with non-ASCII characters in name' do
+ fill_in 'Comment', with: "@#{user.name[0...8]}"
- # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
- it 'keeps autocomplete key listeners' do
- note = find_field('Comment')
+ wait_for_requests
- start_comment_with_emoji(note, '.atwho-view li')
+ expect(find_autocomplete_menu).to have_text(user.name)
+ end
- start_and_cancel_discussion
+ it 'searches across full name for assignees' do
+ fill_in 'Comment', with: '@speciฤ…lsome'
- note.fill_in(with: '')
- start_comment_with_emoji(note, '.atwho-view li')
- note.native.send_keys(:enter)
+ wait_for_requests
- expect(note.value).to eql('Hello :100: ')
- end
+ expect(find_highlighted_autocomplete_item).to have_text(user.name)
end
- shared_examples 'autocomplete suggestions' do
- it 'suggests objects correctly' do
- fill_in 'Comment', with: object.class.reference_prefix
+ it 'shows names that start with the query as the top result' do
+ fill_in 'Comment', with: '@mar'
- find_autocomplete_menu.find('li').click
+ wait_for_requests
- expect(find_field('Comment').value).to have_text(expected_body)
- end
+ expect(find_highlighted_autocomplete_item).to have_text(user2.name)
end
- context 'issues' do
- let(:object) { issue }
- let(:expected_body) { object.to_reference }
+ it 'shows usernames that start with the query as the top result' do
+ fill_in 'Comment', with: '@msi'
- it_behaves_like 'autocomplete suggestions'
- end
-
- context 'merge requests' do
- let(:object) { create(:merge_request, source_project: project) }
- let(:expected_body) { object.to_reference }
+ wait_for_requests
- it_behaves_like 'autocomplete suggestions'
+ expect(find_highlighted_autocomplete_item).to have_text(user2.name)
end
- context 'project snippets' do
- let!(:object) { snippet }
- let(:expected_body) { object.to_reference }
+ # Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/321925
+ it 'shows username when pasting then pressing Enter' do
+ fill_in 'Comment', with: "@#{user.username}\n"
- it_behaves_like 'autocomplete suggestions'
+ expect(find_field('Comment').value).to have_text "@#{user.username}"
end
- context 'milestone' do
- let_it_be(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
- let_it_be(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
- let_it_be(:milestone1) { create(:milestone, project: project, title: 'Milestone-1', due_date: 20.days.from_now) }
- let_it_be(:milestone2) { create(:milestone, project: project, title: 'Milestone-2', due_date: 15.days.from_now) }
- let_it_be(:milestone3) { create(:milestone, project: project, title: 'Milestone-3', due_date: 10.days.from_now) }
-
- before do
- fill_in 'Comment', with: '/milestone %'
+ it 'does not show `@undefined` when pressing `@` then Enter' do
+ fill_in 'Comment', with: "@\n"
- wait_for_requests
- end
+ expect(find_field('Comment').value).to have_text '@'
+ expect(find_field('Comment').value).not_to have_text '@undefined'
+ end
- it 'shows milestons list in the autocomplete menu' do
- page.within(find_autocomplete_menu) do
- expect(page).to have_selector('li', count: 5)
- end
- end
+ context 'when /assign quick action is selected' do
+ it 'triggers user autocomplete and lists users who are currently not assigned to the issue' do
+ fill_in 'Comment', with: '/as'
- it 'shows expired milestone at the bottom of the list' do
- page.within(find_autocomplete_menu) do
- expect(page.find('li:last-child')).to have_content milestone_expired.title
- end
- end
+ find_highlighted_autocomplete_item.click
- it 'shows milestone due earliest at the top of the list' do
- page.within(find_autocomplete_menu) do
- aggregate_failures do
- expect(page.all('li')[0]).to have_content milestone3.title
- expect(page.all('li')[1]).to have_content milestone2.title
- expect(page.all('li')[2]).to have_content milestone1.title
- expect(page.all('li')[3]).to have_content milestone_no_duedate.title
- end
- end
+ expect(find_autocomplete_menu).not_to have_text(user.username)
+ expect(find_autocomplete_menu).to have_text(user2.username)
end
end
end
- end
- describe 'when tribute_autocomplete feature flag is on' do
- describe 'issue description' do
- let(:issue_to_edit) { create(:issue, project: project) }
+ context 'if a selected value has special characters' do
+ it 'wraps the result in double quotes' do
+ fill_in 'Comment', with: "~#{label.title[0..2]}"
- before do
- stub_feature_flags(tribute_autocomplete: true)
-
- sign_in(user)
- visit project_issue_path(project, issue_to_edit)
+ find_highlighted_autocomplete_item.click
- wait_for_requests
+ expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
end
- it 'updates with GFM reference' do
- click_button 'Edit title and description'
-
- wait_for_requests
-
- fill_in 'Description', with: "@#{user.name[0...3]}"
+ it 'doesn\'t wrap for emoji values' do
+ fill_in 'Comment', with: ':cartwheel_'
- wait_for_requests
-
- find_highlighted_tribute_autocomplete_menu.click
-
- click_button 'Save changes'
-
- wait_for_requests
+ find_highlighted_autocomplete_item.click
- expect(find('.description')).to have_text(user.to_reference)
+ expect(find_field('Comment').value).to have_text('cartwheel_tone1')
end
end
- describe 'issue comment' do
- before do
- stub_feature_flags(tribute_autocomplete: true)
-
- sign_in(user)
- visit project_issue_path(project, issue)
+ context 'quick actions' do
+ it 'does not limit quick actions autocomplete list to 5' do
+ fill_in 'Comment', with: '/'
- wait_for_requests
+ expect(find_autocomplete_menu).to have_css('li', minimum: 6)
end
+ end
- describe 'triggering autocomplete' do
- it 'only opens autocomplete menu when trigger character is after whitespace', :aggregate_failures do
- fill_in 'Comment', with: 'testing@'
- expect(page).not_to have_css('.tribute-container')
-
- fill_in 'Comment', with: "hello:#{user.username[0..2]}"
- expect(page).not_to have_css('.tribute-container')
-
- fill_in 'Comment', with: '7:'
- expect(page).not_to have_css('.tribute-container')
-
- fill_in 'Comment', with: 'w:'
- expect(page).not_to have_css('.tribute-container')
+ context 'labels' do
+ it 'allows colons when autocompleting scoped labels' do
+ fill_in 'Comment', with: '~scoped:'
- fill_in 'Comment', with: 'ะ:'
- expect(page).not_to have_css('.tribute-container')
+ wait_for_requests
- fill_in 'Comment', with: "test\n\n@"
- expect(find_tribute_autocomplete_menu).to be_visible
- end
+ expect(find_autocomplete_menu).to have_text('scoped::label')
end
- context 'xss checks' do
- it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
- issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
- create(:issue, project: project, title: issue_xss_title)
-
- fill_in 'Comment', with: '#'
-
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).to have_text(issue_xss_title)
- end
-
- it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
- fill_in 'Comment', with: '@ev'
-
- wait_for_requests
+ it 'allows spaces when autocompleting multi-word labels' do
+ fill_in 'Comment', with: '~Accepting merge'
- expect(find_tribute_autocomplete_menu).to have_text(user_xss.username)
- end
-
- it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
- milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
- create(:milestone, project: project, title: milestone_xss_title)
-
- fill_in 'Comment', with: '%'
-
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).to have_text('alert milestone')
- end
-
- it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
- fill_in 'Comment', with: '~'
-
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).to have_text('alert label')
- end
- end
-
- describe 'autocomplete highlighting' do
- it 'auto-selects the first item with query', :aggregate_failures do
- fill_in 'Comment', with: ':1'
- wait_for_requests
- expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
+ wait_for_requests
- fill_in 'Comment', with: '@'
- wait_for_requests
- expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
- end
+ expect(find_autocomplete_menu).to have_text('Accepting merge requests')
end
- describe 'assignees' do
- it 'does not wrap with quotes for assignee values' do
- fill_in 'Comment', with: "@#{user.username[0..2]}"
+ it 'only autocompletes the last label' do
+ fill_in 'Comment', with: '~scoped:: foo bar ~Accepting merge'
- find_highlighted_tribute_autocomplete_menu.click
-
- expect(find_field('Comment').value).to have_text("@#{user.username}")
- end
-
- it 'includes items for assignee dropdowns with non-ASCII characters in name' do
- fill_in 'Comment', with: "@#{user.name[0...8]}"
-
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).to have_text(user.name)
- end
-
- context 'when autocompleting for groups' do
- it 'shows the group when searching for the name of the group' do
- fill_in 'Comment', with: '@mygroup'
+ wait_for_requests
- expect(find_tribute_autocomplete_menu).to have_text('My group')
- end
+ expect(find_autocomplete_menu).to have_text('Accepting merge requests')
+ end
- it 'does not show the group when searching for the name of the parent of the group' do
- fill_in 'Comment', with: '@ancestor'
+ it 'does not autocomplete labels if no tilde is typed' do
+ fill_in 'Comment', with: 'Accepting merge'
- expect(find_tribute_autocomplete_menu).not_to have_text('My group')
- end
- end
-
- context 'when /assign quick action is selected' do
- it 'lists users who are currently not assigned to the issue' do
- note = find_field('Comment')
- note.native.send_keys('/assign ')
- # The `/assign` ajax response might replace the one by `@` below causing a failed test
- # so we need to wait for the `/assign` ajax request to finish first
- wait_for_requests
- note.native.send_keys('@')
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
- expect(find_tribute_autocomplete_menu).to have_text(user2.username)
- end
+ wait_for_requests
- it 'lists users who are currently not assigned to the issue when using /assign on the second line' do
- note = find_field('Comment')
- note.native.send_keys('/assign @user2')
- note.native.send_keys(:enter)
- note.native.send_keys('/assign ')
- # The `/assign` ajax response might replace the one by `@` below causing a failed test
- # so we need to wait for the `/assign` ajax request to finish first
- wait_for_requests
- note.native.send_keys('@')
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
- expect(find_tribute_autocomplete_menu).to have_text(user2.username)
- end
- end
+ expect(page).not_to have_css('.atwho-view')
end
+ end
- context 'if a selected value has special characters' do
- it 'wraps the result in double quotes' do
- fill_in 'Comment', with: "~#{label.title[0..2]}"
+ context 'when other notes are destroyed' do
+ let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
- find_highlighted_tribute_autocomplete_menu.click
+ # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
+ it 'keeps autocomplete key listeners' do
+ note = find_field('Comment')
- expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
- end
+ start_comment_with_emoji(note, '.atwho-view li')
- it 'does not wrap for emoji values' do
- fill_in 'Comment', with: ':cartwheel_'
+ start_and_cancel_discussion
- find_highlighted_tribute_autocomplete_menu.click
+ note.fill_in(with: '')
+ start_comment_with_emoji(note, '.atwho-view li')
+ note.native.send_keys(:enter)
- expect(find_field('Comment').value).to have_text('cartwheel_tone1')
- end
+ expect(note.value).to eql('Hello :100: ')
end
+ end
- context 'quick actions' do
- it 'autocompletes for quick actions' do
- fill_in 'Comment', with: '/as'
+ shared_examples 'autocomplete suggestions' do
+ it 'suggests objects correctly' do
+ fill_in 'Comment', with: object.class.reference_prefix
- find_highlighted_tribute_autocomplete_menu.click
+ find_autocomplete_menu.find('li').click
- expect(find_field('Comment').value).to have_text('/assign')
- end
+ expect(find_field('Comment').value).to have_text(expected_body)
end
+ end
- context 'labels' do
- it 'allows colons when autocompleting scoped labels' do
- fill_in 'Comment', with: '~scoped:'
-
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).to have_text('scoped::label')
- end
+ context 'issues' do
+ let(:object) { issue }
+ let(:expected_body) { object.to_reference }
- it 'autocompletes multi-word labels' do
- fill_in 'Comment', with: '~Acceptingmerge'
+ it_behaves_like 'autocomplete suggestions'
+ end
- wait_for_requests
+ context 'merge requests' do
+ let(:object) { create(:merge_request, source_project: project) }
+ let(:expected_body) { object.to_reference }
- expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
- end
+ it_behaves_like 'autocomplete suggestions'
+ end
- it 'only autocompletes the last label' do
- fill_in 'Comment', with: '~scoped:: foo bar ~Acceptingmerge'
- # Invoke autocompletion
- find_field('Comment').native.send_keys(:right)
+ context 'project snippets' do
+ let!(:object) { snippet }
+ let(:expected_body) { object.to_reference }
- wait_for_requests
+ it_behaves_like 'autocomplete suggestions'
+ end
- expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
- end
+ context 'milestone' do
+ let_it_be(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
+ let_it_be(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
+ let_it_be(:milestone1) { create(:milestone, project: project, title: 'Milestone-1', due_date: 20.days.from_now) }
+ let_it_be(:milestone2) { create(:milestone, project: project, title: 'Milestone-2', due_date: 15.days.from_now) }
+ let_it_be(:milestone3) { create(:milestone, project: project, title: 'Milestone-3', due_date: 10.days.from_now) }
- it 'does not autocomplete labels if no tilde is typed' do
- fill_in 'Comment', with: 'Accepting'
+ before do
+ fill_in 'Comment', with: '/milestone %'
- wait_for_requests
+ wait_for_requests
+ end
- expect(page).not_to have_css('.tribute-container')
+ it 'shows milestons list in the autocomplete menu' do
+ page.within(find_autocomplete_menu) do
+ expect(page).to have_selector('li', count: 5)
end
end
- context 'when other notes are destroyed' do
- let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
-
- # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
- it 'keeps autocomplete key listeners' do
- note = find_field('Comment')
-
- start_comment_with_emoji(note, '.tribute-container li')
-
- start_and_cancel_discussion
-
- note.fill_in(with: '')
- start_comment_with_emoji(note, '.tribute-container li')
- note.native.send_keys(:enter)
-
- expect(note.value).to eql('Hello :100: ')
+ it 'shows expired milestone at the bottom of the list' do
+ page.within(find_autocomplete_menu) do
+ expect(page.find('li:last-child')).to have_content milestone_expired.title
end
end
- shared_examples 'autocomplete suggestions' do
- it 'suggests objects correctly' do
- fill_in 'Comment', with: object.class.reference_prefix
-
- find_tribute_autocomplete_menu.find('li').click
-
- expect(find_field('Comment').value).to have_text(expected_body)
+ it 'shows milestone due earliest at the top of the list' do
+ page.within(find_autocomplete_menu) do
+ aggregate_failures do
+ expect(page.all('li')[0]).to have_content milestone3.title
+ expect(page.all('li')[1]).to have_content milestone2.title
+ expect(page.all('li')[2]).to have_content milestone1.title
+ expect(page.all('li')[3]).to have_content milestone_no_duedate.title
+ end
end
end
+ end
- context 'issues' do
- let(:object) { issue }
- let(:expected_body) { object.to_reference }
-
- it_behaves_like 'autocomplete suggestions'
- end
+ context 'contact' do
+ let_it_be(:contacts) { create_list(:contact, 2, group: group) }
- context 'merge requests' do
- let(:object) { create(:merge_request, source_project: project) }
- let(:expected_body) { object.to_reference }
+ before do
+ fill_in 'Comment', with: '/add_contacts [contact:'
- it_behaves_like 'autocomplete suggestions'
+ wait_for_requests
end
- context 'project snippets' do
- let!(:object) { snippet }
- let(:expected_body) { object.to_reference }
-
- it_behaves_like 'autocomplete suggestions'
+ it 'shows contacts list in the autocomplete menu' do
+ page.within(find_autocomplete_menu) do
+ expect(page).to have_selector('li', count: 2)
+ end
end
- context 'milestone' do
- let!(:object) { create(:milestone, project: project) }
- let(:expected_body) { object.to_reference }
+ it 'shows all contacts' do
+ page.within(find_autocomplete_menu) do
+ expected_data = contacts.map { |c| "#{c.first_name} #{c.last_name} #{c.email}"}
- it_behaves_like 'autocomplete suggestions'
+ expect(page.all('li').map(&:text)).to match_array(expected_data)
+ end
end
end
end
@@ -707,9 +420,10 @@ RSpec.describe 'GFM autocomplete', :js do
def start_and_cancel_discussion
fill_in('Reply to comment', with: 'Whoops!')
+ click_button('Cancel')
- page.accept_alert 'Are you sure you want to cancel creating this comment?' do
- click_button('Cancel')
+ page.within('.modal') do
+ click_button('OK', match: :first)
end
wait_for_requests
@@ -722,12 +436,4 @@ RSpec.describe 'GFM autocomplete', :js do
def find_highlighted_autocomplete_item
find('.atwho-view li.cur', visible: true)
end
-
- def find_tribute_autocomplete_menu
- find('.tribute-container ul', visible: true)
- end
-
- def find_highlighted_tribute_autocomplete_menu
- find('.tribute-container li.highlight', visible: true)
- end
end
diff --git a/spec/features/issues/keyboard_shortcut_spec.rb b/spec/features/issues/keyboard_shortcut_spec.rb
index 502412bab5d..4dbc5d8e01c 100644
--- a/spec/features/issues/keyboard_shortcut_spec.rb
+++ b/spec/features/issues/keyboard_shortcut_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'Issues shortcut', :js do
let(:project) { create(:project) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_path(project)
end
@@ -23,7 +23,7 @@ RSpec.describe 'Issues shortcut', :js do
let(:project) { create(:project, :issues_disabled) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_path(project)
end
diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb
index 315d1c911a2..d63d21353e5 100644
--- a/spec/features/issues/todo_spec.rb
+++ b/spec/features/issues/todo_spec.rb
@@ -19,13 +19,13 @@ RSpec.describe 'Manually create a todo item from issue', :js do
expect(page).to have_content 'Mark as done'
end
- page.within '.header-content .todos-count' do
+ page.within ".header-content span[aria-label='#{_('Todos count')}']" do
expect(page).to have_content '1'
end
visit project_issue_path(project, issue)
- page.within '.header-content .todos-count' do
+ page.within ".header-content span[aria-label='#{_('Todos count')}']" do
expect(page).to have_content '1'
end
end
@@ -36,10 +36,10 @@ RSpec.describe 'Manually create a todo item from issue', :js do
click_button 'Mark as done'
end
- expect(page).to have_selector('.todos-count', visible: false)
+ expect(page).to have_selector(".header-content span[aria-label='#{_('Todos count')}']", visible: false)
visit project_issue_path(project, issue)
- expect(page).to have_selector('.todos-count', visible: false)
+ expect(page).to have_selector(".header-content span[aria-label='#{_('Todos count')}']", visible: false)
end
end
diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb
index 5d03aa1fc2b..a719263f092 100644
--- a/spec/features/issues/user_comments_on_issue_spec.rb
+++ b/spec/features/issues/user_comments_on_issue_spec.rb
@@ -10,7 +10,6 @@ RSpec.describe "User comments on issue", :js do
let(:user) { create(:user) }
before do
- stub_feature_flags(tribute_autocomplete: false)
stub_feature_flags(sandboxed_mermaid: false)
project.add_guest(user)
sign_in(user)
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 875b0a60634..167521134b1 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
@@ -71,16 +71,10 @@ RSpec.describe 'User creates branch and merge request on issue page', :js do
perform_enqueued_jobs do
select_dropdown_option('create-mr')
- expect(page).to have_content('Draft: Resolve "Cherry-Coloured Funk"')
- expect(current_path).to eq(project_merge_request_path(project, MergeRequest.first))
-
- wait_for_requests
+ expect(page).to have_content('New merge request')
+ expect(page).to have_content("From #{issue.to_branch_name} into #{project.default_branch}")
+ expect(page).to have_current_path(project_new_merge_request_path(project, merge_request: { source_branch: issue.to_branch_name, target_branch: project.default_branch }))
end
-
- visit project_issue_path(project, issue)
-
- expect(page).to have_content("created merge request !1 to address this issue")
- expect(page).to have_content('mentioned in merge request !1')
end
it 'creates a branch' do
@@ -100,17 +94,10 @@ RSpec.describe 'User creates branch and merge request on issue page', :js do
perform_enqueued_jobs do
select_dropdown_option('create-mr', branch_name)
- expect(page).to have_content('Draft: Resolve "Cherry-Coloured Funk"')
- expect(page).to have_content('Request to merge custom-branch-name into')
- expect(current_path).to eq(project_merge_request_path(project, MergeRequest.first))
-
- wait_for_requests
+ expect(page).to have_content('New merge request')
+ expect(page).to have_content("From #{branch_name} into #{project.default_branch}")
+ expect(page).to have_current_path(project_new_merge_request_path(project, merge_request: { source_branch: branch_name, target_branch: project.default_branch }))
end
-
- visit project_issue_path(project, issue)
-
- expect(page).to have_content("created merge request !1 to address this issue")
- expect(page).to have_content('mentioned in merge request !1')
end
it 'creates a branch' do
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index a036a9a5bbc..8c906e6a27c 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -145,7 +145,7 @@ RSpec.describe "Issues > User edits issue", :js do
fill_in 'Comment', with: '/label ~syzygy'
click_button 'Comment'
- expect(page).to have_text('added syzygy label just now', wait: 300)
+ expect(page).to have_text('added syzygy label just now')
page.within '.block.labels' do
# Remove `verisimilitude` label
diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb
index 2e52a8d862e..892b57bac5c 100644
--- a/spec/features/issues/user_interacts_with_awards_spec.rb
+++ b/spec/features/issues/user_interacts_with_awards_spec.rb
@@ -65,9 +65,10 @@ RSpec.describe 'User interacts with awards' do
expect(page.find('[data-testid="award-button"].selected .js-counter')).to have_content('1')
expect(page).to have_css('[data-testid="award-button"].selected[title="You reacted with :8ball:"]')
+ wait_for_requests
+
expect do
page.find('[data-testid="award-button"].selected').click
- wait_for_requests
end.to change { page.all('[data-testid="award-button"]').size }.from(3).to(2)
end
end
diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb
index 48297e9049e..f3eaff379a1 100644
--- a/spec/features/issues/user_sorts_issues_spec.rb
+++ b/spec/features/issues/user_sorts_issues_spec.rb
@@ -119,89 +119,6 @@ RSpec.describe "User sorts issues" do
end
end
- describe 'filtering by due date', :js do
- before do
- issue1.update!(due_date: 1.day.from_now)
- issue2.update!(due_date: 6.days.from_now)
- end
-
- it 'filters by none' do
- visit project_issues_path(project, due_date: Issue::NoDueDate.name)
-
- page.within '.issues-list' do
- expect(page).not_to have_content('foo')
- expect(page).not_to have_content('bar')
- expect(page).to have_content('baz')
- end
- end
-
- it 'filters by any' do
- visit project_issues_path(project, due_date: Issue::AnyDueDate.name)
-
- page.within '.issues-list' do
- expect(page).to have_content('foo')
- expect(page).to have_content('bar')
- expect(page).to have_content('baz')
- end
- end
-
- it 'filters by due this week' do
- issue1.update!(due_date: Date.today.beginning_of_week + 2.days)
- issue2.update!(due_date: Date.today.end_of_week)
- issue3.update!(due_date: Date.today - 8.days)
-
- visit project_issues_path(project, due_date: Issue::DueThisWeek.name)
-
- page.within '.issues-list' do
- expect(page).to have_content('foo')
- expect(page).to have_content('bar')
- expect(page).not_to have_content('baz')
- end
- end
-
- it 'filters by due this month' do
- issue1.update!(due_date: Date.today.beginning_of_month + 2.days)
- issue2.update!(due_date: Date.today.end_of_month)
- issue3.update!(due_date: Date.today - 50.days)
-
- visit project_issues_path(project, due_date: Issue::DueThisMonth.name)
-
- page.within '.issues-list' do
- expect(page).to have_content('foo')
- expect(page).to have_content('bar')
- expect(page).not_to have_content('baz')
- end
- end
-
- it 'filters by overdue' do
- issue1.update!(due_date: Date.today + 2.days)
- issue2.update!(due_date: Date.today + 20.days)
- issue3.update!(due_date: Date.yesterday)
-
- visit project_issues_path(project, due_date: Issue::Overdue.name)
-
- page.within '.issues-list' do
- expect(page).not_to have_content('foo')
- expect(page).not_to have_content('bar')
- expect(page).to have_content('baz')
- end
- end
-
- it 'filters by due next month and previous two weeks' do
- issue1.update!(due_date: Date.today - 4.weeks)
- issue2.update!(due_date: (Date.today + 2.months).beginning_of_month)
- issue3.update!(due_date: Date.yesterday)
-
- visit project_issues_path(project, due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name)
-
- page.within '.issues-list' do
- expect(page).not_to have_content('foo')
- expect(page).not_to have_content('bar')
- expect(page).to have_content('baz')
- end
- end
- end
-
describe 'sorting by milestone', :js do
before do
issue1.milestone = newer_due_milestone
diff --git a/spec/features/jira_connect/branches_spec.rb b/spec/features/jira_connect/branches_spec.rb
index 6fa600c6906..c334a425849 100644
--- a/spec/features/jira_connect/branches_spec.rb
+++ b/spec/features/jira_connect/branches_spec.rb
@@ -25,8 +25,9 @@ RSpec.describe 'Create GitLab branches from Jira', :js do
it 'select project and branch and submit the form' do
visit new_jira_connect_branch_path(issue_key: 'ACME-123', issue_summary: 'My issue !@#$% title')
- expect(page).to have_field('Branch name', with: 'ACME-123-my-issue-title')
expect(page).to have_button('Create branch', disabled: true)
+ # initially, branch field should be hidden.
+ expect(page).not_to have_field('Branch name')
# Select project1
@@ -44,6 +45,7 @@ RSpec.describe 'Create GitLab branches from Jira', :js do
click_on 'Alice / foo'
end
+ expect(page).to have_field('Branch name', with: 'ACME-123-my-issue-title')
expect(page).to have_button('Create branch', disabled: false)
click_on 'master'
diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb
index 0e5a20fe24a..6951d8298e5 100644
--- a/spec/features/markdown/copy_as_gfm_spec.rb
+++ b/spec/features/markdown/copy_as_gfm_spec.rb
@@ -663,7 +663,7 @@ RSpec.describe 'Copy as GFM', :js do
let(:project) { create(:project, :repository) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
end
context 'from a diff' do
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index f695b225915..eb98c7d5061 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe 'Merge request > Batch comments', :js do
expect(page).to have_selector('[data-testid="review_bar_component"]')
- expect(find('.review-bar-content .btn-confirm')).to have_content('1')
+ expect(find('[data-testid="review_bar_component"] .btn-confirm')).to have_content('1')
end
it 'publishes review' do
@@ -64,7 +64,11 @@ RSpec.describe 'Merge request > Batch comments', :js do
it 'deletes draft note' do
write_diff_comment
- accept_alert { find('.js-note-delete').click }
+ find('.js-note-delete').click
+
+ page.within('.modal') do
+ click_button('Delete Comment', match: :first)
+ end
wait_for_requests
@@ -146,10 +150,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
it 'adds draft comments to both sides' do
write_parallel_comment('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9')
-
- # make sure line 9 is in the view
- execute_script("window.scrollBy(0, -200)")
-
write_parallel_comment('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9', button_text: 'Add to review', text: 'Another wrong line')
expect(find('.new .draft-note-component')).to have_content('Line is wrong')
@@ -251,13 +251,15 @@ RSpec.describe 'Merge request > Batch comments', :js do
end
def write_diff_comment(**params)
- click_diff_line(find("[id='#{sample_compare.changes[0][:line_code]}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[0][:line_code]}']"))
write_comment(**params)
end
def write_parallel_comment(line, **params)
- find("div[id='#{line}']").hover
+ line_element = find_by_scrolling("[id='#{line}']")
+ scroll_to_elements_bottom(line_element)
+ line_element.hover
find(".js-add-diff-note-button").click
write_comment(selector: "form[data-line-code='#{line}']", **params)
diff --git a/spec/features/merge_request/user_awards_emoji_spec.rb b/spec/features/merge_request/user_awards_emoji_spec.rb
index 240b8f996c8..35eadb34799 100644
--- a/spec/features/merge_request/user_awards_emoji_spec.rb
+++ b/spec/features/merge_request/user_awards_emoji_spec.rb
@@ -27,6 +27,7 @@ RSpec.describe 'Merge request > User awards emoji', :js do
it 'removes award from merge request' do
first('[data-testid="award-button"]').click
+ expect(first('[data-testid="award-button"]')).to have_content '1'
find('[data-testid="award-button"].selected').click
expect(first('[data-testid="award-button"]')).to have_content '0'
diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb
index f9b554c5ed2..c06019f6b77 100644
--- a/spec/features/merge_request/user_comments_on_diff_spec.rb
+++ b/spec/features/merge_request/user_comments_on_diff_spec.rb
@@ -25,14 +25,15 @@ RSpec.describe 'User comments on a diff', :js do
context 'when toggling inline comments' do
context 'in a single file' do
it 'hides a comment' do
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ line_element = find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']").find(:xpath, "..")
+ click_diff_line(line_element)
page.within('.js-discussion-note-form') do
fill_in('note_note', with: 'Line is wrong')
click_button('Add comment now')
end
- page.within('.diff-files-holder > div:nth-child(6)') do
+ page.within(line_element.ancestor('[data-path]')) do
expect(page).to have_content('Line is wrong')
find('.js-diff-more-actions').click
@@ -45,7 +46,9 @@ RSpec.describe 'User comments on a diff', :js do
context 'in multiple files' do
it 'toggles comments' do
- click_diff_line(find("[id='#{sample_compare.changes[0][:line_code]}']"))
+ first_line_element = find_by_scrolling("[id='#{sample_compare.changes[0][:line_code]}']").find(:xpath, "..")
+ first_root_element = first_line_element.ancestor('[data-path]')
+ click_diff_line(first_line_element)
page.within('.js-discussion-note-form') do
fill_in('note_note', with: 'Line is correct')
@@ -54,11 +57,14 @@ RSpec.describe 'User comments on a diff', :js do
wait_for_requests
- page.within('.diff-files-holder > div:nth-child(5) .note-body > .note-text') do
+ page.within(first_root_element) do
expect(page).to have_content('Line is correct')
end
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ second_line_element = find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']")
+ second_root_element = second_line_element.ancestor('[data-path]')
+
+ click_diff_line(second_line_element)
page.within('.js-discussion-note-form') do
fill_in('note_note', with: 'Line is wrong')
@@ -68,7 +74,7 @@ RSpec.describe 'User comments on a diff', :js do
wait_for_requests
# Hide the comment.
- page.within('.diff-files-holder > div:nth-child(6)') do
+ page.within(second_root_element) do
find('.js-diff-more-actions').click
click_button 'Hide comments on this file'
@@ -77,37 +83,36 @@ RSpec.describe 'User comments on a diff', :js do
# At this moment a user should see only one comment.
# The other one should be hidden.
- page.within('.diff-files-holder > div:nth-child(5) .note-body > .note-text') do
+ page.within(first_root_element) do
expect(page).to have_content('Line is correct')
end
# Show the comment.
- page.within('.diff-files-holder > div:nth-child(6)') do
+ page.within(second_root_element) do
find('.js-diff-more-actions').click
click_button 'Show comments on this file'
end
# Now both the comments should be shown.
- page.within('.diff-files-holder > div:nth-child(6) .note-body > .note-text') do
+ page.within(second_root_element) do
expect(page).to have_content('Line is wrong')
end
- page.within('.diff-files-holder > div:nth-child(5) .note-body > .note-text') do
+ page.within(first_root_element) do
expect(page).to have_content('Line is correct')
end
# Check the same comments in the side-by-side view.
- execute_script("window.scrollTo(0,0);")
find('.js-show-diff-settings').click
click_button 'Side-by-side'
wait_for_requests
- page.within('.diff-files-holder > div:nth-child(6) .parallel .note-body > .note-text') do
+ page.within(second_root_element) do
expect(page).to have_content('Line is wrong')
end
- page.within('.diff-files-holder > div:nth-child(5) .parallel .note-body > .note-text') do
+ page.within(first_root_element) do
expect(page).to have_content('Line is correct')
end
end
@@ -121,7 +126,7 @@ RSpec.describe 'User comments on a diff', :js do
context 'when adding multiline comments' do
it 'saves a multiline comment' do
- click_diff_line(find("[id='#{sample_commit.line_code}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_commit.line_code}']").find(:xpath, '..'))
add_comment('-13', '+14')
end
@@ -133,13 +138,13 @@ RSpec.describe 'User comments on a diff', :js do
# In `files/ruby/popen.rb`
it 'allows comments for changes involving both sides' do
# click +15, select -13 add and verify comment
- click_diff_line(find('div[data-path="files/ruby/popen.rb"] .right-side a[data-linenumber="15"]').find(:xpath, '../../..'), 'right')
+ click_diff_line(find_by_scrolling('div[data-path="files/ruby/popen.rb"] .right-side a[data-linenumber="15"]').find(:xpath, '../../..'), 'right')
add_comment('-13', '+15')
end
it 'allows comments on previously hidden lines at the top of a file', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/285294' do
# Click -9, expand up, select 1 add and verify comment
- page.within('[data-path="files/ruby/popen.rb"]') do
+ page.within find_by_scrolling('[data-path="files/ruby/popen.rb"]') do
all('.js-unfold-all')[0].click
end
click_diff_line(find('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="9"]').find(:xpath, '../..'), 'left')
@@ -148,7 +153,7 @@ RSpec.describe 'User comments on a diff', :js do
it 'allows comments on previously hidden lines the middle of a file' do
# Click 27, expand up, select 18, add and verify comment
- page.within('[data-path="files/ruby/popen.rb"]') do
+ page.within find_by_scrolling('[data-path="files/ruby/popen.rb"]') do
all('.js-unfold-all')[1].click
end
click_diff_line(find('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="21"]').find(:xpath, '../..'), 'left')
@@ -157,8 +162,8 @@ RSpec.describe 'User comments on a diff', :js do
it 'allows comments on previously hidden lines at the bottom of a file' do
# Click +28, expand down, select 37 add and verify comment
- page.within('[data-path="files/ruby/popen.rb"]') do
- all('.js-unfold-down')[1].click
+ page.within find_by_scrolling('[data-path="files/ruby/popen.rb"]') do
+ all('.js-unfold-down:not([disabled])')[1].click
end
click_diff_line(find('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="30"]').find(:xpath, '../..'), 'left')
add_comment('+28', '37')
@@ -198,7 +203,7 @@ RSpec.describe 'User comments on a diff', :js do
context 'when editing comments' do
it 'edits a comment' do
- click_diff_line(find("[id='#{sample_commit.line_code}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_commit.line_code}']"))
page.within('.js-discussion-note-form') do
fill_in(:note_note, with: 'Line is wrong')
@@ -224,7 +229,7 @@ RSpec.describe 'User comments on a diff', :js do
context 'when deleting comments' do
it 'deletes a comment' do
- click_diff_line(find("[id='#{sample_commit.line_code}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_commit.line_code}']"))
page.within('.js-discussion-note-form') do
fill_in(:note_note, with: 'Line is wrong')
@@ -238,8 +243,11 @@ RSpec.describe 'User comments on a diff', :js do
page.within('.diff-file:nth-of-type(1) .discussion .note') do
find('.more-actions').click
find('.more-actions .dropdown-menu li', match: :first)
+ find('.js-note-delete').click
+ end
- accept_confirm { find('.js-note-delete').click }
+ page.within('.modal') do
+ click_button('Delete Comment', match: :first)
end
page.within('.merge-request-tabs') do
diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
index cc0d7a279dd..15f186b649a 100644
--- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe 'Merge request > User creates image diff notes', :js do
it 'shows indicator and avatar badges, and allows collapsing/expanding the discussion notes' do
indicator = find('.js-image-badge')
- badge = find('.image-diff-avatar-link .badge')
+ badge = find('.image-diff-avatar-link .design-note-pin')
expect(indicator).to have_content('1')
expect(badge).to have_content('1')
@@ -127,7 +127,7 @@ RSpec.describe 'Merge request > User creates image diff notes', :js do
visit diffs_project_merge_request_path(project, merge_request, view: view)
wait_for_requests
- expect(page.all('.diff-file span.label-lfs', visible: :all)).not_to be_empty
+ expect(page.all('[data-testid="label-lfs"]', visible: :all)).not_to be_empty
end
it_behaves_like 'creates image diff note'
diff --git a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
index 1087be3d8c6..5894ec923c2 100644
--- a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
+++ b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js do
before do
stub_const('Autocomplete::UsersFinder::LIMIT', users_find_limit)
- sign_in(project.owner)
+ sign_in(project.first_owner)
merge_request.assignees << assignee
diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb
index 52554f11d28..25c9584350d 100644
--- a/spec/features/merge_request/user_expands_diff_spec.rb
+++ b/spec/features/merge_request/user_expands_diff_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'User expands diff', :js do
let(:merge_request) { create(:merge_request, source_branch: 'expand-collapse-files', source_project: project, target_project: project) }
before do
- allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.kilobytes)
+ allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.bytes)
visit(diffs_project_merge_request_path(project, merge_request))
@@ -15,7 +15,7 @@ RSpec.describe 'User expands diff', :js do
end
it 'allows user to expand diff' do
- page.within find('[id="19763941ab80e8c09871c0a425f0560d9053bcb3"]') do
+ page.within find("[id='4c76a1271e41072d7da9fe40bf0f79f7384d472a']") do
find('[data-testid="expand-button"]').click
wait_for_requests
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 3665ad91dd6..7d67cde4bbb 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,21 +10,19 @@ RSpec.describe 'Batch diffs', :js do
let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'empty-branch') }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit diffs_project_merge_request_path(merge_request.project, merge_request)
wait_for_requests
- # Add discussion to first line of first file
- click_diff_line(find('.diff-file.file-holder:first-of-type .line_holder .left-side:first-of-type'))
- page.within('.js-discussion-note-form') do
+ click_diff_line(get_first_diff.find('[data-testid="left-side"]', match: :first))
+ page.within get_first_diff.find('.js-discussion-note-form') do
fill_in('note_note', with: 'First Line Comment')
click_button('Add comment now')
end
- # Add discussion to first line of last file
- click_diff_line(find('.diff-file.file-holder:last-of-type .line_holder .left-side:first-of-type'))
- page.within('.js-discussion-note-form') do
+ click_diff_line(get_second_diff.find('[data-testid="left-side"]', match: :first))
+ page.within get_second_diff.find('.js-discussion-note-form') do
fill_in('note_note', with: 'Last Line Comment')
click_button('Add comment now')
end
@@ -36,17 +34,14 @@ RSpec.describe 'Batch diffs', :js do
# Reload so we know the discussions are persisting across batch loads
visit page.current_url
- # Wait for JS to settle
wait_for_requests
- expect(page).to have_selector('.diff-files-holder .file-holder', count: 39)
-
# Confirm discussions are applied to appropriate files (should be contained in multiple diff pages)
- page.within('.diff-file.file-holder:first-of-type .notes .timeline-entry .note .note-text') do
+ page.within get_first_diff.find('.notes .timeline-entry .note .note-text') do
expect(page).to have_content('First Line Comment')
end
- page.within('.diff-file.file-holder:last-of-type .notes .timeline-entry .note .note-text') do
+ page.within get_second_diff.find('.notes .timeline-entry .note .note-text') do
expect(page).to have_content('Last Line Comment')
end
end
@@ -54,7 +49,7 @@ RSpec.describe 'Batch diffs', :js do
context 'when user visits a URL with a link directly to to a discussion' do
context 'which is in the first batched page of diffs' do
it 'scrolls to the correct discussion' do
- page.within('.diff-file.file-holder:first-of-type') do
+ page.within get_first_diff do
click_link('just now')
end
@@ -63,15 +58,15 @@ RSpec.describe 'Batch diffs', :js do
wait_for_requests
# Confirm scrolled to correct UI element
- expect(page.find('.diff-file.file-holder:first-of-type .discussion-notes .timeline-entry li.note[id]').obscured?).to be_falsey
- expect(page.find('.diff-file.file-holder:last-of-type .discussion-notes .timeline-entry li.note[id]').obscured?).to be_truthy
+ expect(get_first_diff.find('.discussion-notes .timeline-entry li.note[id]').obscured?).to be_falsey
+ expect(get_second_diff.find('.discussion-notes .timeline-entry li.note[id]').obscured?).to be_truthy
end
end
context 'which is in at least page 2 of the batched pages of diffs' do
it 'scrolls to the correct discussion',
quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/293814' } do
- page.within('.diff-file.file-holder:last-of-type') do
+ page.within get_first_diff do
click_link('just now')
end
@@ -80,8 +75,8 @@ RSpec.describe 'Batch diffs', :js do
wait_for_requests
# Confirm scrolled to correct UI element
- expect(page.find('.diff-file.file-holder:first-of-type .discussion-notes .timeline-entry li.note[id]').obscured?).to be_truthy
- expect(page.find('.diff-file.file-holder:last-of-type .discussion-notes .timeline-entry li.note[id]').obscured?).to be_falsey
+ expect(get_first_diff.find('.discussion-notes .timeline-entry li.note[id]').obscured?).to be_truthy
+ expect(get_second_diff.find('.discussion-notes .timeline-entry li.note[id]').obscured?).to be_falsey
end
end
end
@@ -95,15 +90,21 @@ RSpec.describe 'Batch diffs', :js do
end
it 'has the correct discussions applied to files across batched pages' do
- expect(page).to have_selector('.diff-files-holder .file-holder', count: 39)
-
- page.within('.diff-file.file-holder:first-of-type .notes .timeline-entry .note .note-text') do
+ page.within get_first_diff.find('.notes .timeline-entry .note .note-text') do
expect(page).to have_content('First Line Comment')
end
- page.within('.diff-file.file-holder:last-of-type .notes .timeline-entry .note .note-text') do
+ page.within get_second_diff.find('.notes .timeline-entry .note .note-text') do
expect(page).to have_content('Last Line Comment')
end
end
end
+
+ def get_first_diff
+ find('#a9b6f940524f646951cc28d954aa41f814f95d4f')
+ end
+
+ def get_second_diff
+ find('#b285a86891571c7fdbf1f82e840816079de1cc8b')
+ end
end
diff --git a/spec/features/merge_request/user_merges_merge_request_spec.rb b/spec/features/merge_request/user_merges_merge_request_spec.rb
index 7758fa8e666..d1be93cae02 100644
--- a/spec/features/merge_request/user_merges_merge_request_spec.rb
+++ b/spec/features/merge_request/user_merges_merge_request_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe "User merges a merge request", :js do
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
index 8438c0af553..4d7ee11e366 100644
--- a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js do
wait_for_requests
expect(page).to have_css('button[disabled="disabled"]', text: 'Merge')
- expect(page).to have_content('The pipeline for this merge request did not complete. Push a new commit to fix the failure, or check the troubleshooting documentation to see other possible actions.')
+ expect(page).to have_content('Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or learn about other solutions.')
end
end
@@ -70,7 +70,7 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js do
wait_for_requests
expect(page).not_to have_button 'Merge'
- expect(page).to have_content('The pipeline for this merge request did not complete. Push a new commit to fix the failure, or check the troubleshooting documentation to see other possible actions.')
+ expect(page).to have_content('Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or learn about other solutions.')
end
end
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 9e314e18563..d803aec5895 100644
--- a/spec/features/merge_request/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb
@@ -29,54 +29,54 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
context 'with an old line on the left and no line on the right' do
it 'allows commenting on the left side' do
- should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_23_22"]'), 'left')
+ should_allow_commenting(find_by_scrolling('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_23_22"]'), 'left')
end
it 'does not allow commenting on the right side' do
- should_not_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_23_22"]').find(:xpath, '..'), 'right')
+ should_not_allow_commenting(find_by_scrolling('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_23_22"]').find(:xpath, '..'), 'right')
end
end
context 'with no line on the left and a new line on the right' do
it 'does not allow commenting on the left side' do
- should_not_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15"]').find(:xpath, '..'), 'left')
+ should_not_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15"]').find(:xpath, '..'), 'left')
end
it 'allows commenting on the right side' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15"]').find(:xpath, '..'), 'right')
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15"]').find(:xpath, '..'), 'right')
end
end
context 'with an old line on the left and a new line on the right' do
it 'allows commenting on the left side', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/199050' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"]').find(:xpath, '..'), 'left')
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"]').find(:xpath, '..'), 'left')
end
it 'allows commenting on the right side' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"]').find(:xpath, '..'), 'right')
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"]').find(:xpath, '..'), 'right')
end
end
context 'with an unchanged line on the left and an unchanged line on the right' do
it 'allows commenting on the left side', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/196826' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]', match: :first).find(:xpath, '..'), 'left')
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]', match: :first).find(:xpath, '..'), 'left')
end
it 'allows commenting on the right side' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]', match: :first).find(:xpath, '..'), 'right')
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]', match: :first).find(:xpath, '..'), 'right')
end
end
context 'with a match line' do
it 'does not allow commenting' do
- line_holder = find('.match', match: :first)
+ line_holder = find_by_scrolling('.match', match: :first)
match_should_not_allow_commenting(line_holder)
end
end
context 'with an unfolded line' do
before do
- page.within('.file-holder[id="a5cc2925ca8258af241be7e5b0381edf30266302"]') do
+ page.within find_by_scrolling('.file-holder[id="a5cc2925ca8258af241be7e5b0381edf30266302"]') do
find('.js-unfold', match: :first).click
end
@@ -84,12 +84,12 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
end
it 'allows commenting on the left side' do
- should_allow_commenting(first('#a5cc2925ca8258af241be7e5b0381edf30266302 .line_holder [data-testid="left-side"]'))
+ should_allow_commenting(find_by_scrolling('#a5cc2925ca8258af241be7e5b0381edf30266302').first('.line_holder [data-testid="left-side"]'))
end
it 'allows commenting on the right side' do
# Automatically shifts comment box to left side.
- should_allow_commenting(first('#a5cc2925ca8258af241be7e5b0381edf30266302 .line_holder [data-testid="right-side"]'))
+ should_allow_commenting(find_by_scrolling('#a5cc2925ca8258af241be7e5b0381edf30266302').first('.line_holder [data-testid="right-side"]'))
end
end
end
@@ -101,44 +101,44 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
context 'after deleteing a note' do
it 'allows commenting' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
- accept_confirm do
+ accept_gl_confirm(button_text: 'Delete Comment') do
first('button.more-actions-toggle').click
first('.js-note-delete').click
end
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
end
end
context 'with a new line' do
it 'allows commenting' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
end
end
context 'with an old line' do
it 'allows commenting' do
- should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
+ should_allow_commenting(find_by_scrolling('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
end
end
context 'with an unchanged line' do
it 'allows commenting' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
end
end
context 'with a match line' do
it 'does not allow commenting' do
- match_should_not_allow_commenting(find('.match', match: :first))
+ match_should_not_allow_commenting(find_by_scrolling('.match', match: :first))
end
end
context 'with an unfolded line' do
before do
- page.within('.file-holder[id="a5cc2925ca8258af241be7e5b0381edf30266302"]') do
+ page.within find_by_scrolling('.file-holder[id="a5cc2925ca8258af241be7e5b0381edf30266302"]') do
find('.js-unfold', match: :first).click
end
@@ -147,7 +147,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
# The first `.js-unfold` unfolds upwards, therefore the first
# `.line_holder` will be an unfolded line.
- let(:line_holder) { first('[id="a5cc2925ca8258af241be7e5b0381edf30266302_1_1"]') }
+ let(:line_holder) { find_by_scrolling('[id="a5cc2925ca8258af241be7e5b0381edf30266302_1_1"]') }
it 'allows commenting' do
should_allow_commenting line_holder
@@ -157,7 +157,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
context 'when hovering over a diff discussion' do
before do
visit diffs_project_merge_request_path(project, merge_request, view: 'inline')
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
visit project_merge_request_path(project, merge_request)
end
@@ -174,7 +174,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
context 'with a new line' do
it 'allows dismissing a comment' do
- should_allow_dismissing_a_comment(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
+ should_allow_dismissing_a_comment(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
end
end
end
@@ -182,13 +182,13 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
describe 'with multiple note forms' do
before do
visit diffs_project_merge_request_path(project, merge_request, view: 'inline')
- click_diff_line(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
- click_diff_line(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
+ click_diff_line(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
+ click_diff_line(find_by_scrolling('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
end
describe 'posting a note' do
it 'adds as discussion' do
- should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'), asset_form_reset: false)
+ should_allow_commenting(find_by_scrolling('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'), asset_form_reset: false)
expect(page).to have_css('.notes_holder .note.note-discussion', count: 1)
expect(page).to have_field('Replyโ€ฆ')
end
@@ -203,25 +203,25 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
context 'with a new line' do
it 'allows commenting' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
end
end
context 'with an old line' do
it 'allows commenting' do
- should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
+ should_allow_commenting(find_by_scrolling('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
end
end
context 'with an unchanged line' do
it 'allows commenting' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
+ should_allow_commenting(find_by_scrolling('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
end
end
context 'with a match line' do
it 'does not allow commenting' do
- match_should_not_allow_commenting(find('.match', match: :first))
+ match_should_not_allow_commenting(find_by_scrolling('.match', match: :first))
end
end
end
diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb
index 0416474218f..1779567624c 100644
--- a/spec/features/merge_request/user_posts_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_notes_spec.rb
@@ -133,7 +133,7 @@ RSpec.describe 'Merge request > User posts notes', :js do
describe 'when previewing a note' do
it 'shows the toolbar buttons when editing a note' do
page.within('.js-main-target-form') do
- expect(page).to have_css('.md-header-toolbar.active')
+ expect(page).to have_css('.md-header-toolbar')
end
end
@@ -141,7 +141,7 @@ RSpec.describe 'Merge request > User posts notes', :js do
wait_for_requests
find('.js-md-preview-button').click
page.within('.js-main-target-form') do
- expect(page).not_to have_css('.md-header-toolbar.active')
+ expect(page).not_to have_css('.md-header-toolbar')
end
end
end
@@ -165,11 +165,13 @@ RSpec.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('[data-testid="cancel"]').click
+ end
- accept_confirm do
- find('[data-testid="cancel"]').click
- end
+ page.within('.modal') do
+ click_button('OK', match: :first)
end
+
expect(find('.js-note-text').text).to eq ''
end
diff --git a/spec/features/merge_request/user_rebases_merge_request_spec.rb b/spec/features/merge_request/user_rebases_merge_request_spec.rb
index a3f72a6266b..d42864200ec 100644
--- a/spec/features/merge_request/user_rebases_merge_request_spec.rb
+++ b/spec/features/merge_request/user_rebases_merge_request_spec.rb
@@ -4,7 +4,7 @@ require "spec_helper"
RSpec.describe "User rebases a merge request", :js do
let(:merge_request) { create(:merge_request, :simple, source_project: project) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/merge_request/user_resolves_wip_mr_spec.rb b/spec/features/merge_request/user_resolves_wip_mr_spec.rb
index fd405855cf8..92927b713f1 100644
--- a/spec/features/merge_request/user_resolves_wip_mr_spec.rb
+++ b/spec/features/merge_request/user_resolves_wip_mr_spec.rb
@@ -2,13 +2,13 @@
require 'spec_helper'
-RSpec.describe 'Merge request > User resolves Work in Progress', :js do
+RSpec.describe 'Merge request > User resolves Draft', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) do
create(:merge_request_with_diffs, source_project: project,
author: user,
- title: 'WIP: Bug NS-04',
+ title: 'Draft: Bug NS-04',
merge_params: { force_remove_source_branch: '1' })
end
diff --git a/spec/features/merge_request/user_reviews_image_spec.rb b/spec/features/merge_request/user_reviews_image_spec.rb
index 533f3c9c91a..bd490294829 100644
--- a/spec/features/merge_request/user_reviews_image_spec.rb
+++ b/spec/features/merge_request/user_reviews_image_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Merge request > image review', :js do
include MergeRequestDiffHelpers
include RepoHelpers
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, author: user) }
diff --git a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb
index 64cd5aa2bb1..33c5a936b8d 100644
--- a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb
@@ -1,9 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
+include Spec::Support::Helpers::ModalHelpers # rubocop:disable Style/MixinUsage
RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
include NoteInteractionHelpers
+ include Spec::Support::Helpers::ModalHelpers
+ include MergeRequestDiffHelpers
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
@@ -121,8 +124,8 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
it 'removes avatar when note is deleted' do
open_more_actions_dropdown(note)
- page.within find(".note-row-#{note.id}") do
- accept_confirm { find('.js-note-delete').click }
+ accept_gl_confirm(button_text: 'Delete Comment') do
+ find(".note-row-#{note.id} .js-note-delete").click
end
wait_for_requests
@@ -133,6 +136,7 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
end
it 'adds avatar when commenting' do
+ find_by_scrolling('[data-discussion-id]', match: :first)
find_field('Replyโ€ฆ', match: :first).click
page.within '.js-discussion-note-form' do
@@ -152,6 +156,7 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
it 'adds multiple comments' do
3.times do
+ find_by_scrolling('[data-discussion-id]', match: :first)
find_field('Replyโ€ฆ', match: :first).click
page.within '.js-discussion-note-form' do
@@ -190,7 +195,7 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do
end
def find_line(line_code)
- line = find("[id='#{line_code}']")
+ line = find_by_scrolling("[id='#{line_code}']")
line = line.find(:xpath, 'preceding-sibling::*[1][self::td]/preceding-sibling::*[1][self::td]') if line.tag_name == 'td'
line
end
diff --git a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
index 7c93952ee99..dc50c3bc8db 100644
--- a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
+++ b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Merge request > User sees deleted target branch', :js do
end
it 'shows a message about missing target branch' do
- expect(page).to have_content('Target branch does not exist')
+ expect(page).to have_content('The target branch feature does not exist')
end
it 'does not show link to target branch' do
diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
index 345404cc28f..01cc58777ba 100644
--- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Merge request > User sees deployment widget', :js do
+ include Spec::Support::Helpers::ModalHelpers
+
describe 'when merge request has associated environments' do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
@@ -118,7 +120,9 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
end
it 'does start build when stop button clicked' do
- accept_confirm { find('.js-stop-env').click }
+ accept_gl_confirm(button_text: 'Stop environment') do
+ find('.js-stop-env').click
+ end
expect(page).to have_content('close_app')
end
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index a7713ed9964..7cd9ef80874 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe 'Merge request > User sees diff', :js do
include ProjectForksHelper
include RepoHelpers
+ include MergeRequestDiffHelpers
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
@@ -58,12 +59,12 @@ RSpec.describe 'Merge request > User sees diff', :js do
let(:changelog_id) { Digest::SHA1.hexdigest("CHANGELOG") }
context 'as author' do
- it 'shows direct edit link', :sidekiq_might_not_need_inline do
+ it 'contains direct edit link', :sidekiq_might_not_need_inline do
sign_in(author_user)
visit diffs_project_merge_request_path(project, merge_request)
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
- expect(page).to have_selector("[id=\"#{changelog_id}\"] .js-edit-blob", visible: false)
+ expect(page).to have_selector(".js-edit-blob", visible: false)
end
end
@@ -72,6 +73,8 @@ RSpec.describe 'Merge request > User sees diff', :js do
sign_in(user)
visit diffs_project_merge_request_path(project, merge_request)
+ find_by_scrolling("[id=\"#{changelog_id}\"]")
+
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
find("[id=\"#{changelog_id}\"] .js-diff-more-actions").click
find("[id=\"#{changelog_id}\"] .js-edit-blob").click
@@ -82,7 +85,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
end
context 'when file contains html' do
- let(:current_user) { project.owner }
+ let(:current_user) { project.first_owner }
let(:branch_name) {"test_branch"}
it 'escapes any HTML special characters in the diff chunk header' do
@@ -107,6 +110,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
CONTENT
file_name = 'xss_file.rs'
+ file_hash = Digest::SHA1.hexdigest(file_name)
create_file('master', file_name, file_content)
merge_request = create(:merge_request, source_project: project)
@@ -116,6 +120,8 @@ RSpec.describe 'Merge request > User sees diff', :js do
visit diffs_project_merge_request_path(project, merge_request)
+ find_by_scrolling("[id='#{file_hash}']")
+
expect(page).to have_text("function foo<input> {")
expect(page).to have_css(".line[lang='rust'] .k")
end
@@ -123,7 +129,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
context 'when file is stored in LFS' do
let(:merge_request) { create(:merge_request, source_project: project) }
- let(:current_user) { project.owner }
+ let(:current_user) { project.first_owner }
context 'when LFS is enabled on the project' do
before do
@@ -136,7 +142,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
end
context 'when file is an image', :js do
- let(:file_name) { 'files/lfs/image.png' }
+ let(:file_name) { 'a/image.png' }
it 'shows an error message' do
expect(page).not_to have_content('could not be displayed because it is stored in LFS')
@@ -144,7 +150,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
end
context 'when file is not an image' do
- let(:file_name) { 'files/lfs/ruby.rb' }
+ let(:file_name) { 'a/ruby.rb' }
it 'shows an error message' do
expect(page).to have_content('This source diff could not be displayed because it is stored in LFS')
@@ -153,7 +159,14 @@ RSpec.describe 'Merge request > User sees diff', :js do
end
context 'when LFS is not enabled' do
+ let(:file_name) { 'a/lfs_object.iso' }
+
before do
+ allow(Gitlab.config.lfs).to receive(:disabled).and_return(true)
+ project.update_attribute(:lfs_enabled, false)
+
+ create_file('master', file_name, project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data)
+
visit diffs_project_merge_request_path(project, merge_request)
end
diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
index 2a49109d360..b77b3d69fc1 100644
--- a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
@@ -64,7 +64,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-created', count: 2)
- expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{detached_merge_request_pipeline.id}")
+ expect(first('[data-testid="pipeline-identifier"]')).to have_content("##{detached_merge_request_pipeline.id}")
end
end
@@ -101,16 +101,16 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 4)
- expect(all('[data-testid="pipeline-url-link"]')[0])
+ expect(all('[data-testid="pipeline-identifier"]')[0])
.to have_content("##{detached_merge_request_pipeline_2.id}")
- expect(all('[data-testid="pipeline-url-link"]')[1])
+ expect(all('[data-testid="pipeline-identifier"]')[1])
.to have_content("##{detached_merge_request_pipeline.id}")
- expect(all('[data-testid="pipeline-url-link"]')[2])
+ expect(all('[data-testid="pipeline-identifier"]')[2])
.to have_content("##{push_pipeline_2.id}")
- expect(all('[data-testid="pipeline-url-link"]')[3])
+ expect(all('[data-testid="pipeline-identifier"]')[3])
.to have_content("##{push_pipeline.id}")
end
end
@@ -201,7 +201,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
it 'sees a branch pipeline in pipeline tab' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-created', count: 1)
- expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{push_pipeline.id}")
+ expect(first('[data-testid="pipeline-identifier"]')).to have_content("##{push_pipeline.id}")
end
end
@@ -252,7 +252,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 2)
- expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{detached_merge_request_pipeline.id}")
+ expect(first('[data-testid="pipeline-identifier"]')).to have_content("##{detached_merge_request_pipeline.id}")
end
end
@@ -295,16 +295,16 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 4)
- expect(all('[data-testid="pipeline-url-link"]')[0])
+ expect(all('[data-testid="pipeline-identifier"]')[0])
.to have_content("##{detached_merge_request_pipeline_2.id}")
- expect(all('[data-testid="pipeline-url-link"]')[1])
+ expect(all('[data-testid="pipeline-identifier"]')[1])
.to have_content("##{detached_merge_request_pipeline.id}")
- expect(all('[data-testid="pipeline-url-link"]')[2])
+ expect(all('[data-testid="pipeline-identifier"]')[2])
.to have_content("##{push_pipeline_2.id}")
- expect(all('[data-testid="pipeline-url-link"]')[3])
+ expect(all('[data-testid="pipeline-identifier"]')[3])
.to have_content("##{push_pipeline.id}")
end
end
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index 8761ee89463..872507c3b7a 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -104,10 +104,11 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
visit project_merge_request_path(project, merge_request)
end
- it 'has danger button while waiting for external CI status' do
+ it 'has merge button with confirm variant while waiting for external CI status' do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
- expect(page).to have_selector('.accept-merge-request.btn-danger')
+
+ expect(page).to have_selector('.accept-merge-request.btn-confirm')
end
end
@@ -125,10 +126,27 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
visit project_merge_request_path(project, merge_request)
end
- it 'has danger button when not succeeded' do
+ it 'has merge button that shows modal when pipeline does not succeeded' do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
- expect(page).to have_selector('.accept-merge-request.btn-danger')
+
+ click_button 'Merge...'
+
+ expect(page).to have_selector('[data-testid="merge-failed-pipeline-confirmation-dialog"]', visible: true)
+ end
+
+ it 'allows me to merge with a failed pipeline' do
+ modal_selector = '[data-testid="merge-failed-pipeline-confirmation-dialog"]'
+
+ wait_for_requests
+
+ click_button 'Merge...'
+
+ page.within(modal_selector) do
+ click_button 'Merge unverified changes'
+ end
+
+ expect(find('.media-body h4')).to have_content('Merging!')
end
end
diff --git a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb
index e997fb3e853..39bba3f2f73 100644
--- a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb
+++ b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'Merge request > User sees MR with deleted source branch', :js do
end
it 'shows a message about missing source branch' do
- expect(page).to have_content('Source branch does not exist.')
+ expect(page).to have_content('The source branch this-branch-does-not-exist does not exist.')
end
it 'still contains Discussion, Commits and Changes tabs' do
@@ -27,7 +27,7 @@ RSpec.describe 'Merge request > User sees MR with deleted source branch', :js do
expect(page).to have_content('Changes')
end
- expect(page).to have_content('Source branch does not exist.')
+ expect(page).to have_content('The source branch this-branch-does-not-exist does not exist.')
click_on 'Changes'
wait_for_requests
diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb
index 4967f58528e..a356dd50898 100644
--- a/spec/features/merge_request/user_sees_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_spec.rb
@@ -125,6 +125,7 @@ RSpec.describe 'Merge request > User sees pipelines', :js do
before do
stub_feature_flags(ci_disallow_to_create_merge_request_pipelines_in_target_project: false)
+ stub_feature_flags(rearrange_pipelines_table: false)
end
it 'creates a pipeline in the parent project when user proceeds with the warning' do
@@ -133,7 +134,7 @@ RSpec.describe 'Merge request > User sees pipelines', :js do
create_merge_request_pipeline
act_on_security_warning(action: 'Run pipeline')
- check_pipeline(expected_project: parent_project)
+ check_pipeline(expected_project: parent_project, link_selector: 'pipeline-url-link')
check_head_pipeline(expected_project: parent_project)
end
@@ -178,13 +179,13 @@ RSpec.describe 'Merge request > User sees pipelines', :js do
click_button('Run pipeline')
end
- def check_pipeline(expected_project:)
+ def check_pipeline(expected_project:, link_selector: 'commit-title')
page.within('.ci-table') do
expect(page).to have_selector('.commit', count: 2)
page.within(first('.commit')) do
page.within('.pipeline-tags') do
- expect(page.find('[data-testid="pipeline-url-link"]')[:href]).to include(expected_project.full_path)
+ expect(page.find("[data-testid=#{link_selector}]")[:href]).to include(expected_project.full_path)
expect(page).to have_content('detached')
end
page.within('.pipeline-triggerer') do
diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb
index 5abf4e2f5ad..2b856811e02 100644
--- a/spec/features/merge_request/user_sees_versions_spec.rb
+++ b/spec/features/merge_request/user_sees_versions_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Merge request > User sees versions', :js do
+ include MergeRequestDiffHelpers
+
let(:merge_request) do
create(:merge_request).tap do |mr|
mr.merge_request_diff.destroy!
@@ -27,8 +29,12 @@ RSpec.describe 'Merge request > User sees versions', :js do
diff_file_selector = ".diff-file[id='#{file_id}']"
line_code = "#{file_id}_#{line_code}"
- page.within(diff_file_selector) do
- first("[id='#{line_code}']").hover
+ page.within find_by_scrolling(diff_file_selector) do
+ line_code_element = first("[id='#{line_code}']")
+ # scrolling to element's bottom is required in order for .hover action to work
+ # otherwise, the element could be hidden underneath a sticky header
+ scroll_to_elements_bottom(line_code_element)
+ line_code_element.hover
first("[id='#{line_code}'] [role='button']").click
page.within("form[data-line-code='#{line_code}']") do
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index 690a292937a..beb658bb7a0 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe 'User comments on a diff', :js do
context 'single suggestion note' do
it 'hides suggestion popover' do
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
expect(page).to have_selector('.diff-suggest-popover')
@@ -46,7 +46,7 @@ RSpec.describe 'User comments on a diff', :js do
end
it 'suggestion is presented' do
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
page.within('.js-discussion-note-form') do
fill_in('note_note', with: "```suggestion\n# change to a comment\n```")
@@ -74,7 +74,7 @@ RSpec.describe 'User comments on a diff', :js do
end
it 'allows suggestions in replies' do
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
page.within('.js-discussion-note-form') do
fill_in('note_note', with: "```suggestion\n# change to a comment\n```")
@@ -91,7 +91,7 @@ RSpec.describe 'User comments on a diff', :js do
end
it 'suggestion is appliable' do
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
page.within('.js-discussion-note-form') do
fill_in('note_note', with: "```suggestion\n# change to a comment\n```")
@@ -273,7 +273,7 @@ RSpec.describe 'User comments on a diff', :js do
context 'multiple suggestions in a single note' do
it 'suggestions are presented', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/258989' do
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
page.within('.js-discussion-note-form') do
fill_in('note_note', with: "```suggestion\n# change to a comment\n```\n```suggestion:-2\n# or that\n# heh\n```")
@@ -316,7 +316,7 @@ RSpec.describe 'User comments on a diff', :js do
context 'multi-line suggestions' do
before do
- click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
page.within('.js-discussion-note-form') do
fill_in('note_note', with: "```suggestion:-3+5\n# change to a\n# comment\n# with\n# broken\n# lines\n```")
diff --git a/spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb b/spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb
index 370341a43f9..e3272a6e280 100644
--- a/spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb
+++ b/spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'User views merged merge request from deleted fork' do
let(:project) { create(:project, :repository) }
let(:source_project) { fork_project(project, nil, repository: true) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let!(:merge_request) { create(:merge_request, :merged, source_project: source_project, target_project: project) }
before do
diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb
index b5a973a53c0..a145bcb976b 100644
--- a/spec/features/merge_request/user_views_open_merge_request_spec.rb
+++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb
@@ -128,4 +128,30 @@ RSpec.describe 'User views an open merge request' do
expect(find("[data-testid='ref-name']")[:title]).to eq(source_branch)
end
end
+
+ context 'when user preferred language has changed', :use_clean_rails_memory_store_fragment_caching do
+ let(:project) { create(:project, :public, :repository) }
+ let(:user) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ it 'renders edit button in preferred language' do
+ visit(merge_request_path(merge_request))
+
+ page.within('.detail-page-header-actions') do
+ expect(page).to have_link('Edit')
+ end
+
+ user.update!(preferred_language: 'de')
+
+ visit(merge_request_path(merge_request))
+
+ page.within('.detail-page-header-actions') do
+ expect(page).to have_link('Bearbeiten')
+ end
+ end
+ end
end
diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb
index 46c12784ea8..f781ba0827c 100644
--- a/spec/features/merge_requests/user_mass_updates_spec.rb
+++ b/spec/features/merge_requests/user_mass_updates_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'Merge requests > User mass updates', :js do
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
before do
+ stub_feature_flags(mr_attention_requests: false)
+
project.add_maintainer(user)
sign_in(user)
end
@@ -59,6 +61,18 @@ RSpec.describe 'Merge requests > User mass updates', :js do
expect(find('.merge-request')).to have_link "Assigned to #{user.name}"
end
+
+ describe 'with attention requests feature flag on' do
+ before do
+ stub_feature_flags(mr_attention_requests: true)
+ end
+
+ it 'updates merge request with assignee' do
+ change_assignee(user.name)
+
+ expect(find('.issuable-meta a.author-link')[:title]).to eq "Attention requested from assignee #{user.name}, go to their profile."
+ end
+ end
end
describe 'remove assignee' do
diff --git a/spec/features/monitor_sidebar_link_spec.rb b/spec/features/monitor_sidebar_link_spec.rb
index bb5e581a034..fcef0fa0eff 100644
--- a/spec/features/monitor_sidebar_link_spec.rb
+++ b/spec/features/monitor_sidebar_link_spec.rb
@@ -117,9 +117,8 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures do
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
expect(page).to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).to have_link('Logs', href: project_logs_path(project))
-
- expect(page).not_to have_link('Serverless', href: project_serverless_functions_path(project))
- expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
+ expect(page).to have_link('Serverless', href: project_serverless_functions_path(project))
+ expect(page).to have_link('Kubernetes', href: project_clusters_path(project))
end
it_behaves_like 'shows Monitor menu based on the access level'
diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb
index cc805e7d369..b2739454b52 100644
--- a/spec/features/participants_autocomplete_spec.rb
+++ b/spec/features/participants_autocomplete_spec.rb
@@ -33,31 +33,12 @@ RSpec.describe 'Member autocomplete', :js do
let(:noteable) { create(:issue, author: author, project: project) }
before do
- stub_feature_flags(tribute_autocomplete: false)
visit project_issue_path(project, noteable)
end
include_examples "open suggestions when typing @", 'issue'
end
- describe 'when tribute_autocomplete feature flag is on' do
- context 'adding a new note on a Issue' do
- let(:noteable) { create(:issue, author: author, project: project) }
-
- before do
- stub_feature_flags(tribute_autocomplete: true)
- visit project_issue_path(project, noteable)
-
- fill_in 'Comment', with: '@'
- end
-
- it 'suggests noteable author and note author' do
- expect(find_tribute_autocomplete_menu).to have_content(author.username)
- expect(find_tribute_autocomplete_menu).to have_content(note.author.username)
- end
- end
- end
-
context 'adding a new note on a Merge Request' do
let(:noteable) do
create(:merge_request, source_project: project,
@@ -91,8 +72,4 @@ RSpec.describe 'Member autocomplete', :js do
def find_autocomplete_menu
find('.atwho-view ul', visible: true)
end
-
- def find_tribute_autocomplete_menu
- find('.tribute-container ul', visible: true)
- end
end
diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb
index b9e59a0239b..fde85a731a1 100644
--- a/spec/features/profiles/keys_spec.rb
+++ b/spec/features/profiles/keys_spec.rb
@@ -49,7 +49,12 @@ RSpec.describe 'Profile > SSH Keys' do
context 'when only DSA and ECDSA keys are allowed' do
before do
forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE
- stub_application_setting(rsa_key_restriction: forbidden, ed25519_key_restriction: forbidden)
+ stub_application_setting(
+ rsa_key_restriction: forbidden,
+ ed25519_key_restriction: forbidden,
+ ecdsa_sk_key_restriction: forbidden,
+ ed25519_sk_key_restriction: forbidden
+ )
end
it 'shows a validation error' do
diff --git a/spec/features/profiles/password_spec.rb b/spec/features/profiles/password_spec.rb
index 25fe43617fd..898e2c2aa59 100644
--- a/spec/features/profiles/password_spec.rb
+++ b/spec/features/profiles/password_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe 'Profile > Password' do
it 'shows a success message' do
fill_passwords(Gitlab::Password.test_default, Gitlab::Password.test_default)
- page.within('.flash-notice') do
+ page.within('[data-testid="alert-info"]') do
expect(page).to have_content('Password was successfully updated. Please sign in again.')
end
end
diff --git a/spec/features/projects/active_tabs_spec.rb b/spec/features/projects/active_tabs_spec.rb
index b8c928004ed..2601dcf55c9 100644
--- a/spec/features/projects/active_tabs_spec.rb
+++ b/spec/features/projects/active_tabs_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Project active tab' do
let_it_be(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/activity/rss_spec.rb b/spec/features/projects/activity/rss_spec.rb
index 9012b335bf4..a3e511b5c22 100644
--- a/spec/features/projects/activity/rss_spec.rb
+++ b/spec/features/projects/activity/rss_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Project Activity RSS' do
let(:project) { create(:project, :public) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:path) { activity_project_path(project) }
before do
@@ -13,7 +13,7 @@ RSpec.describe 'Project Activity RSS' do
context 'when signed in' do
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit path
end
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 62994d19fc0..77194fd6ca1 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -29,443 +29,421 @@ RSpec.describe 'File blob', :js do
).execute
end
- before do
- stub_feature_flags(refactor_blob_viewer: false) # This stub will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/350455
- end
-
- context 'Ruby file' do
- before do
- visit_blob('files/ruby/popen.rb')
-
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows highlighted Ruby code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("require 'fileutils'")
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
- end
- end
-
- it 'displays file actions on all screen sizes' do
- file_actions_selector = '.file-actions'
-
- resize_screen_sm
- expect(page).to have_selector(file_actions_selector, visible: true)
-
- resize_screen_xs
- expect(page).to have_selector(file_actions_selector, visible: true)
- end
- end
-
- context 'Markdown file' do
- context 'visiting directly' do
+ context 'with refactor_blob_viewer feature flag enabled' do
+ context 'Ruby file' do
before do
- visit_blob('files/markdown/ruby-style-guide.md')
+ visit_blob('files/ruby/popen.rb')
wait_for_requests
end
- it 'displays the blob using the rich viewer' do
+ it 'displays the blob' do
aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
-
- # shows rendered Markdown
- expect(page).to have_link("PEP-8")
+ # shows highlighted Ruby code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("require 'fileutils'")
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# shows a raw button
expect(page).to have_link('Open raw')
end
end
- context 'switching to the simple viewer' do
+ it 'displays file actions on all screen sizes' do
+ file_actions_selector = '.file-actions'
+
+ resize_screen_sm
+ expect(page).to have_selector(file_actions_selector, visible: true)
+
+ resize_screen_xs
+ expect(page).to have_selector(file_actions_selector, visible: true)
+ end
+ end
+
+ context 'Markdown file' do
+ context 'visiting directly' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
+ visit_blob('files/markdown/ruby-style-guide.md')
wait_for_requests
end
- it 'displays the blob using the simple viewer' do
+ it 'displays the blob using the rich viewer' do
aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
- # shows highlighted Markdown code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+ # shows rendered Markdown
+ expect(page).to have_link("PEP-8")
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # shows a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
- context 'switching to the rich viewer again' do
+ context 'switching to the simple viewer' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+ find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
wait_for_requests
end
- it 'displays the blob using the rich viewer' do
+ it 'displays the blob using the simple viewer' do
aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows highlighted Markdown code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
end
end
- end
- end
- end
- context 'when ref switch' do
- def switch_ref_to(ref_name)
- first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
-
- page.within '.project-refs-form' do
- click_link ref_name
- wait_for_requests
- end
- end
+ context 'switching to the rich viewer again' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
- it 'displays single highlighted line number of different ref' do
- visit_blob('files/js/application.js', anchor: 'L1')
+ wait_for_requests
+ end
- switch_ref_to('feature')
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
- page.within '.blob-content' do
- expect(find_by_id('LC1')[:class]).to include("hll")
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ end
+ end
+ end
end
end
- it 'displays multiple highlighted line numbers of different ref' do
- visit_blob('files/js/application.js', anchor: 'L1-3')
+ context 'when ref switch' do
+ def switch_ref_to(ref_name)
+ first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
- switch_ref_to('feature')
-
- page.within '.blob-content' do
- expect(find_by_id('LC1')[:class]).to include("hll")
- expect(find_by_id('LC2')[:class]).to include("hll")
- expect(find_by_id('LC3')[:class]).to include("hll")
+ page.within '.project-refs-form' do
+ click_link ref_name
+ wait_for_requests
+ end
end
- end
- it 'displays no highlighted number of different ref' do
- Files::UpdateService.new(
- project,
- project.owner,
- commit_message: 'Update',
- start_branch: 'feature',
- branch_name: 'feature',
- file_path: 'files/js/application.js',
- file_content: 'new content'
- ).execute
+ it 'displays no highlighted number of different ref' do
+ Files::UpdateService.new(
+ project,
+ project.first_owner,
+ commit_message: 'Update',
+ start_branch: 'feature',
+ branch_name: 'feature',
+ file_path: 'files/js/application.js',
+ file_content: 'new content'
+ ).execute
- project.commit('feature').diffs.diff_files.first
+ project.commit('feature').diffs.diff_files.first
- visit_blob('files/js/application.js', anchor: 'L3')
- switch_ref_to('feature')
+ visit_blob('files/js/application.js', anchor: 'L3')
+ switch_ref_to('feature')
- page.within '.blob-content' do
- expect(page).not_to have_css('.hll')
+ page.within '.blob-content' do
+ expect(page).not_to have_css('.hll')
+ end
end
- end
- context 'successfully change ref of similar name' do
- before do
- project.repository.create_branch('dev')
- project.repository.create_branch('development')
- end
+ context 'successfully change ref of similar name' do
+ before do
+ project.repository.create_branch('dev')
+ project.repository.create_branch('development')
+ end
- it 'switch ref from longer to shorter ref name' do
- visit_blob('files/js/application.js', ref: 'development')
- switch_ref_to('dev')
+ it 'switch ref from longer to shorter ref name' do
+ visit_blob('files/js/application.js', ref: 'development')
+ switch_ref_to('dev')
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
end
- end
- it 'switch ref from shorter to longer ref name' do
- visit_blob('files/js/application.js', ref: 'dev')
- switch_ref_to('development')
+ it 'switch ref from shorter to longer ref name' do
+ visit_blob('files/js/application.js', ref: 'dev')
+ switch_ref_to('development')
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
end
end
- end
- it 'successfully changes ref when the ref name matches the project name' do
- project.repository.create_branch(project.name)
+ it 'successfully changes ref when the ref name matches the project name' do
+ project.repository.create_branch(project.name)
- visit_blob('files/js/application.js', ref: project.name)
- switch_ref_to('master')
+ visit_blob('files/js/application.js', ref: project.name)
+ switch_ref_to('master')
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
end
end
end
- context 'visiting with a line number anchor' do
+ context 'Markdown rendering' do
before do
- visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
- end
+ project.add_maintainer(project.creator)
- it 'displays the blob using the simple viewer' do
- aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add RedCarpet and CommonMark Markdown ",
+ file_path: 'files/commonmark/file.md',
+ file_content: "1. one\n - sublist\n"
+ ).execute
+ end
- # highlights the line in question
- expect(page).to have_selector('#LC1.hll')
+ context 'when rendering default markdown' do
+ before do
+ visit_blob('files/commonmark/file.md')
- # shows highlighted Markdown code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+ wait_for_requests
+ end
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ it 'renders using CommonMark' do
+ aggregate_failures do
+ expect(page).to have_content("sublist")
+ expect(page).not_to have_xpath("//ol//li//ul")
+ end
end
end
end
- end
-
- context 'Markdown rendering' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add RedCarpet and CommonMark Markdown ",
- file_path: 'files/commonmark/file.md',
- file_content: "1. one\n - sublist\n"
- ).execute
- end
- context 'when rendering default markdown' do
+ context 'Markdown file (stored in LFS)' do
before do
- visit_blob('files/commonmark/file.md')
-
- wait_for_requests
- end
+ project.add_maintainer(project.creator)
- it 'renders using CommonMark' do
- aggregate_failures do
- expect(page).to have_content("sublist")
- expect(page).not_to have_xpath("//ol//li//ul")
- end
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add Markdown in LFS",
+ file_path: 'files/lfs/file.md',
+ file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data
+ ).execute
end
- end
- end
- context 'Markdown file (stored in LFS)' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add Markdown in LFS",
- file_path: 'files/lfs/file.md',
- file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data
- ).execute
- end
-
- context 'when LFS is enabled on the project' do
- before do
- allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
- project.update_attribute(:lfs_enabled, true)
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
- visit_blob('files/lfs/file.md')
+ visit_blob('files/lfs/file.md')
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'displays an error' do
- aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+ it 'displays an error' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
- # shows an error message
- expect(page).to have_content('The rendered file could not be displayed because it is stored in LFS. You can download it instead.')
+ # shows an error message
+ expect(page).to have_content('This content could not be displayed because it is stored in LFS. You can download it instead.')
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
end
end
- context 'switching to the simple viewer' do
+ context 'when LFS is disabled on the project' do
before do
- find('.js-blob-viewer-switcher .js-blob-viewer-switch-btn[data-viewer=simple]').click
+ visit_blob('files/lfs/file.md')
wait_for_requests
end
- it 'displays an error' do
+ it 'displays the blob' do
aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ # shows text
+ expect(page).to have_content('size 1575078')
- # shows an error message
- expect(page).to have_content('The source could not be displayed because it is stored in LFS. You can download it instead.')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
end
end
- context 'when LFS is disabled on the project' do
+ context 'PDF file' do
before do
- visit_blob('files/lfs/file.md')
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add PDF",
+ file_path: 'files/test.pdf',
+ file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data
+ ).execute
+
+ visit_blob('files/test.pdf')
wait_for_requests
end
it 'displays the blob' do
aggregate_failures do
- # shows text
- expect(page).to have_content('size 1575078')
+ # shows rendered PDF
+ expect(page).to have_selector('.js-pdf-viewer')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
- # shows a raw button
- expect(page).to have_link('Open raw')
+ # shows a download button
+ expect(page).to have_link('Download')
end
end
end
- end
- context 'PDF file' do
- before do
- project.add_maintainer(project.creator)
+ context 'Jupiter Notebook file' do
+ before do
+ project.add_maintainer(project.creator)
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add PDF",
- file_path: 'files/test.pdf',
- file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data
- ).execute
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add Jupiter Notebook",
+ file_path: 'files/basic.ipynb',
+ file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data
+ ).execute
- visit_blob('files/test.pdf')
+ visit_blob('files/basic.ipynb')
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'displays the blob' do
- aggregate_failures do
- # shows rendered PDF
- expect(page).to have_selector('.js-pdf-viewer')
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows rendered notebook
+ expect(page).to have_selector('.js-notebook-viewer-mounted')
+
+ # does show a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # show a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ # shows a raw button
+ expect(page).to have_link('Open raw')
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ # shows a download button
+ expect(page).to have_link('Download')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows the rendered notebook
+ expect(page).to have_content('test')
+ end
end
end
- end
- context 'Jupiter Notebook file' do
- before do
- project.add_maintainer(project.creator)
+ context 'ISO file (stored in LFS)' do
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add Jupiter Notebook",
- file_path: 'files/basic.ipynb',
- file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data
- ).execute
+ visit_blob('files/lfs/lfs_object.iso')
- visit_blob('files/basic.ipynb')
+ wait_for_requests
+ end
- wait_for_requests
- end
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows a download link
+ expect(page).to have_link('Download (1.50 MiB)')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
- it 'displays the blob' do
- aggregate_failures do
- # shows rendered notebook
- expect(page).to have_selector('.js-notebook-viewer-mounted')
+ context 'when LFS is disabled on the project' do
+ before do
+ visit_blob('files/lfs/lfs_object.iso')
- # does show a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
+ wait_for_requests
+ end
- # show a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows text
+ expect(page).to have_content('size 1575078')
- # shows a raw button
- expect(page).to have_link('Open raw')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- # shows the rendered notebook
- expect(page).to have_content('test')
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+ end
+ end
end
end
- end
- context 'ISO file (stored in LFS)' do
- context 'when LFS is enabled on the project' do
+ context 'ZIP file' do
before do
- allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
- project.update_attribute(:lfs_enabled, true)
-
- visit_blob('files/lfs/lfs_object.iso')
+ visit_blob('Gemfile.zip')
wait_for_requests
end
@@ -473,7 +451,7 @@ RSpec.describe 'File blob', :js do
it 'displays the blob' do
aggregate_failures do
# shows a download link
- expect(page).to have_link('Download (1.5 MB)')
+ expect(page).to have_link('Download (2.11 KiB)')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
@@ -487,578 +465,703 @@ RSpec.describe 'File blob', :js do
end
end
- context 'when LFS is disabled on the project' do
+ context 'empty file' do
before do
- visit_blob('files/lfs/lfs_object.iso')
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add empty file",
+ file_path: 'files/empty.md',
+ file_content: ''
+ ).execute
+
+ visit_blob('files/empty.md')
wait_for_requests
end
- it 'displays the blob' do
+ it 'displays an error' do
aggregate_failures do
- # shows text
- expect(page).to have_content('size 1575078')
+ # shows an error message
+ expect(page).to have_content('Empty file')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
- # shows a raw button
- expect(page).to have_link('Open raw')
+ # does not show a download or raw button
+ expect(page).not_to have_link('Download')
+ expect(page).not_to have_link('Open raw')
end
end
end
- end
-
- context 'ZIP file' do
- before do
- visit_blob('Gemfile.zip')
- wait_for_requests
- end
+ context 'files with auxiliary viewers' do
+ describe '.gitlab-ci.yml' do
+ before do
+ project.add_maintainer(project.creator)
- it 'displays the blob' do
- aggregate_failures do
- # shows a download link
- expect(page).to have_link('Download (2.11 KB)')
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab-ci.yml",
+ file_path: '.gitlab-ci.yml',
+ file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ ).execute
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ visit_blob('.gitlab-ci.yml')
+ end
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that configuration is valid
+ expect(page).to have_content('This GitLab CI configuration is valid.')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
end
- end
- end
- context 'empty file' do
- before do
- project.add_maintainer(project.creator)
+ describe '.gitlab/route-map.yml' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab/route-map.yml",
+ file_path: '.gitlab/route-map.yml',
+ file_content: <<-MAP.strip_heredoc
+ # Team data
+ - source: 'data/team.yml'
+ public: 'team/'
+ MAP
+ ).execute
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add empty file",
- file_path: 'files/empty.md',
- file_content: ''
- ).execute
+ visit_blob('.gitlab/route-map.yml')
+ end
- visit_blob('files/empty.md')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that map is valid
+ expect(page).to have_content('This Route Map is valid.')
- wait_for_requests
- end
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
- it 'displays an error' do
- aggregate_failures do
- # shows an error message
- expect(page).to have_content('Empty file')
+ describe '.gitlab/dashboards/custom-dashboard.yml' do
+ before do
+ project.add_maintainer(project.creator)
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab/dashboards/custom-dashboard.yml",
+ file_path: '.gitlab/dashboards/custom-dashboard.yml',
+ file_content: file_content
+ ).execute
+ end
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ context 'with metrics_dashboard_exhaustive_validations feature flag off' do
+ before do
+ stub_feature_flags(metrics_dashboard_exhaustive_validations: false)
+ visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ end
- # does not show a download or raw button
- expect(page).not_to have_link('Download')
- expect(page).not_to have_link('Open raw')
- end
- end
- end
+ context 'valid dashboard file' do
+ let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
- context 'binary file that appears to be text in the first 1024 bytes' do
- before do
- visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
- end
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is valid
+ expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
- it 'displays the blob' do
- aggregate_failures do
- # shows a download link
- expect(page).to have_link('Download (23.8 KB)')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ context 'invalid dashboard file' do
+ let(:file_content) { "dashboard: 'invalid'" }
- # The specs below verify an arguably incorrect result, but since we only
- # learn that the file is not actually text once the text viewer content
- # is loaded asynchronously, there is no straightforward way to get these
- # synchronously loaded elements to display correctly.
- #
- # Clicking the copy button will result in nothing being copied.
- # Clicking the raw button will result in the binary file being downloaded,
- # as expected.
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is invalid
+ expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
+ expect(page).to have_content("panel_groups: should be an array of panel_groups objects")
- # shows an enabled copy button, incorrectly
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+ end
- # shows a raw button, incorrectly
- expect(page).to have_link('Open raw')
- end
- end
- end
+ context 'with metrics_dashboard_exhaustive_validations feature flag on' do
+ before do
+ stub_feature_flags(metrics_dashboard_exhaustive_validations: true)
+ visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ end
- context 'files with auxiliary viewers' do
- before do
- stub_feature_flags(refactor_blob_viewer: true)
- end
+ context 'valid dashboard file' do
+ let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
- describe '.gitlab-ci.yml' do
- before do
- project.add_maintainer(project.creator)
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is valid
+ expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab-ci.yml",
- file_path: '.gitlab-ci.yml',
- file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- ).execute
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
- visit_blob('.gitlab-ci.yml')
- end
+ context 'invalid dashboard file' do
+ let(:file_content) { "dashboard: 'invalid'" }
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that configuration is valid
- expect(page).to have_content('This GitLab CI configuration is valid.')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is invalid
+ expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
+ expect(page).to have_content("root is missing required keys: panel_groups")
- # shows a learn more link
- expect(page).to have_link('Learn more')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
end
end
- end
- describe '.gitlab/route-map.yml' do
- before do
- project.add_maintainer(project.creator)
+ context 'LICENSE' do
+ before do
+ visit_blob('LICENSE')
+ end
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab/route-map.yml",
- file_path: '.gitlab/route-map.yml',
- file_content: <<-MAP.strip_heredoc
- # Team data
- - source: 'data/team.yml'
- public: 'team/'
- MAP
- ).execute
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows license
+ expect(page).to have_content('This project is licensed under the MIT License.')
- visit_blob('.gitlab/route-map.yml')
+ # shows a learn more link
+ expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
+ end
+ end
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that map is valid
- expect(page).to have_content('This Route Map is valid.')
+ context '*.gemspec' do
+ before do
+ project.add_maintainer(project.creator)
- # shows a learn more link
- expect(page).to have_link('Learn more')
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add activerecord.gemspec",
+ file_path: 'activerecord.gemspec',
+ file_content: <<-SPEC.strip_heredoc
+ Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = "activerecord"
+ end
+ SPEC
+ ).execute
+
+ visit_blob('activerecord.gemspec')
end
- end
- end
- describe '.gitlab/dashboards/custom-dashboard.yml' do
- before do
- project.add_maintainer(project.creator)
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows names of dependency manager and package
+ expect(page).to have_content('This project manages its dependencies using RubyGems.')
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab/dashboards/custom-dashboard.yml",
- file_path: '.gitlab/dashboards/custom-dashboard.yml',
- file_content: file_content
- ).execute
+ # shows a learn more link
+ expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
+ end
+ end
end
- context 'with metrics_dashboard_exhaustive_validations feature flag off' do
+ context 'CONTRIBUTING.md' do
before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: false)
- visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ file_name = 'CONTRIBUTING.md'
+
+ create_file(file_name, '## Contribution guidelines')
+ visit_blob(file_name)
end
- context 'valid dashboard file' do
- let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.")
+ end
+ end
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is valid
- expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
+ context 'CHANGELOG.md' do
+ before do
+ file_name = 'CHANGELOG.md'
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ create_file(file_name, '## Changelog for v1.0.0')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.")
end
end
+ end
- context 'invalid dashboard file' do
- let(:file_content) { "dashboard: 'invalid'" }
+ context 'Cargo.toml' do
+ before do
+ file_name = 'Cargo.toml'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is invalid
- expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
- expect(page).to have_content("panel_groups: should be an array of panel_groups objects")
+ create_file(file_name, '
+ [package]
+ name = "hello_world" # the name of the package
+ version = "0.1.0" # the current version, obeying semver
+ authors = ["Alice <a@example.com>", "Bob <b@example.com>"]
+ ')
+ visit_blob(file_name)
+ end
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Cargo.")
end
end
end
- context 'with metrics_dashboard_exhaustive_validations feature flag on' do
+ context 'Cartfile' do
before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: true)
- visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ file_name = 'Cartfile'
+
+ create_file(file_name, '
+ gitlab "Alamofire/Alamofire" == 4.9.0
+ gitlab "Alamofire/AlamofireImage" ~> 3.4
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Carthage.")
+ end
end
+ end
- context 'valid dashboard file' do
- let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
+ context 'composer.json' do
+ before do
+ file_name = 'composer.json'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is valid
- expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
+ create_file(file_name, '
+ {
+ "license": "MIT"
+ }
+ ')
+ visit_blob(file_name)
+ end
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Composer.")
end
end
+ end
- context 'invalid dashboard file' do
- let(:file_content) { "dashboard: 'invalid'" }
+ context 'Gemfile' do
+ before do
+ file_name = 'Gemfile'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is invalid
- expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
- expect(page).to have_content("root is missing required keys: panel_groups")
+ create_file(file_name, '
+ source "https://rubygems.org"
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ # Gems here
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Bundler.")
end
end
end
- end
- context 'LICENSE' do
- before do
- visit_blob('LICENSE')
- end
+ context 'Godeps.json' do
+ before do
+ file_name = 'Godeps.json'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows license
- expect(page).to have_content('This project is licensed under the MIT License.')
+ create_file(file_name, '
+ {
+ "GoVersion": "go1.6"
+ }
+ ')
+ visit_blob(file_name)
+ end
- # shows a learn more link
- expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using godep.")
+ end
end
end
- end
- context '*.gemspec' do
- before do
- project.add_maintainer(project.creator)
+ context 'go.mod' do
+ before do
+ file_name = 'go.mod'
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add activerecord.gemspec",
- file_path: 'activerecord.gemspec',
- file_content: <<-SPEC.strip_heredoc
- Gem::Specification.new do |s|
- s.platform = Gem::Platform::RUBY
- s.name = "activerecord"
- end
- SPEC
- ).execute
+ create_file(file_name, '
+ module example.com/mymodule
+
+ go 1.14
+ ')
+ visit_blob(file_name)
+ end
- visit_blob('activerecord.gemspec')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Go Modules.")
+ end
+ end
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows names of dependency manager and package
- expect(page).to have_content('This project manages its dependencies using RubyGems.')
+ context 'package.json' do
+ before do
+ file_name = 'package.json'
- # shows a learn more link
- expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
+ create_file(file_name, '
+ {
+ "name": "my-awesome-package",
+ "version": "1.0.0"
+ }
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using npm.")
+ end
end
end
- end
- context 'CONTRIBUTING.md' do
- before do
- file_name = 'CONTRIBUTING.md'
+ context 'podfile' do
+ before do
+ file_name = 'podfile'
- create_file(file_name, '## Contribution guidelines')
- visit_blob(file_name)
- end
+ create_file(file_name, 'platform :ios, "8.0"')
+ visit_blob(file_name)
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.")
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
end
end
- end
- context 'CHANGELOG.md' do
- before do
- file_name = 'CHANGELOG.md'
+ context 'test.podspec' do
+ before do
+ file_name = 'test.podspec'
- create_file(file_name, '## Changelog for v1.0.0')
- visit_blob(file_name)
- end
+ create_file(file_name, '
+ Pod::Spec.new do |s|
+ s.name = "TensorFlowLiteC"
+ ')
+ visit_blob(file_name)
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.")
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
end
end
- end
- context 'Cargo.toml' do
- before do
- file_name = 'Cargo.toml'
+ context 'JSON.podspec.json' do
+ before do
+ file_name = 'JSON.podspec.json'
- create_file(file_name, '
- [package]
- name = "hello_world" # the name of the package
- version = "0.1.0" # the current version, obeying semver
- authors = ["Alice <a@example.com>", "Bob <b@example.com>"]
- ')
- visit_blob(file_name)
- end
+ create_file(file_name, '
+ {
+ "name": "JSON"
+ }
+ ')
+ visit_blob(file_name)
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Cargo.")
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
end
end
- end
- context 'Cartfile' do
- before do
- file_name = 'Cartfile'
+ context 'requirements.txt' do
+ before do
+ file_name = 'requirements.txt'
- create_file(file_name, '
- gitlab "Alamofire/Alamofire" == 4.9.0
- gitlab "Alamofire/AlamofireImage" ~> 3.4
- ')
- visit_blob(file_name)
+ create_file(file_name, 'Project requirements')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using pip.")
+ end
+ end
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Carthage.")
+ context 'yarn.lock' do
+ before do
+ file_name = 'yarn.lock'
+
+ create_file(file_name, '
+ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+ # yarn lockfile v1
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Yarn.")
+ end
end
end
end
- context 'composer.json' do
+ context 'realtime pipelines' do
before do
- file_name = 'composer.json'
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'feature',
+ branch_name: 'feature',
+ commit_message: "Add ruby file",
+ file_path: 'files/ruby/test.rb',
+ file_content: "# Awesome content"
+ ).execute
- create_file(file_name, '
- {
- "license": "MIT"
- }
- ')
- visit_blob(file_name)
+ create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha)
+ visit_blob('files/ruby/test.rb', ref: 'feature')
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Composer.")
+ it 'shows the realtime pipeline status' do
+ page.within('.commit-actions') do
+ expect(page).to have_css('.ci-status-icon')
+ expect(page).to have_css('.ci-status-icon-running')
+ expect(page).to have_css('.js-ci-status-icon-running')
end
end
end
- context 'Gemfile' do
- before do
- file_name = 'Gemfile'
+ context 'for subgroups' do
+ let(:group) { create(:group) }
+ let(:subgroup) { create(:group, parent: group) }
+ let(:project) { create(:project, :public, :repository, group: subgroup) }
- create_file(file_name, '
- source "https://rubygems.org"
+ it 'renders tree table without errors' do
+ visit_blob('README.md')
- # Gems here
- ')
- visit_blob(file_name)
+ expect(page).to have_selector('.file-content')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Bundler.")
- end
+ it 'displays a GPG badge' do
+ visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
+
+ expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
+ expect(page).to have_selector '.gpg-status-box.invalid'
end
end
- context 'Godeps.json' do
- before do
- file_name = 'Godeps.json'
+ context 'on signed merge commit' do
+ it 'displays a GPG badge' do
+ visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
- create_file(file_name, '
- {
- "GoVersion": "go1.6"
- }
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using godep.")
- end
+ expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
+ expect(page).to have_selector '.gpg-status-box.invalid'
end
end
- context 'go.mod' do
+ context 'when static objects external storage is enabled' do
before do
- file_name = 'go.mod'
+ stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
+ end
- create_file(file_name, '
- module example.com/mymodule
+ context 'public project' do
+ before do
+ visit_blob('README.md')
+ end
- go 1.14
- ')
- visit_blob(file_name)
- end
+ it 'shows open raw and download buttons with external storage URL prepended to their href' do
+ path = project_raw_path(project, 'master/README.md')
+ raw_uri = "https://cdn.gitlab.com#{path}"
+ download_uri = "https://cdn.gitlab.com#{path}?inline=false"
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Go Modules.")
+ aggregate_failures do
+ expect(page).to have_link 'Open raw', href: raw_uri
+ expect(page).to have_link 'Download', href: download_uri
+ end
end
end
end
+ end
- context 'package.json' do
- before do
- file_name = 'package.json'
+ context 'with refactor_blob_viewer feature flag disabled' do
+ before do
+ stub_feature_flags(refactor_blob_viewer: false)
+ end
- create_file(file_name, '
- {
- "name": "my-awesome-package",
- "version": "1.0.0"
- }
- ')
- visit_blob(file_name)
- end
+ context 'when ref switch' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351558
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using npm.")
+ def switch_ref_to(ref_name)
+ first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
+
+ page.within '.project-refs-form' do
+ click_link ref_name
+ wait_for_requests
end
end
- end
- context 'podfile' do
- before do
- file_name = 'podfile'
+ context 'when highlighting lines' do
+ it 'displays single highlighted line number of different ref' do
+ visit_blob('files/js/application.js', anchor: 'L1')
- create_file(file_name, 'platform :ios, "8.0"')
- visit_blob(file_name)
- end
+ switch_ref_to('feature')
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ page.within '.blob-content' do
+ expect(find_by_id('LC1')[:class]).to include("hll")
+ end
end
- end
- end
- context 'test.podspec' do
- before do
- file_name = 'test.podspec'
+ it 'displays multiple highlighted line numbers of different ref' do
+ visit_blob('files/js/application.js', anchor: 'L1-3')
- create_file(file_name, '
- Pod::Spec.new do |s|
- s.name = "TensorFlowLiteC"
- ')
- visit_blob(file_name)
- end
+ switch_ref_to('feature')
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ page.within '.blob-content' do
+ expect(find_by_id('LC1')[:class]).to include("hll")
+ expect(find_by_id('LC2')[:class]).to include("hll")
+ expect(find_by_id('LC3')[:class]).to include("hll")
+ end
end
end
end
- context 'JSON.podspec.json' do
- before do
- file_name = 'JSON.podspec.json'
+ context 'visiting with a line number anchor' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351558
- create_file(file_name, '
- {
- "name": "JSON"
- }
- ')
- visit_blob(file_name)
+ before do
+ visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
- it 'displays an auxiliary viewer' do
+ it 'displays the blob using the simple viewer' do
aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
+
+ # highlights the line in question
+ expect(page).to have_selector('#LC1.hll')
+
+ # shows highlighted Markdown code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
end
end
end
- context 'requirements.txt' do
- before do
- file_name = 'requirements.txt'
+ context 'binary file that appears to be text in the first 1024 bytes' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351559
- create_file(file_name, 'Project requirements')
- visit_blob(file_name)
+ before do
+ visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
end
-
- it 'displays an auxiliary viewer' do
+ it 'displays the blob' do
aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using pip.")
+ # shows a download link
+ expect(page).to have_link('Download (23.8 KB)')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ # The specs below verify an arguably incorrect result, but since we only
+ # learn that the file is not actually text once the text viewer content
+ # is loaded asynchronously, there is no straightforward way to get these
+ # synchronously loaded elements to display correctly.
+ #
+ # Clicking the copy button will result in nothing being copied.
+ # Clicking the raw button will result in the binary file being downloaded,
+ # as expected.
+ # shows an enabled copy button, incorrectly
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # shows a raw button, incorrectly
+ expect(page).to have_link('Open raw')
end
end
end
- context 'yarn.lock' do
- before do
- file_name = 'yarn.lock'
+ context 'when static objects external storage is enabled' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351555
- create_file(file_name, '
- # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
- # yarn lockfile v1
- ')
- visit_blob(file_name)
+ before do
+ stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Yarn.")
+ context 'private project' do
+ let_it_be(:project) { create(:project, :repository, :private) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ project.add_developer(user)
+
+ sign_in(user)
+ visit_blob('README.md')
+ end
+
+ it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do
+ path = project_raw_path(project, 'master/README.md')
+ raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}"
+ download_uri = "https://cdn.gitlab.com#{path}?inline=false&token=#{user.static_object_token}"
+
+ aggregate_failures do
+ expect(page).to have_link 'Open raw', href: raw_uri
+ expect(page).to have_link 'Download', href: download_uri
+ end
end
end
end
- context 'when refactor_blob_viewer is disabled' do
- before do
- stub_feature_flags(refactor_blob_viewer: false)
- end
+ context 'files with auxiliary viewers' do
+ # This context is the same as the other 'files with auxiliary viewers' in this file, we just ensure that the auxiliary viewers still work this the refactor_blob_viewer disabled
+ # It should be safe to remove once we rollout the refactored blob viewer
describe '.gitlab-ci.yml' do
before do
@@ -1554,104 +1657,4 @@ RSpec.describe 'File blob', :js do
end
end
end
-
- context 'realtime pipelines' do
- before do
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'feature',
- branch_name: 'feature',
- commit_message: "Add ruby file",
- file_path: 'files/ruby/test.rb',
- file_content: "# Awesome content"
- ).execute
-
- create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha)
- visit_blob('files/ruby/test.rb', ref: 'feature')
- end
-
- it 'shows the realtime pipeline status' do
- page.within('.commit-actions') do
- expect(page).to have_css('.ci-status-icon')
- expect(page).to have_css('.ci-status-icon-running')
- expect(page).to have_css('.js-ci-status-icon-running')
- end
- end
- end
-
- context 'for subgroups' do
- let(:group) { create(:group) }
- let(:subgroup) { create(:group, parent: group) }
- let(:project) { create(:project, :public, :repository, group: subgroup) }
-
- it 'renders tree table without errors' do
- visit_blob('README.md')
-
- expect(page).to have_selector('.file-content')
- expect(page).not_to have_selector('.flash-alert')
- end
-
- it 'displays a GPG badge' do
- visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
-
- expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
- expect(page).to have_selector '.gpg-status-box.invalid'
- end
- end
-
- context 'on signed merge commit' do
- it 'displays a GPG badge' do
- visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
-
- expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
- expect(page).to have_selector '.gpg-status-box.invalid'
- end
- end
-
- context 'when static objects external storage is enabled' do
- before do
- stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
- end
-
- context 'private project' do
- let_it_be(:project) { create(:project, :repository, :private) }
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_developer(user)
-
- sign_in(user)
- visit_blob('README.md')
- end
-
- it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do
- path = project_raw_path(project, 'master/README.md')
- raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}"
- download_uri = "https://cdn.gitlab.com#{path}?inline=false&token=#{user.static_object_token}"
-
- aggregate_failures do
- expect(page).to have_link 'Open raw', href: raw_uri
- expect(page).to have_link 'Download', href: download_uri
- end
- end
- end
-
- context 'public project' do
- before do
- visit_blob('README.md')
- end
-
- it 'shows open raw and download buttons with external storage URL prepended to their href' do
- path = project_raw_path(project, 'master/README.md')
- raw_uri = "https://cdn.gitlab.com#{path}"
- download_uri = "https://cdn.gitlab.com#{path}?inline=false"
-
- aggregate_failures do
- expect(page).to have_link 'Open raw', href: raw_uri
- expect(page).to have_link 'Download', href: download_uri
- end
- end
- end
- end
end
diff --git a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
index 1c79b2ddc38..a2db5e11c7c 100644
--- a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
+++ b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'User follows pipeline suggest nudge spec when feature is enabled
include CookieHelper
let(:project) { create(:project, :empty_repo) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
describe 'viewing the new blob page' do
before do
diff --git a/spec/features/projects/branches/user_views_branches_spec.rb b/spec/features/projects/branches/user_views_branches_spec.rb
index d0c0a0860d9..b6b6dcb5cf1 100644
--- a/spec/features/projects/branches/user_views_branches_spec.rb
+++ b/spec/features/projects/branches/user_views_branches_spec.rb
@@ -4,7 +4,7 @@ require "spec_helper"
RSpec.describe "User views branches", :js do
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:user) { project.owner }
+ let_it_be(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb
index 16cfa9f5f84..daf5ac61d73 100644
--- a/spec/features/projects/ci/editor_spec.rb
+++ b/spec/features/projects/ci/editor_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe 'Pipeline Editor', :js do
expect(page).to have_content('Pipeline Editor')
end
- context 'branch switcher' do
+ describe 'Branch switcher' do
def switch_to_branch(branch)
find('[data-testid="branch-selector"]').click
@@ -64,7 +64,64 @@ RSpec.describe 'Pipeline Editor', :js do
end
end
- context 'Editor content' do
+ describe 'Editor navigation' do
+ context 'when no change is made' do
+ it 'user can navigate away without a browser alert' do
+ expect(page).to have_content('Pipeline Editor')
+
+ click_link 'Pipelines'
+
+ expect(page).not_to have_content('Pipeline Editor')
+ end
+ end
+
+ context 'when a change is made' do
+ before do
+ click_button 'Collapse'
+
+ page.within('#source-editor-') do
+ find('textarea').send_keys '123'
+ # It takes some time after sending keys for the vue
+ # component to update
+ sleep 1
+ end
+ end
+
+ it 'user who tries to navigate away can cancel the action and keep their changes' do
+ click_link 'Pipelines'
+
+ page.driver.browser.switch_to.alert.dismiss
+
+ expect(page).to have_content('Pipeline Editor')
+
+ page.within('#source-editor-') do
+ expect(page).to have_content('Default Content123')
+ end
+ end
+
+ it 'user who tries to navigate away can confirm the action and discard their change' do
+ click_link 'Pipelines'
+
+ page.driver.browser.switch_to.alert.accept
+
+ expect(page).not_to have_content('Pipeline Editor')
+ end
+
+ it 'user who creates a MR is taken to the merge request page without warnings' do
+ expect(page).not_to have_content('New merge request')
+
+ find_field('Target Branch').set 'new_branch'
+ find_field('Start a new merge request with these changes').click
+
+ click_button 'Commit changes'
+
+ expect(page).not_to have_content('Pipeline Editor')
+ expect(page).to have_content('New merge request')
+ end
+ end
+ end
+
+ describe 'Editor content' do
it 'user can reset their CI configuration' do
click_button 'Collapse'
diff --git a/spec/features/projects/cluster_agents_spec.rb b/spec/features/projects/cluster_agents_spec.rb
index 4018ef2abc9..d2b07bbc1de 100644
--- a/spec/features/projects/cluster_agents_spec.rb
+++ b/spec/features/projects/cluster_agents_spec.rb
@@ -10,6 +10,11 @@ RSpec.describe 'ClusterAgents', :js do
let(:user) { project.creator }
before do
+ allow(Gitlab::Kas).to receive(:enabled?).and_return(true)
+ allow_next_instance_of(Gitlab::Kas::Client) do |client|
+ allow(client).to receive(:get_connected_agents).and_return([])
+ end
+
gitlab_sign_in(user)
end
@@ -22,7 +27,7 @@ RSpec.describe 'ClusterAgents', :js do
end
it 'displays empty state', :aggregate_failures do
- expect(page).to have_content('Install a new agent')
+ expect(page).to have_content('Install new Agent')
expect(page).to have_selector('.empty-state')
end
end
diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb
index 6e45529c659..b0406e1f3c4 100644
--- a/spec/features/projects/clusters_spec.rb
+++ b/spec/features/projects/clusters_spec.rb
@@ -99,7 +99,8 @@ RSpec.describe 'Clusters', :js do
allow_any_instance_of(GoogleApi::CloudPlatform::Client)
.to receive(:projects_zones_clusters_create) do
- OpenStruct.new(
+ double(
+ 'cluster_control',
self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123',
status: 'RUNNING'
)
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index d88ff5c1aa5..bfd54b9c6da 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -132,6 +132,29 @@ RSpec.describe 'Environment' do
end
end
+ context 'with upcoming deployments' do
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
+
+ let!(:runnind_deployment_1) { create(:deployment, environment: environment, deployable: build, status: :running) }
+ let!(:runnind_deployment_2) { create(:deployment, environment: environment, deployable: build, status: :running) }
+ # Success deployments must have present `finished_at`. We'll backfill in the future.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/350618 for more information.
+ let!(:success_without_finished_at) { create(:deployment, environment: environment, deployable: build, status: :success, finished_at: nil) }
+
+ before do
+ visit_environment(environment)
+ end
+
+ # This ordering is unexpected and to be fixed.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/350618 for more information.
+ it 'shows upcoming deployments in unordered way' do
+ displayed_ids = find_all('[data-testid="deployment-id"]').map { |e| e.text }
+ internal_ids = [runnind_deployment_1, runnind_deployment_2, success_without_finished_at].map { |d| "##{d.iid}" }
+ expect(displayed_ids).to match_array(internal_ids)
+ end
+ end
+
context 'with related deployable present' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
diff --git a/spec/features/projects/environments_pod_logs_spec.rb b/spec/features/projects/environments_pod_logs_spec.rb
index 7d31de2b418..531eae1d638 100644
--- a/spec/features/projects/environments_pod_logs_spec.rb
+++ b/spec/features/projects/environments_pod_logs_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe 'Environment > Pod Logs', :js, :kubeclient do
stub_kubeclient_ingresses(environment.deployment_namespace)
stub_kubeclient_nodes_and_nodes_metrics(cluster.platform.api_url)
- sign_in(project.owner)
+ sign_in(project.first_owner)
end
it "shows environments in dropdown" do
diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb
index 11663158b33..3a0cc61d9c6 100644
--- a/spec/features/projects/files/dockerfile_dropdown_spec.rb
+++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Projects > Files > User wants to add a Dockerfile file', :js do
before do
project = create(:project, :repository)
- sign_in project.owner
+ sign_in project.first_owner
visit project_new_blob_path(project, 'master', file_name: 'Dockerfile')
end
diff --git a/spec/features/projects/files/edit_file_soft_wrap_spec.rb b/spec/features/projects/files/edit_file_soft_wrap_spec.rb
index fda024e893d..e08c53a67dd 100644
--- a/spec/features/projects/files/edit_file_soft_wrap_spec.rb
+++ b/spec/features/projects/files/edit_file_soft_wrap_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > User uses soft wrap while editing file', :js do
before do
project = create(:project, :repository)
- user = project.owner
+ user = project.first_owner
sign_in user
visit project_new_blob_path(project, 'master', file_name: 'test_file-name')
diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb
index 819864b3def..e256bec2a1c 100644
--- a/spec/features/projects/files/editing_a_file_spec.rb
+++ b/spec/features/projects/files/editing_a_file_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > User wants to edit a file' do
let(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:commit_params) do
{
start_branch: project.default_branch,
diff --git a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
index 94190889ace..a283f7d128c 100644
--- a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
+++ b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > User views files page' do
let(:project) { create(:forked_project_with_submodules) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in user
diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb
index 4293183fd9a..9ae3be4993b 100644
--- a/spec/features/projects/files/find_file_keyboard_spec.rb
+++ b/spec/features/projects/files/find_file_keyboard_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > Find file keyboard shortcuts', :js do
let(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in user
diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb
index d47eaee2e79..4a92216f46c 100644
--- a/spec/features/projects/files/gitignore_dropdown_spec.rb
+++ b/spec/features/projects/files/gitignore_dropdown_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Projects > Files > User wants to add a .gitignore file', :js do
before do
project = create(:project, :repository)
- sign_in project.owner
+ sign_in project.first_owner
visit project_new_blob_path(project, 'master', file_name: '.gitignore')
end
diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
index fc199f66490..cdf6c219ea5 100644
--- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
+++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js
let_it_be(:project) { create(:project, :repository) }
before do
- sign_in project.owner
+ sign_in project.first_owner
visit project_new_blob_path(project, 'master', file_name: filename, **params)
end
diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
index ab62e8aabc0..4a0b1f4c548 100644
--- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb
+++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > Project owner creates a license file', :js do
let(:project) { create(:project, :repository) }
- let(:project_maintainer) { project.owner }
+ let(:project_maintainer) { project.first_owner }
before do
project.repository.delete_file(project_maintainer, 'LICENSE',
diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
index 37583870cfd..ca384291c12 100644
--- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
+++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Projects > Files > Project owner sees a link to create a license
include WebIdeSpecHelpers
let(:project) { create(:project_empty_repo) }
- let(:project_maintainer) { project.owner }
+ let(:project_maintainer) { project.first_owner }
before do
sign_in(project_maintainer)
diff --git a/spec/features/projects/files/template_type_dropdown_spec.rb b/spec/features/projects/files/template_type_dropdown_spec.rb
index ca9ce841a92..9cdb5eeb076 100644
--- a/spec/features/projects/files/template_type_dropdown_spec.rb
+++ b/spec/features/projects/files/template_type_dropdown_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > Template type dropdown selector', :js do
let(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in user
diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb
index 560cb53ead2..0b2daf12063 100644
--- a/spec/features/projects/files/undo_template_spec.rb
+++ b/spec/features/projects/files/undo_template_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > Template Undo Button', :js do
let(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in user
diff --git a/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb b/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb
index 4d9da783f98..220572c6a6d 100644
--- a/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb
+++ b/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
# This is a regression test for https://gitlab.com/gitlab-org/gitlab-foss/issues/37569
RSpec.describe 'Projects > Files > User browses a tree with a folder containing only a folder', :js do
let(:project) { create(:project, :empty_repo) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
project.repository.create_dir(user, 'foo/bar', branch_name: 'master', message: 'Add the foo/bar folder')
diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb
index 508dec70db6..9b4d1502bc8 100644
--- a/spec/features/projects/files/user_browses_files_spec.rb
+++ b/spec/features/projects/files/user_browses_files_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe "User browses files" do
+RSpec.describe "User browses files", :js do
include RepoHelpers
let(:fork_message) do
@@ -13,7 +13,7 @@ RSpec.describe "User browses files" do
let(:project) { create(:project, :repository, name: "Shop") }
let(:project2) { create(:project, :repository, name: "Another Project", path: "another-project") }
let(:tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
@@ -340,32 +340,37 @@ RSpec.describe "User browses files" do
let(:newrev) { project.repository.commit('master').sha }
before do
- stub_feature_flags(refactor_blob_viewer: false) # This stub will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/350456
create_file_in_repo(project, 'master', 'master', filename, 'Test file')
path = File.join('master', filename)
visit(project_blob_path(project, path))
+ wait_for_requests
end
- it "shows a raw file content" do
- click_link("Open raw")
+ it "shows raw file content in a new tab" do
+ new_tab = window_opened_by {click_link 'Open raw'}
- expect(source).to eq("") # Body is filled in by gitlab-workhorse
+ within_window new_tab do
+ expect(page).to have_content("Test file")
+ end
end
end
context "when browsing a raw file" do
before do
- stub_feature_flags(refactor_blob_viewer: false) # This stub will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/350456
- path = File.join(RepoHelpers.sample_commit.id, RepoHelpers.sample_blob.path)
+ visit(tree_path_root_ref)
+ wait_for_requests
- visit(project_blob_path(project, path))
+ click_link(".gitignore")
+ wait_for_requests
end
- it "shows a raw file content" do
- click_link("Open raw")
+ it "shows raw file content in a new tab" do
+ new_tab = window_opened_by {click_link 'Open raw'}
- expect(source).to eq("") # Body is filled in by gitlab-workhorse
+ within_window new_tab do
+ expect(page).to have_content("*.rbc")
+ end
end
end
end
diff --git a/spec/features/projects/files/user_browses_lfs_files_spec.rb b/spec/features/projects/files/user_browses_lfs_files_spec.rb
index 17699847704..3976df849fa 100644
--- a/spec/features/projects/files/user_browses_lfs_files_spec.rb
+++ b/spec/features/projects/files/user_browses_lfs_files_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > User browses LFS files' do
let(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/files/user_searches_for_files_spec.rb b/spec/features/projects/files/user_searches_for_files_spec.rb
index 7fd7dfff279..cce73d06f94 100644
--- a/spec/features/projects/files/user_searches_for_files_spec.rb
+++ b/spec/features/projects/files/user_searches_for_files_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User searches for files' do
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/gfm_autocomplete_load_spec.rb b/spec/features/projects/gfm_autocomplete_load_spec.rb
index f4cd65bcba1..a7d68b07dd3 100644
--- a/spec/features/projects/gfm_autocomplete_load_spec.rb
+++ b/spec/features/projects/gfm_autocomplete_load_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'GFM autocomplete loading', :js do
let(:project) { create(:project) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_path(project)
end
diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb
index 2fbec4e22f4..1e5c5d33ad9 100644
--- a/spec/features/projects/import_export/import_file_spec.rb
+++ b/spec/features/projects/import_export/import_file_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe 'Import/Export - project import integration test', :js do
project = Project.last
expect(project).not_to be_nil
- expect(page).to have_content("Project 'test-project-path' is being imported")
+ expect(page).to have_content("Project 'Test Project Name' is being imported")
end
it 'invalid project' do
diff --git a/spec/features/projects/services/disable_triggers_spec.rb b/spec/features/projects/integrations/disable_triggers_spec.rb
index c6413685f38..b039d610ecb 100644
--- a/spec/features/projects/services/disable_triggers_spec.rb
+++ b/spec/features/projects/integrations/disable_triggers_spec.rb
@@ -3,16 +3,16 @@
require 'spec_helper'
RSpec.describe 'Disable individual triggers', :js do
- include_context 'project service activation'
+ include_context 'project integration activation'
let(:checkbox_selector) { 'input[name$="_events]"]' }
before do
- visit_project_integration(service_name)
+ visit_project_integration(integration_name)
end
- context 'service has multiple supported events' do
- let(:service_name) { 'Jenkins' }
+ context 'integration has multiple supported events' do
+ let(:integration_name) { 'Jenkins' }
it 'shows trigger checkboxes' do
event_count = Integrations::Jenkins.supported_events.count
@@ -22,8 +22,8 @@ RSpec.describe 'Disable individual triggers', :js do
end
end
- context 'services only has one supported event' do
- let(:service_name) { 'Asana' }
+ context 'integrations only has one supported event' do
+ let(:integration_name) { 'Asana' }
it "doesn't show unnecessary Trigger checkboxes" do
expect(page).not_to have_content "Trigger"
diff --git a/spec/features/projects/integrations/project_integrations_spec.rb b/spec/features/projects/integrations/project_integrations_spec.rb
new file mode 100644
index 00000000000..708a5bca8c1
--- /dev/null
+++ b/spec/features/projects/integrations/project_integrations_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Project integrations', :js do
+ include_context 'project integration activation'
+
+ it_behaves_like 'integration settings form' do
+ let(:integrations) { project.find_or_initialize_integrations }
+
+ def navigate_to_integration(integration)
+ visit_project_integration(integration.title)
+ end
+ end
+end
diff --git a/spec/features/projects/services/prometheus_external_alerts_spec.rb b/spec/features/projects/integrations/prometheus_external_alerts_spec.rb
index c2ae72ddb5e..7e56ca13e23 100644
--- a/spec/features/projects/services/prometheus_external_alerts_spec.rb
+++ b/spec/features/projects/integrations/prometheus_external_alerts_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Prometheus external alerts', :js do
- include_context 'project service activation'
+ include_context 'project integration activation'
let(:alerts_section_selector) { '.js-prometheus-alerts' }
let(:alerts_section) { page.find(alerts_section_selector) }
diff --git a/spec/features/projects/integrations/user_activates_asana_spec.rb b/spec/features/projects/integrations/user_activates_asana_spec.rb
index cf2290383e8..9ec9f00529a 100644
--- a/spec/features/projects/integrations/user_activates_asana_spec.rb
+++ b/spec/features/projects/integrations/user_activates_asana_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'User activates Asana' do
- include_context 'project service activation'
+ include_context 'project integration activation'
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Asana')
fill_in('API key', with: 'verySecret')
fill_in('Restrict to branch', with: 'verySecret')
diff --git a/spec/features/projects/integrations/user_activates_assembla_spec.rb b/spec/features/projects/integrations/user_activates_assembla_spec.rb
index 63cc424a641..be9034ec5ba 100644
--- a/spec/features/projects/integrations/user_activates_assembla_spec.rb
+++ b/spec/features/projects/integrations/user_activates_assembla_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
RSpec.describe 'User activates Assembla' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_request(:post, /.*atlas.assembla.com.*/)
end
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Assembla')
fill_in('Token', with: 'verySecret')
diff --git a/spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb b/spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb
index 91db375be3a..49f62a34bd2 100644
--- a/spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb
+++ b/spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
RSpec.describe 'User activates Atlassian Bamboo CI' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_request(:get, /.*bamboo.example.com.*/)
end
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Atlassian Bamboo')
fill_in('Bamboo URL', with: 'http://bamboo.example.com')
fill_in('Build key', with: 'KEY')
diff --git a/spec/features/projects/services/user_activates_emails_on_push_spec.rb b/spec/features/projects/integrations/user_activates_emails_on_push_spec.rb
index 5a075fc61e8..168779aad07 100644
--- a/spec/features/projects/services/user_activates_emails_on_push_spec.rb
+++ b/spec/features/projects/integrations/user_activates_emails_on_push_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'User activates Emails on push' do
- include_context 'project service activation'
+ include_context 'project integration activation'
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Emails on push')
fill_in('Recipients', with: 'qa@company.name')
diff --git a/spec/features/projects/integrations/user_activates_flowdock_spec.rb b/spec/features/projects/integrations/user_activates_flowdock_spec.rb
index 4a4d7bbecfd..df1a4feddfb 100644
--- a/spec/features/projects/integrations/user_activates_flowdock_spec.rb
+++ b/spec/features/projects/integrations/user_activates_flowdock_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User activates Flowdock' do
- include_context 'project service activation' do
+ include_context 'project integration activation' do
let(:project) { create(:project, :repository) }
end
@@ -11,7 +11,7 @@ RSpec.describe 'User activates Flowdock' do
stub_request(:post, /.*api.flowdock.com.*/)
end
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Flowdock')
fill_in('Token', with: 'verySecret')
diff --git a/spec/features/projects/services/user_activates_irker_spec.rb b/spec/features/projects/integrations/user_activates_irker_spec.rb
index 004aa116bb3..23b5f2a5c47 100644
--- a/spec/features/projects/services/user_activates_irker_spec.rb
+++ b/spec/features/projects/integrations/user_activates_irker_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'User activates irker (IRC gateway)' do
- include_context 'project service activation'
+ include_context 'project integration activation'
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('irker (IRC gateway)')
check('Colorize messages')
fill_in('Recipients', with: 'irc://chat.freenode.net/#commits')
diff --git a/spec/features/projects/services/user_activates_issue_tracker_spec.rb b/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb
index 27c23e7beb5..b9c2c539899 100644
--- a/spec/features/projects/services/user_activates_issue_tracker_spec.rb
+++ b/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User activates issue tracker', :js do
- include_context 'project service activation'
+ include_context 'project integration activation'
let(:url) { 'http://tracker.example.com' }
@@ -17,7 +17,7 @@ RSpec.describe 'User activates issue tracker', :js do
end
shared_examples 'external issue tracker activation' do |tracker:, skip_new_issue_url: false, skip_test: false|
- describe 'user sets and activates the Service' do
+ describe 'user sets and activates the integration' do
context 'when the connection test succeeds' do
before do
stub_request(:head, url).to_return(headers: { 'Content-Type' => 'application/json' })
@@ -32,7 +32,7 @@ RSpec.describe 'User activates issue tracker', :js do
end
end
- it 'activates the service' do
+ it 'activates the integration' do
expect(page).to have_content("#{tracker} settings saved and active.")
expect(current_path).to eq(edit_project_integration_path(project, tracker.parameterize(separator: '_')))
end
@@ -45,7 +45,7 @@ RSpec.describe 'User activates issue tracker', :js do
end
context 'when the connection test fails' do
- it 'activates the service' do
+ it 'activates the integration' do
stub_request(:head, url).to_raise(Gitlab::HTTP::Error)
visit_project_integration(tracker)
@@ -63,7 +63,7 @@ RSpec.describe 'User activates issue tracker', :js do
end
end
- describe 'user disables the service' do
+ describe 'user disables the integration' do
before do
visit_project_integration(tracker)
fill_form(disable: true, skip_new_issue_url: skip_new_issue_url)
@@ -71,7 +71,7 @@ RSpec.describe 'User activates issue tracker', :js do
click_button('Save changes')
end
- it 'saves but does not activate the service' do
+ it 'saves but does not activate the integration' do
expect(page).to have_content("#{tracker} settings saved, but not active.")
expect(current_path).to eq(edit_project_integration_path(project, tracker.parameterize(separator: '_')))
end
diff --git a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb b/spec/features/projects/integrations/user_activates_jetbrains_teamcity_ci_spec.rb
index 17bfe8fc1e2..e6f2e462b8c 100644
--- a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb
+++ b/spec/features/projects/integrations/user_activates_jetbrains_teamcity_ci_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
RSpec.describe 'User activates JetBrains TeamCity CI' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_request(:post, /.*teamcity.example.com.*/)
end
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('JetBrains TeamCity')
check('Push')
check('Merge Request')
diff --git a/spec/features/projects/integrations/user_activates_jira_spec.rb b/spec/features/projects/integrations/user_activates_jira_spec.rb
index 50010950f0e..7562dc00092 100644
--- a/spec/features/projects/integrations/user_activates_jira_spec.rb
+++ b/spec/features/projects/integrations/user_activates_jira_spec.rb
@@ -3,14 +3,14 @@
require 'spec_helper'
RSpec.describe 'User activates Jira', :js do
- include_context 'project service activation'
- include_context 'project service Jira context'
+ include_context 'project integration activation'
+ include_context 'project integration Jira context'
before do
stub_request(:get, test_url).to_return(body: { key: 'value' }.to_json)
end
- describe 'user tests Jira Service' do
+ describe 'user tests Jira integration' do
context 'when Jira connection test succeeds' do
before do
visit_project_integration('Jira')
@@ -18,7 +18,7 @@ RSpec.describe 'User activates Jira', :js do
click_test_then_save_integration(expect_test_to_fail: false)
end
- it 'activates the Jira service' do
+ it 'activates the Jira integration' do
expect(page).to have_content('Jira settings saved and active.')
expect(current_path).to eq(edit_project_integration_path(project, :jira))
end
@@ -46,7 +46,7 @@ RSpec.describe 'User activates Jira', :js do
end
end
- it 'activates the Jira service' do
+ it 'activates the Jira integration' do
stub_request(:get, test_url).with(basic_auth: %w(username password))
.to_raise(JIRA::HTTPError.new(double(message: 'message')))
@@ -60,7 +60,7 @@ RSpec.describe 'User activates Jira', :js do
end
end
- describe 'user disables the Jira Service' do
+ describe 'user disables the Jira integration' do
include JiraServiceHelper
before do
@@ -70,7 +70,7 @@ RSpec.describe 'User activates Jira', :js do
click_save_integration
end
- it 'saves but does not activate the Jira service' do
+ it 'saves but does not activate the Jira integration' do
expect(page).to have_content('Jira settings saved, but not active.')
expect(current_path).to eq(edit_project_integration_path(project, :jira))
end
diff --git a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
index 74919a99f04..ed0877ab0e9 100644
--- a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb
+++ b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
@@ -4,14 +4,14 @@ require 'spec_helper'
RSpec.describe 'Set up Mattermost slash commands', :js do
describe 'user visits the mattermost slash command config page' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_mattermost_setting(enabled: mattermost_enabled)
visit_project_integration('Mattermost slash commands')
end
- context 'mattermost service is enabled' do
+ context 'mattermost integration is enabled' do
let(:mattermost_enabled) { true }
describe 'activation' do
@@ -84,7 +84,9 @@ RSpec.describe 'Set up Mattermost slash commands', :js do
end
it 'shows an error alert with the error message if there is an error requesting teams' do
- allow_any_instance_of(Integrations::MattermostSlashCommands).to receive(:list_teams) { [[], 'test mattermost error message'] }
+ allow_next_instance_of(Integrations::MattermostSlashCommands) do |integration|
+ allow(integration).to receive(:list_teams).and_return([[], 'test mattermost error message'])
+ end
click_link 'Add to Mattermost'
@@ -113,7 +115,9 @@ RSpec.describe 'Set up Mattermost slash commands', :js do
def stub_teams(count: 0)
teams = create_teams(count)
- allow_any_instance_of(Integrations::MattermostSlashCommands).to receive(:list_teams) { [teams, nil] }
+ allow_next_instance_of(Integrations::MattermostSlashCommands) do |integration|
+ allow(integration).to receive(:list_teams).and_return([teams, nil])
+ end
teams
end
@@ -129,7 +133,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js do
end
end
- context 'mattermost service is not enabled' do
+ context 'mattermost integration is not enabled' do
let(:mattermost_enabled) { false }
it 'shows the correct trigger url' do
diff --git a/spec/features/projects/services/user_activates_packagist_spec.rb b/spec/features/projects/integrations/user_activates_packagist_spec.rb
index 87303cf8fb4..0892843e840 100644
--- a/spec/features/projects/services/user_activates_packagist_spec.rb
+++ b/spec/features/projects/integrations/user_activates_packagist_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
RSpec.describe 'User activates Packagist' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_request(:post, /.*packagist.org.*/)
end
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Packagist')
fill_in('Username', with: 'theUser')
fill_in('Token', with: 'verySecret')
diff --git a/spec/features/projects/integrations/user_activates_pivotaltracker_spec.rb b/spec/features/projects/integrations/user_activates_pivotaltracker_spec.rb
index ea34a766719..fe6ed786ace 100644
--- a/spec/features/projects/integrations/user_activates_pivotaltracker_spec.rb
+++ b/spec/features/projects/integrations/user_activates_pivotaltracker_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
RSpec.describe 'User activates PivotalTracker' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_request(:post, /.*www.pivotaltracker.com.*/)
end
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Pivotal Tracker')
fill_in('Token', with: 'verySecret')
diff --git a/spec/features/projects/services/user_activates_prometheus_spec.rb b/spec/features/projects/integrations/user_activates_prometheus_spec.rb
index 73ad8088be2..80629af6fce 100644
--- a/spec/features/projects/services/user_activates_prometheus_spec.rb
+++ b/spec/features/projects/integrations/user_activates_prometheus_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
RSpec.describe 'User activates Prometheus' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_request(:get, /.*prometheus.example.com.*/)
end
- it 'does not activate service and informs about deprecation', :js do
+ it 'does not activate integration and informs about deprecation', :js do
visit_project_integration('Prometheus')
check('Active')
fill_in('API URL', with: 'http://prometheus.example.com')
diff --git a/spec/features/projects/services/user_activates_pushover_spec.rb b/spec/features/projects/integrations/user_activates_pushover_spec.rb
index d92f69e700a..616efdc836f 100644
--- a/spec/features/projects/services/user_activates_pushover_spec.rb
+++ b/spec/features/projects/integrations/user_activates_pushover_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
RSpec.describe 'User activates Pushover' do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_request(:post, /.*api.pushover.net.*/)
end
- it 'activates service', :js do
+ it 'activates integration', :js do
visit_project_integration('Pushover')
fill_in('API key', with: 'verySecret')
fill_in('User key', with: 'verySecret')
diff --git a/spec/features/projects/services/user_activates_slack_notifications_spec.rb b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
index 38b6ad84c77..616469c5df8 100644
--- a/spec/features/projects/services/user_activates_slack_notifications_spec.rb
+++ b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
@@ -3,14 +3,14 @@
require 'spec_helper'
RSpec.describe 'User activates Slack notifications', :js do
- include_context 'project service activation'
+ include_context 'project integration activation'
- context 'when service is not configured yet' do
+ context 'when integration is not configured yet' do
before do
visit_project_integration('Slack notifications')
end
- it 'activates service' do
+ it 'activates integration' do
fill_in('Webhook', with: 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685')
click_test_then_save_integration
@@ -19,7 +19,7 @@ RSpec.describe 'User activates Slack notifications', :js do
end
end
- context 'when service is already configured' do
+ context 'when integration is already configured' do
let(:integration) { Integrations::Slack.new }
let(:project) { create(:project, slack_integration: integration) }
diff --git a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
index d46d1f739b7..7ec469070ea 100644
--- a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb
+++ b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Slack slash commands', :js do
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
visit_project_integration('Slack slash commands')
diff --git a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb
index d2c4418f0d6..fcb04c338a9 100644
--- a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb
+++ b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User uses inherited settings', :js do
include JiraServiceHelper
- include_context 'project service activation'
+ include_context 'project integration activation'
before do
stub_jira_integration_test
diff --git a/spec/features/projects/services/user_views_services_spec.rb b/spec/features/projects/integrations/user_views_services_spec.rb
index 201a58ba379..559461f911f 100644
--- a/spec/features/projects/services/user_views_services_spec.rb
+++ b/spec/features/projects/integrations/user_views_services_spec.rb
@@ -2,10 +2,10 @@
require 'spec_helper'
-RSpec.describe 'User views services', :js do
- include_context 'project service activation'
+RSpec.describe 'User views integrations', :js do
+ include_context 'project integration activation'
- it 'shows the list of available services' do
+ it 'shows the list of available integrations' do
visit_project_integrations
expect(page).to have_content('Integrations')
diff --git a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
index 211576a93f3..762f9c33510 100644
--- a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
+++ b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'User uploads new design', :js do
include DesignManagementTestHelpers
let(:project) { create(:project_empty_repo, :public) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:issue) { create(:issue, project: project) }
before do
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 7ccd5c51493..a65d2d15c12 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -615,7 +615,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
end
context 'when the user is not able to view the cluster' do
- let(:user_access_level) { :developer }
+ let(:user_access_level) { :reporter }
it 'includes only the name of the cluster without a link' do
expect(page).to have_content 'using cluster the-cluster'
diff --git a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
index c8a9f959188..c9fee9bee7a 100644
--- a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
+++ b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
@@ -21,6 +21,6 @@ RSpec.describe 'Projects > Members > Group member cannot leave group project' do
it 'renders a flash message if attempting to leave by url', :js do
visit project_path(project, leave: 1)
- expect(find('.flash-alert')).to have_content 'You do not have permission to leave this project'
+ expect(find('[data-testid="alert-danger"]')).to have_content 'You do not have permission to leave this project'
end
end
diff --git a/spec/features/projects/members/invite_group_spec.rb b/spec/features/projects/members/invite_group_spec.rb
index b674cad0312..066e0b0d20f 100644
--- a/spec/features/projects/members/invite_group_spec.rb
+++ b/spec/features/projects/members/invite_group_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'Project > Members > Invite group', :js do
include Spec::Support::Helpers::Features::MembersHelpers
include Spec::Support::Helpers::Features::InviteMembersModalHelper
- let(:maintainer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
using RSpec::Parameterized::TableSyntax
@@ -190,17 +190,26 @@ RSpec.describe 'Project > Members > Invite group', :js do
end
describe 'the groups dropdown' do
- context 'with multiple groups to choose from' do
- let(:project) { create(:project) }
+ let_it_be(:parent_group) { create(:group, :public) }
+ let_it_be(:project_group) { create(:group, :public, parent: parent_group) }
+ let_it_be(:public_sub_subgroup) { create(:group, :public, parent: project_group) }
+ let_it_be(:public_sibbling_group) { create(:group, :public, parent: parent_group) }
+ let_it_be(:private_sibbling_group) { create(:group, :private, parent: parent_group) }
+ let_it_be(:private_membership_group) { create(:group, :private) }
+ let_it_be(:public_membership_group) { create(:group, :public) }
+ let_it_be(:project) { create(:project, group: project_group) }
- it 'includes multiple groups' do
- project.add_maintainer(maintainer)
- sign_in(maintainer)
+ before do
+ private_membership_group.add_guest(maintainer)
+ public_membership_group.add_maintainer(maintainer)
+
+ sign_in(maintainer)
+ end
- group1 = create(:group)
- group1.add_owner(maintainer)
- group2 = create(:group)
- group2.add_owner(maintainer)
+ context 'for a project in a nested group' do
+ it 'does not show the groups inherited from projects' do
+ project.add_maintainer(maintainer)
+ public_sibbling_group.add_maintainer(maintainer)
visit project_project_members_path(project)
@@ -208,37 +217,90 @@ RSpec.describe 'Project > Members > Invite group', :js do
click_on 'Select a group'
wait_for_requests
- expect(page).to have_button(group1.name)
- expect(page).to have_button(group2.name)
- end
- end
-
- context 'for a project in a nested group' do
- let(:group) { create(:group) }
- let!(:nested_group) { create(:group, parent: group) }
- let!(:group_to_share_with) { create(:group) }
- let!(:project) { create(:project, namespace: nested_group) }
+ page.within('[data-testid="group-select-dropdown"]') do
+ expect_to_have_group(public_membership_group)
+ expect_to_have_group(public_sibbling_group)
+ expect_to_have_group(private_membership_group)
- before do
- project.add_maintainer(maintainer)
- sign_in(maintainer)
- group.add_maintainer(maintainer)
- group_to_share_with.add_maintainer(maintainer)
+ expect_not_to_have_group(public_sub_subgroup)
+ expect_not_to_have_group(private_sibbling_group)
+ expect_not_to_have_group(parent_group)
+ expect_not_to_have_group(project_group)
+ end
end
- # This behavior should be changed to exclude the ancestor and project
- # group from the options once issue is fixed for the modal:
- # https://gitlab.com/gitlab-org/gitlab/-/issues/329835
- it 'the groups dropdown does show ancestors and the project group' do
+ it 'does not show the ancestors or project group', :aggregate_failures do
+ parent_group.add_maintainer(maintainer)
+
visit project_project_members_path(project)
click_on 'Invite a group'
click_on 'Select a group'
wait_for_requests
- expect(page).to have_button(group_to_share_with.name)
- expect(page).to have_button(group.name)
- expect(page).to have_button(nested_group.name)
+ page.within('[data-testid="group-select-dropdown"]') do
+ expect_to_have_group(public_membership_group)
+ expect_to_have_group(public_sibbling_group)
+ expect_to_have_group(private_membership_group)
+ expect_to_have_group(public_sub_subgroup)
+ expect_to_have_group(private_sibbling_group)
+
+ expect_not_to_have_group(parent_group)
+ expect_not_to_have_group(project_group)
+ end
+ end
+
+ context 'when invite_members_group_modal feature disabled' do
+ let(:group_invite_dropdown) { find('#select2-results-2') }
+
+ before do
+ stub_feature_flags(invite_members_group_modal: false)
+ end
+
+ it 'does not show the groups inherited from projects', :aggregate_failures do
+ project.add_maintainer(maintainer)
+ public_sibbling_group.add_maintainer(maintainer)
+
+ visit project_project_members_path(project)
+
+ click_on 'Invite group'
+ click_on 'Search for a group'
+ wait_for_requests
+
+ expect(group_invite_dropdown).to have_text(public_membership_group.full_path)
+ expect(group_invite_dropdown).to have_text(public_sibbling_group.full_path)
+ expect(group_invite_dropdown).to have_text(private_membership_group.full_path)
+ expect(group_invite_dropdown).not_to have_text(public_sub_subgroup.full_path)
+ expect(group_invite_dropdown).not_to have_text(private_sibbling_group.full_path)
+ expect(group_invite_dropdown).not_to have_text(parent_group.full_path, exact: true)
+ expect(group_invite_dropdown).not_to have_text(project_group.full_path, exact: true)
+ end
+
+ it 'does not show the ancestors or project group', :aggregate_failures do
+ parent_group.add_maintainer(maintainer)
+
+ visit project_project_members_path(project)
+
+ click_on 'Invite group'
+ click_on 'Search for a group'
+ wait_for_requests
+
+ expect(group_invite_dropdown).to have_text(public_membership_group.full_path)
+ expect(group_invite_dropdown).to have_text(public_sub_subgroup.full_path)
+ expect(group_invite_dropdown).to have_text(public_sibbling_group.full_path)
+ expect(group_invite_dropdown).to have_text(private_sibbling_group.full_path)
+ expect(group_invite_dropdown).to have_text(private_membership_group.full_path)
+ expect(group_invite_dropdown).not_to have_text(parent_group.full_path, exact: true)
+ expect(group_invite_dropdown).not_to have_text(project_group.full_path, exact: true)
+ end
+ end
+
+ def expect_to_have_group(group)
+ expect(page).to have_selector("[entity-id='#{group.id}']")
+ end
+
+ def expect_not_to_have_group(group)
+ expect(page).not_to have_selector("[entity-id='#{group.id}']")
end
end
end
diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb
index 4881a7bdf1a..c38292f81bf 100644
--- a/spec/features/projects/members/member_leaves_project_spec.rb
+++ b/spec/features/projects/members/member_leaves_project_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Member leaves project' do
+ include Spec::Support::Helpers::Features::MembersHelpers
+
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
@@ -21,13 +23,18 @@ RSpec.describe 'Projects > Members > Member leaves project' do
expect(project.users.exists?(user.id)).to be_falsey
end
- it 'user leaves project by url param', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/35925' do
+ it 'user leaves project by url param', :js do
visit project_path(project, leave: 1)
page.accept_confirm
+ wait_for_all_requests
- expect(find('.flash-notice')).to have_content "You left the \"#{project.full_name}\" project"
expect(current_path).to eq(dashboard_projects_path)
- expect(project.users.exists?(user.id)).to be_falsey
+
+ sign_in(project.first_owner)
+
+ visit project_project_members_path(project)
+
+ expect(members_table).not_to have_content(user.name)
end
end
diff --git a/spec/features/projects/members/owner_cannot_leave_project_spec.rb b/spec/features/projects/members/owner_cannot_leave_project_spec.rb
index fbe8583b236..45a8f979b87 100644
--- a/spec/features/projects/members/owner_cannot_leave_project_spec.rb
+++ b/spec/features/projects/members/owner_cannot_leave_project_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Projects > Members > Owner cannot leave project' do
let(:project) { create(:project) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_path(project)
end
diff --git a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb
index 5e6e3d4d7f2..fad5d831c19 100644
--- a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb
+++ b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Projects > Members > Owner cannot request access to their own pr
let(:project) { create(:project) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_path(project)
end
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index dcaef5f4ef0..0b00656f87b 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Projects > Members > User requests access', :js do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
- let(:maintainer) { project.owner }
+ let(:maintainer) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index f61eaccf5b9..91e643ff258 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'Project navbar' do
let_it_be(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/network_graph_spec.rb b/spec/features/projects/network_graph_spec.rb
index 4ae809399b6..1ee0ea51e53 100644
--- a/spec/features/projects/network_graph_spec.rb
+++ b/spec/features/projects/network_graph_spec.rb
@@ -96,7 +96,7 @@ RSpec.describe 'Project Network Graph', :js do
find('button').click
end
- expect(page).to have_selector '.flash-alert', text: "Git revision ';' does not exist."
+ expect(page).to have_selector '[data-testid="alert-danger"]', text: "Git revision ';' does not exist."
end
end
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index f1786c1be40..b3fbf5d356e 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -306,10 +306,24 @@ RSpec.describe 'New project', :js do
expect(page).to have_text('There is not a valid Git repository at this URL')
end
+ it 'reports error if repo URL is not a valid Git repository and submit button is clicked immediately' do
+ stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return(status: 200, body: "not-a-git-repo")
+
+ fill_in 'project_import_url', with: 'http://foo/bar'
+ click_on 'Create project'
+
+ wait_for_requests
+
+ expect(page).to have_text('There is not a valid Git repository at this URL')
+ end
+
it 'keeps "Import project" tab open after form validation error' do
collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace)
+ stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return({ status: 200,
+ body: '001e# service=git-upload-pack',
+ headers: { 'Content-Type': 'application/x-git-upload-pack-advertisement' } })
- fill_in 'project_import_url', with: collision_project.http_url_to_repo
+ fill_in 'project_import_url', with: 'http://foo/bar'
fill_in 'project_name', with: collision_project.name
click_on 'Create project'
@@ -319,6 +333,38 @@ RSpec.describe 'New project', :js do
end
end
+ context 'when import is initiated from project page' do
+ before do
+ project_without_repo = create(:project, name: 'project-without-repo', namespace: user.namespace)
+ visit project_path(project_without_repo)
+ click_on 'Import repository'
+ end
+
+ it 'reports error when invalid url is provided' do
+ stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return(status: 200, body: "not-a-git-repo")
+
+ fill_in 'project_import_url', with: 'http://foo/bar'
+
+ click_on 'Start import'
+ wait_for_requests
+
+ expect(page).to have_text('There is not a valid Git repository at this URL')
+ end
+
+ it 'initiates import when valid repo url is provided' do
+ stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return({ status: 200,
+ body: '001e# service=git-upload-pack',
+ headers: { 'Content-Type': 'application/x-git-upload-pack-advertisement' } })
+
+ fill_in 'project_import_url', with: 'http://foo/bar'
+
+ click_on 'Start import'
+ wait_for_requests
+
+ expect(page).to have_text('Import in progress')
+ end
+ end
+
context 'from GitHub' do
before do
first('.js-import-github').click
@@ -358,4 +404,47 @@ RSpec.describe 'New project', :js do
end
end
end
+
+ context 'from Bitbucket', :js do
+ shared_examples 'has a link to bitbucket cloud' do
+ context 'when bitbucket is not configured' do
+ before do
+ allow(Gitlab::Auth::OAuth::Provider).to receive(:enabled?).and_call_original
+ allow(Gitlab::Auth::OAuth::Provider)
+ .to receive(:enabled?).with(:bitbucket)
+ .and_return(false)
+
+ visit new_project_path
+ click_link 'Import project'
+ click_link 'Bitbucket Cloud'
+ end
+
+ it 'shows import instructions' do
+ expect(find('.modal-body')).to have_content(bitbucket_link_content)
+ end
+ end
+ end
+
+ context 'as a user' do
+ let(:user) { create(:user) }
+ let(:bitbucket_link_content) { 'To enable importing projects from Bitbucket, ask your GitLab administrator to configure OAuth integration' }
+
+ before do
+ sign_in(user)
+ end
+
+ it_behaves_like 'has a link to bitbucket cloud'
+ end
+
+ context 'as an admin' do
+ let(:user) { create(:admin) }
+ let(:bitbucket_link_content) { 'To enable importing projects from Bitbucket, as administrator you need to configure OAuth integration' }
+
+ before do
+ sign_in(user)
+ end
+
+ it_behaves_like 'has a link to bitbucket cloud'
+ end
+ end
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 5176a7ec5a1..01c942aec4c 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -715,7 +715,7 @@ RSpec.describe 'Pipeline', :js do
let(:schedule) do
create(:ci_pipeline_schedule,
project: project,
- owner: project.owner,
+ owner: project.first_owner,
description: 'blocked user schedule'
).tap do |schedule|
schedule.update_column(:next_run_at, 1.minute.ago)
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index fb45db213d0..d5b470194a2 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Pipelines', :js do
include ProjectForksHelper
+ include Spec::Support::Helpers::ModalHelpers
let(:project) { create(:project) }
@@ -159,7 +160,7 @@ RSpec.describe 'Pipelines', :js do
end
end
- context 'when pipeline is detached merge request pipeline' do
+ context 'when pipeline is detached merge request pipeline, with rearrange_pipelines_table feature flag turned off' do
let(:merge_request) do
create(:merge_request,
:with_detached_merge_request_pipeline,
@@ -172,6 +173,8 @@ RSpec.describe 'Pipelines', :js do
let(:target_project) { project }
before do
+ stub_feature_flags(rearrange_pipelines_table: false)
+
visit project_pipelines_path(source_project)
end
@@ -201,7 +204,47 @@ RSpec.describe 'Pipelines', :js do
end
end
- context 'when pipeline is merge request pipeline' do
+ context 'when pipeline is detached merge request pipeline, with rearrange_pipelines_table feature flag turned on' do
+ let(:merge_request) do
+ create(:merge_request,
+ :with_detached_merge_request_pipeline,
+ source_project: source_project,
+ target_project: target_project)
+ end
+
+ let!(:pipeline) { merge_request.all_pipelines.first }
+ let(:source_project) { project }
+ let(:target_project) { project }
+
+ before do
+ stub_feature_flags(rearrange_pipelines_table: true)
+
+ visit project_pipelines_path(source_project)
+ end
+
+ shared_examples_for 'detached merge request pipeline' do
+ it 'shows pipeline information without pipeline ref', :sidekiq_might_not_need_inline do
+ within '.pipeline-tags' do
+ expect(page).to have_content('detached')
+
+ expect(page).to have_link(merge_request.iid,
+ href: project_merge_request_path(project, merge_request))
+
+ expect(page).not_to have_link(pipeline.ref)
+ end
+ end
+ end
+
+ it_behaves_like 'detached merge request pipeline'
+
+ context 'when source project is a forked project' do
+ let(:source_project) { fork_project(project, user, repository: true) }
+
+ it_behaves_like 'detached merge request pipeline'
+ end
+ end
+
+ context 'when pipeline is merge request pipeline, with rearrange_pipelines_table feature flag turned off' do
let(:merge_request) do
create(:merge_request,
:with_merge_request_pipeline,
@@ -215,6 +258,8 @@ RSpec.describe 'Pipelines', :js do
let(:target_project) { project }
before do
+ stub_feature_flags(rearrange_pipelines_table: false)
+
visit project_pipelines_path(source_project)
end
@@ -244,6 +289,47 @@ RSpec.describe 'Pipelines', :js do
end
end
+ context 'when pipeline is merge request pipeline, with rearrange_pipelines_table feature flag turned on' do
+ let(:merge_request) do
+ create(:merge_request,
+ :with_merge_request_pipeline,
+ source_project: source_project,
+ target_project: target_project,
+ merge_sha: target_project.commit.sha)
+ end
+
+ let!(:pipeline) { merge_request.all_pipelines.first }
+ let(:source_project) { project }
+ let(:target_project) { project }
+
+ before do
+ stub_feature_flags(rearrange_pipelines_table: true)
+
+ visit project_pipelines_path(source_project)
+ end
+
+ shared_examples_for 'Correct merge request pipeline information' do
+ it 'does not show detached tag for the pipeline, and shows the link of the merge request, and does not show the ref of the pipeline', :sidekiq_might_not_need_inline do
+ within '.pipeline-tags' do
+ expect(page).not_to have_content('detached')
+
+ expect(page).to have_link(merge_request.iid,
+ href: project_merge_request_path(project, merge_request))
+
+ expect(page).not_to have_link(pipeline.ref)
+ end
+ end
+ end
+
+ it_behaves_like 'Correct merge request pipeline information'
+
+ context 'when source project is a forked project' do
+ let(:source_project) { fork_project(project, user, repository: true) }
+
+ it_behaves_like 'Correct merge request pipeline information'
+ end
+ end
+
context 'when pipeline has configuration errors' do
let(:pipeline) do
create(:ci_pipeline, :invalid, project: project)
@@ -351,7 +437,9 @@ RSpec.describe 'Pipelines', :js do
context 'when user played a delayed job immediately' do
before do
find('[data-testid="pipelines-manual-actions-dropdown"]').click
- page.accept_confirm { click_button('delayed job 1') }
+ accept_gl_confirm do
+ click_button 'delayed job 1'
+ end
wait_for_requests
end
@@ -587,6 +675,7 @@ RSpec.describe 'Pipelines', :js do
context 'with pipeline key selection' do
before do
+ stub_feature_flags(rearrange_pipelines_table: false)
visit project_pipelines_path(project)
wait_for_requests
end
@@ -604,6 +693,27 @@ RSpec.describe 'Pipelines', :js do
expect(page.find('[data-testid="pipeline-url-link"]')).to have_content "##{pipeline.iid}"
end
end
+
+ context 'with pipeline key selection and rearrange_pipelines_table ff on' do
+ before do
+ stub_feature_flags(rearrange_pipelines_table: true)
+ visit project_pipelines_path(project)
+ wait_for_requests
+ end
+
+ it 'changes the Pipeline ID column for Pipeline IID' do
+ page.find('[data-testid="pipeline-key-dropdown"]').click
+
+ within '.gl-new-dropdown-contents' do
+ dropdown_options = page.find_all '.gl-new-dropdown-item'
+
+ dropdown_options[1].click
+ end
+
+ expect(page.find('[data-testid="pipeline-th"]')).to have_content 'Pipeline'
+ expect(page.find('[data-testid="pipeline-identifier"]')).to have_content "##{pipeline.iid}"
+ end
+ end
end
describe 'GET /:project/-/pipelines/show' do
@@ -750,7 +860,7 @@ RSpec.describe 'Pipelines', :js do
it 'increments jobs_cache_index' do
click_button 'Clear runner caches'
wait_for_requests
- expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Project cache successfully reset.'
end
end
@@ -758,7 +868,7 @@ RSpec.describe 'Pipelines', :js do
it 'sets jobs_cache_index to 1' do
click_button 'Clear runner caches'
wait_for_requests
- expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Project cache successfully reset.'
end
end
end
diff --git a/spec/features/projects/settings/monitor_settings_spec.rb b/spec/features/projects/settings/monitor_settings_spec.rb
index 3f6c4646f00..871391fbe9c 100644
--- a/spec/features/projects/settings/monitor_settings_spec.rb
+++ b/spec/features/projects/settings/monitor_settings_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Settings > For a forked project', :js do
let_it_be(:project) { create(:project, :repository, create_templates: :issue) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/settings/packages_settings_spec.rb b/spec/features/projects/settings/packages_settings_spec.rb
index e70839e9720..057e6b635fe 100644
--- a/spec/features/projects/settings/packages_settings_spec.rb
+++ b/spec/features/projects/settings/packages_settings_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Settings > Packages', :js do
let_it_be(:project) { create(:project) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/settings/project_settings_spec.rb b/spec/features/projects/settings/project_settings_spec.rb
index b67caa5a5f9..a0d44b579a8 100644
--- a/spec/features/projects/settings/project_settings_spec.rb
+++ b/spec/features/projects/settings/project_settings_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Projects settings' do
let_it_be(:project) { create(:project) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:panel) { find('.general-settings', match: :first) }
let(:button) { panel.find('.btn.gl-button.js-settings-toggle') }
let(:title) { panel.find('.settings-title') }
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 91a7753fe6d..d16295aedbe 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
@@ -4,7 +4,7 @@ require "spec_helper"
RSpec.describe "User interacts with deploy keys", :js do
let(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/show/redirects_spec.rb b/spec/features/projects/show/redirects_spec.rb
index 659edda5672..3ac82244ded 100644
--- a/spec/features/projects/show/redirects_spec.rb
+++ b/spec/features/projects/show/redirects_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe 'Projects > Show > Redirects' do
it 'redirects to private project page after sign in' do
visit project_path(private_project)
- owner = private_project.owner
+ owner = private_project.first_owner
fill_in 'user_login', with: owner.email
fill_in 'user_password', with: owner.password
click_button 'Sign in'
diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb
index 80dae4ec386..1df37eef6a9 100644
--- a/spec/features/projects/show/user_manages_notifications_spec.rb
+++ b/spec/features/projects/show/user_manages_notifications_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
let(:project) { create(:project, :public, :repository) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
end
def click_notifications_button
diff --git a/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb b/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb
index b7af0c29b33..47e010dcf89 100644
--- a/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb
+++ b/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Projects > Show > User sees a deletion failure message' do
let(:project) { create(:project, :empty_repo, pending_delete: true) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
end
it 'shows error message if deletion for project fails' do
diff --git a/spec/features/projects/show/user_sees_git_instructions_spec.rb b/spec/features/projects/show/user_sees_git_instructions_spec.rb
index e6157887c12..5270939f681 100644
--- a/spec/features/projects/show/user_sees_git_instructions_spec.rb
+++ b/spec/features/projects/show/user_sees_git_instructions_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe 'Projects > Show > User sees Git instructions' do
let_it_be(:project) { create(:project, :public) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_path(project)
end
@@ -77,7 +77,7 @@ RSpec.describe 'Projects > Show > User sees Git instructions' do
.at_least(:once)
.and_return('example_branch')
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit project_path(project)
end
diff --git a/spec/features/projects/tree/tree_show_spec.rb b/spec/features/projects/tree/tree_show_spec.rb
index f8bbaa9535b..cd94e6da018 100644
--- a/spec/features/projects/tree/tree_show_spec.rb
+++ b/spec/features/projects/tree/tree_show_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'Projects tree', :js do
expect(page).to have_selector('.tree-item')
expect(page).to have_content('add tests for .gitattributes custom highlighting')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
expect(page).not_to have_selector('[data-qa-selector="label-lfs"]', text: 'LFS') # rubocop:disable QA/SelectorUsage
end
@@ -36,7 +36,7 @@ RSpec.describe 'Projects tree', :js do
expect(page).to have_selector('.tree-item')
expect(page).to have_content('add spaces in whitespace file')
expect(page).not_to have_selector('[data-qa-selector="label-lfs"]', text: 'LFS') # rubocop:disable QA/SelectorUsage
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
it 'renders tree table with non-ASCII filenames without errors' do
@@ -46,7 +46,7 @@ RSpec.describe 'Projects tree', :js do
expect(page).to have_selector('.tree-item')
expect(page).to have_content('Files, encoding and much more')
expect(page).to have_content('ใƒ†ใ‚นใƒˆ.txt')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
context "with a tree that contains pathspec characters" do
@@ -139,7 +139,7 @@ RSpec.describe 'Projects tree', :js do
wait_for_requests
expect(page).to have_selector('.tree-item')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
context 'for signed commit' do
diff --git a/spec/features/projects/user_changes_project_visibility_spec.rb b/spec/features/projects/user_changes_project_visibility_spec.rb
index 68fed9b8a74..d2a7596aec0 100644
--- a/spec/features/projects/user_changes_project_visibility_spec.rb
+++ b/spec/features/projects/user_changes_project_visibility_spec.rb
@@ -43,9 +43,9 @@ RSpec.describe 'User changes public project visibility', :js do
context 'when the project has forks' do
before do
- fork_project(project, project.owner)
+ fork_project(project, project.first_owner)
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit edit_project_path(project)
end
@@ -84,7 +84,7 @@ RSpec.describe 'User changes public project visibility', :js do
let(:project) { create(:project, :empty_repo, :public) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit edit_project_path(project)
end
@@ -98,9 +98,9 @@ RSpec.describe 'User changes public project visibility', :js do
before do
stub_feature_flags(unlink_fork_network_upon_visibility_decrease: false)
- fork_project(project, project.owner)
+ fork_project(project, project.first_owner)
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit edit_project_path(project)
end
diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb
index 7bb15451538..cd6f09ce275 100644
--- a/spec/features/projects/user_uses_shortcuts_spec.rb
+++ b/spec/features/projects/user_uses_shortcuts_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User uses shortcuts', :js do
let_it_be(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/projects/view_on_env_spec.rb b/spec/features/projects/view_on_env_spec.rb
index 94085b075aa..5dd30f59e3d 100644
--- a/spec/features/projects/view_on_env_spec.rb
+++ b/spec/features/projects/view_on_env_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe 'View on environment', :js do
let(:user) { project.creator }
before do
- stub_feature_flags(refactor_blob_viewer: false) # This stub will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/350457
project.add_maintainer(user)
end
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 63ee89bd11f..fbb5c24f6e1 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
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Wiki > User views wiki in project page' do
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
end
context 'when repository is disabled for project' do
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 26deca9c8f1..1049f8bc18f 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe 'Project' do
let(:path) { project_path(project) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
end
it 'parses Markdown' do
@@ -123,7 +123,7 @@ RSpec.describe 'Project' do
let(:path) { project_path(project) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit path
end
@@ -154,7 +154,7 @@ RSpec.describe 'Project' do
let(:path) { project_path(project) }
before do
- sign_in(project.owner)
+ sign_in(project.first_owner)
visit path
end
@@ -201,7 +201,7 @@ RSpec.describe 'Project' do
it 'does not show the name of the deleted project when the source was deleted', :sidekiq_might_not_need_inline do
forked_project
- Projects::DestroyService.new(base_project, base_project.owner).execute
+ Projects::DestroyService.new(base_project, base_project.first_owner).execute
visit project_path(forked_project)
@@ -236,7 +236,7 @@ RSpec.describe 'Project' do
it 'does not show an error' do
wait_for_requests
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
end
@@ -316,7 +316,7 @@ RSpec.describe 'Project' do
wait_for_requests
expect(page).to have_selector('.tree-item')
- expect(page).not_to have_selector('.flash-alert')
+ expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
context 'for signed commit' do
diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb
index 376f990f054..c89dd4d1f90 100644
--- a/spec/features/protected_tags_spec.rb
+++ b/spec/features/protected_tags_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Protected Tags', :js do
include ProtectedTagHelpers
let(:project) { create(:project, :repository) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
before do
sign_in(user)
diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb
index 12237863188..ab080f0a460 100644
--- a/spec/features/security/project/snippet/internal_access_spec.rb
+++ b/spec/features/security/project/snippet/internal_access_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe "Internal Project Snippets Access" do
include AccessMatchers
let_it_be(:project) { create(:project, :internal) }
- let_it_be(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.owner) }
- let_it_be(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) }
+ let_it_be(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.first_owner) }
+ let_it_be(:private_snippet) { create(:project_snippet, :private, project: project, author: project.first_owner) }
describe "GET /:project_path/snippets" do
subject { project_snippets_path(project) }
diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb
index 0c06841399d..1e0afc09b74 100644
--- a/spec/features/security/project/snippet/private_access_spec.rb
+++ b/spec/features/security/project/snippet/private_access_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe "Private Project Snippets Access" do
include AccessMatchers
let_it_be(:project) { create(:project, :private) }
- let_it_be(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) }
+ let_it_be(:private_snippet) { create(:project_snippet, :private, project: project, author: project.first_owner) }
describe "GET /:project_path/snippets" do
subject { project_snippets_path(project) }
diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb
index 2ae08205602..f734f7ba9e2 100644
--- a/spec/features/security/project/snippet/public_access_spec.rb
+++ b/spec/features/security/project/snippet/public_access_spec.rb
@@ -6,9 +6,9 @@ RSpec.describe "Public Project Snippets Access" do
include AccessMatchers
let_it_be(:project) { create(:project, :public) }
- let_it_be(:public_snippet) { create(:project_snippet, :public, project: project, author: project.owner) }
- let_it_be(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.owner) }
- let_it_be(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) }
+ let_it_be(:public_snippet) { create(:project_snippet, :public, project: project, author: project.first_owner) }
+ let_it_be(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.first_owner) }
+ let_it_be(:private_snippet) { create(:project_snippet, :private, project: project, author: project.first_owner) }
describe "GET /:project_path/snippets" do
subject { project_snippets_path(project) }
diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb
index 8cdb4bc3344..35eb5c2e193 100644
--- a/spec/features/snippets_spec.rb
+++ b/spec/features/snippets_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Snippets' do
context 'when the project has snippets' do
let(:project) { create(:project, :public) }
- let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) }
+ let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.first_owner, project: project) }
before do
allow(Snippet).to receive(:default_per_page).and_return(1)
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 2ddd86dd807..1f1824c897e 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe 'Triggers', :js do
click_button 'Add trigger'
aggregate_failures 'display creation notice and trigger is created' do
- expect(page.find('.flash-notice')).to have_content 'Trigger was created successfully.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Trigger was created successfully.'
expect(page.find('.triggers-list')).to have_content 'trigger desc'
expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
end
@@ -63,7 +63,7 @@ RSpec.describe 'Triggers', :js do
click_button 'Save trigger'
aggregate_failures 'display update notice and trigger is updated' do
- expect(page.find('.flash-notice')).to have_content 'Trigger was successfully updated.'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Trigger was successfully updated.'
expect(page.find('.triggers-list')).to have_content new_trigger_title
expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
end
@@ -89,7 +89,7 @@ RSpec.describe 'Triggers', :js do
end
aggregate_failures 'trigger is removed' do
- expect(page.find('.flash-notice')).to have_content 'Trigger removed'
+ expect(page.find('[data-testid="alert-info"]')).to have_content 'Trigger removed'
expect(page).to have_css('[data-testid="no_triggers_content"]')
end
end
diff --git a/spec/features/user_sorts_things_spec.rb b/spec/features/user_sorts_things_spec.rb
index 8e6f6a96bd2..fa37d692225 100644
--- a/spec/features/user_sorts_things_spec.rb
+++ b/spec/features/user_sorts_things_spec.rb
@@ -33,18 +33,6 @@ RSpec.describe "User sorts things" do
expect(find(".issues-filters")).to have_content(sort_option)
end
- it "issues -> merge requests" do
- sort_option = 'Updated date'
-
- visit(project_issues_path(project))
-
- sort_by(sort_option)
-
- visit(project_merge_requests_path(project))
-
- expect(find(".issues-filters")).to have_content(sort_option)
- end
-
it "merge requests -> dashboard merge requests" do
sort_option = 'Updated date'
diff --git a/spec/features/users/bizible_csp_spec.rb b/spec/features/users/bizible_csp_spec.rb
new file mode 100644
index 00000000000..af0b42050b3
--- /dev/null
+++ b/spec/features/users/bizible_csp_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Bizible content security policy' do
+ before do
+ stub_config(extra: { one_trust_id: SecureRandom.uuid })
+ end
+
+ it 'has proper Content Security Policy headers' do
+ visit root_path
+
+ expect(response_headers['Content-Security-Policy']).to include('https://cdn.bizible.com/scripts/bizible.js')
+ end
+end
diff --git a/spec/features/users/logout_spec.rb b/spec/features/users/logout_spec.rb
index ffb8785b277..3129eb5e6f3 100644
--- a/spec/features/users/logout_spec.rb
+++ b/spec/features/users/logout_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'Logout/Sign out', :js do
it 'sign out does not show signed out flash notice' do
gitlab_sign_out
- expect(page).not_to have_selector('.flash-notice')
+ expect(page).not_to have_selector('[data-testid="alert-info"]')
end
context 'on a read-only instance' do